diff --git a/src/Files.App/Actions/FileSystem/RenameAction.cs b/src/Files.App/Actions/FileSystem/RenameAction.cs index 1896a5bbbb00..20172a0ee348 100644 --- a/src/Files.App/Actions/FileSystem/RenameAction.cs +++ b/src/Files.App/Actions/FileSystem/RenameAction.cs @@ -23,7 +23,7 @@ public RichGlyph Glyph context.ShellPage is not null && IsPageTypeValid() && context.ShellPage.SlimContentPage is not null && - IsSelectionValid(); + context.HasSelection; public RenameAction() { @@ -32,16 +32,18 @@ public RenameAction() context.PropertyChanged += Context_PropertyChanged; } - public Task ExecuteAsync(object? parameter = null) + public async Task ExecuteAsync(object? parameter = null) { - context.ShellPage?.SlimContentPage?.ItemManipulationModel.StartRenameItem(); - - return Task.CompletedTask; - } - - private bool IsSelectionValid() - { - return context.HasSelection && context.SelectedItems.Count == 1; + if (context.SelectedItems.Count > 1) + { + var viewModel = new BulkRenameDialogViewModel(); + var dialogService = Ioc.Default.GetRequiredService(); + var result = await dialogService.ShowDialogAsync(viewModel); + } + else + { + context.ShellPage?.SlimContentPage?.ItemManipulationModel.StartRenameItem(); + } } private bool IsPageTypeValid() diff --git a/src/Files.App/Dialogs/BulkRenameDialog.xaml b/src/Files.App/Dialogs/BulkRenameDialog.xaml new file mode 100644 index 000000000000..21c462ab6fda --- /dev/null +++ b/src/Files.App/Dialogs/BulkRenameDialog.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Files.App/Dialogs/BulkRenameDialog.xaml.cs b/src/Files.App/Dialogs/BulkRenameDialog.xaml.cs new file mode 100644 index 000000000000..a7f5b5478b65 --- /dev/null +++ b/src/Files.App/Dialogs/BulkRenameDialog.xaml.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Files Community +// Licensed under the MIT License. See the LICENSE. +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace Files.App.Dialogs +{ + public sealed partial class BulkRenameDialog : ContentDialog, IDialog + { + private FrameworkElement RootAppElement + => (FrameworkElement)MainWindow.Instance.Content; + + public BulkRenameDialogViewModel ViewModel + { + get => (BulkRenameDialogViewModel)DataContext; + set => DataContext = value; + } + + public BulkRenameDialog() + { + InitializeComponent(); + } + + public new async Task ShowAsync() + { + return (DialogResult)await base.ShowAsync(); + } + } +} diff --git a/src/Files.App/Services/App/AppDialogService.cs b/src/Files.App/Services/App/AppDialogService.cs index 298533b94d04..ab30b5e6c959 100644 --- a/src/Files.App/Services/App/AppDialogService.cs +++ b/src/Files.App/Services/App/AppDialogService.cs @@ -35,6 +35,7 @@ public DialogService() { typeof(GitHubLoginDialogViewModel), () => new GitHubLoginDialog() }, { typeof(FileTooLargeDialogViewModel), () => new FileTooLargeDialog() }, { typeof(ReleaseNotesDialogViewModel), () => new ReleaseNotesDialog() }, + { typeof(BulkRenameDialogViewModel), () => new BulkRenameDialog() }, }.ToFrozenDictionary(); } diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index c0352332b016..ed3df48d111f 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -3947,4 +3947,7 @@ User ID + + Bulk rename + \ No newline at end of file diff --git a/src/Files.App/ViewModels/Dialogs/BulkRenameDialogViewModel.cs b/src/Files.App/ViewModels/Dialogs/BulkRenameDialogViewModel.cs new file mode 100644 index 000000000000..cf363bf90482 --- /dev/null +++ b/src/Files.App/ViewModels/Dialogs/BulkRenameDialogViewModel.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2024 Files Community +// Licensed under the MIT License. See the LICENSE. + +using Windows.Storage; + +namespace Files.App.ViewModels.Dialogs +{ + public sealed class BulkRenameDialogViewModel : ObservableObject + { + private IContentPageContext context { get; } = Ioc.Default.GetRequiredService(); + + // Properties + + public bool IsNameValid => + FilesystemHelpers.IsValidForFilename(_FileName) && !_FileName.Contains("."); + + public bool ShowNameWarning => + !string.IsNullOrEmpty(_FileName) && !IsNameValid; + + private string _FileName = string.Empty; + public string FileName + { + get => _FileName; + set + { + if (SetProperty(ref _FileName, value)) + { + OnPropertyChanged(nameof(IsNameValid)); + OnPropertyChanged(nameof(ShowNameWarning)); + } + } + } + + // Commands + + public IAsyncRelayCommand CommitRenameCommand { get; private set; } + + public BulkRenameDialogViewModel() + { + CommitRenameCommand = new AsyncRelayCommand(DoCommitRenameAsync); + } + + private async Task DoCommitRenameAsync() + { + if (context.ShellPage is null) + return; + + await Task.WhenAll(context.SelectedItems.Select(item => + { + var itemType = item.PrimaryItemAttribute == StorageItemTypes.Folder ? FilesystemItemType.Directory : FilesystemItemType.File; + return context.ShellPage.FilesystemHelpers.RenameAsync( + StorageHelpers.FromPathAndType(item.ItemPath, itemType), + FileName + item.FileExtension, + NameCollisionOption.GenerateUniqueName, + true, + false + ); + })); + } + } +} \ No newline at end of file