Skip to content

Commit 555f0b0

Browse files
ferrariofilippoQuaintMako
authored andcommitted
Feature: Added option to create new shortcuts (files-community#10879)
1 parent 641b987 commit 555f0b0

16 files changed

+296
-7
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<ContentDialog
2+
x:Class="Files.App.Dialogs.CreateShortcutDialog"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:helpers="using:Files.App.Helpers"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
Title="{helpers:ResourceString Name=NewShortcutDialogTitle}"
9+
DefaultButton="Primary"
10+
PrimaryButtonCommand="{x:Bind ViewModel.PrimaryButtonCommand}"
11+
IsPrimaryButtonEnabled="{x:Bind ViewModel.IsLocationValid, Mode=OneWay}"
12+
PrimaryButtonText="{helpers:ResourceString Name=Create}"
13+
RequestedTheme="{x:Bind helpers:ThemeHelper.RootTheme}"
14+
SecondaryButtonText="{helpers:ResourceString Name=Cancel}"
15+
Style="{StaticResource DefaultContentDialogStyle}"
16+
mc:Ignorable="d">
17+
18+
<Border Width="400">
19+
<Grid
20+
x:Name="DestinationPathGrid"
21+
ColumnSpacing="8"
22+
RowSpacing="8">
23+
<Grid.ColumnDefinitions>
24+
<ColumnDefinition />
25+
<ColumnDefinition Width="Auto" />
26+
</Grid.ColumnDefinitions>
27+
<Grid.RowDefinitions>
28+
<RowDefinition Height="Auto" />
29+
<RowDefinition Height="Auto" />
30+
<RowDefinition Height="Auto" />
31+
</Grid.RowDefinitions>
32+
33+
<!-- Header -->
34+
<TextBlock
35+
Grid.ColumnSpan="2"
36+
Margin="0, 0, 0, 20"
37+
Text="{helpers:ResourceString Name=NewShortcutDialogDescription}"
38+
TextWrapping="Wrap" />
39+
40+
<TextBlock
41+
Grid.Row="1"
42+
Grid.ColumnSpan="2"
43+
Text="{helpers:ResourceString Name=NewShortcutDialogPrompt}" />
44+
45+
<!-- Path Box -->
46+
<TextBox
47+
x:Name="DestinationItemPath"
48+
Grid.Row="2"
49+
Grid.Column="0"
50+
HorizontalAlignment="Stretch"
51+
PlaceholderText="C:\Users\"
52+
Text="{x:Bind ViewModel.DestinationItemPath, Mode=TwoWay}"
53+
TextChanged="DestinationItemPath_TextChanged" />
54+
<Button
55+
x:Name="SelectDestination"
56+
Grid.Row="2"
57+
Grid.Column="1"
58+
Command="{x:Bind ViewModel.SelectDestinationCommand}"
59+
Content="{helpers:ResourceString Name=Browse}" />
60+
</Grid>
61+
</Border>
62+
</ContentDialog>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Files.App.ViewModels.Dialogs;
2+
using Files.Backend.ViewModels.Dialogs;
3+
using Files.Shared.Enums;
4+
using Microsoft.UI.Xaml.Controls;
5+
using System;
6+
using System.IO;
7+
using System.Threading.Tasks;
8+
9+
namespace Files.App.Dialogs
10+
{
11+
public sealed partial class CreateShortcutDialog : ContentDialog, IDialog<CreateShortcutDialogViewModel>
12+
{
13+
public CreateShortcutDialogViewModel ViewModel
14+
{
15+
get => (CreateShortcutDialogViewModel)DataContext;
16+
set => DataContext = value;
17+
}
18+
19+
public CreateShortcutDialog()
20+
{
21+
this.InitializeComponent();
22+
}
23+
24+
public new async Task<DialogResult> ShowAsync() => (DialogResult)await base.ShowAsync();
25+
26+
private void DestinationItemPath_TextChanged(object sender, TextChangedEventArgs e)
27+
{
28+
if (string.IsNullOrWhiteSpace(DestinationItemPath.Text))
29+
{
30+
ViewModel.IsLocationValid = false;
31+
return;
32+
}
33+
34+
try
35+
{
36+
ViewModel.DestinationPathExists = Path.Exists(DestinationItemPath.Text) && DestinationItemPath.Text != Path.GetPathRoot(DestinationItemPath.Text);
37+
if (ViewModel.DestinationPathExists)
38+
{
39+
ViewModel.IsLocationValid = true;
40+
}
41+
else
42+
{
43+
var uri = new Uri(DestinationItemPath.Text);
44+
ViewModel.IsLocationValid = uri.IsWellFormedOriginalString();
45+
}
46+
}
47+
catch (Exception)
48+
{
49+
ViewModel.IsLocationValid = false;
50+
}
51+
}
52+
}
53+
}

src/Files.App/Helpers/ContextFlyoutItemHelper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,13 @@ public static List<ContextMenuFlyoutItemViewModel> GetNewItemItems(BaseLayoutCom
11091109
ShowInZipPage = true,
11101110
IsEnabled = canCreateFileInPage
11111111
},
1112+
new ContextMenuFlyoutItemViewModel
1113+
{
1114+
Text = "Shortcut".GetLocalizedResource(),
1115+
Glyph = "\uF10A",
1116+
GlyphFontFamilyName = "CustomGlyph",
1117+
Command = commandsViewModel.CreateShortcutFromDialogCommand
1118+
},
11121119
new ContextMenuFlyoutItemViewModel()
11131120
{
11141121
ItemType = ItemType.Separator,

src/Files.App/Helpers/UIFilesystemHelpers.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
using CommunityToolkit.Mvvm.DependencyInjection;
12
using Files.App.Dialogs;
23
using Files.App.Extensions;
34
using Files.App.Filesystem;
45
using Files.App.Filesystem.StorageItems;
56
using Files.App.Interacts;
67
using Files.App.ViewModels;
8+
using Files.App.ViewModels.Dialogs;
79
using Files.Backend.Enums;
10+
using Files.Backend.Services;
811
using Files.Shared;
912
using Files.Shared.Enums;
1013
using Files.Shared.Extensions;
@@ -386,5 +389,12 @@ public static void SetHiddenAttributeItem(ListedItem item, bool isHidden, ItemMa
386389
item.IsHiddenItem = isHidden;
387390
itemManipulationModel.RefreshItemsOpacity();
388391
}
392+
393+
public static async Task CreateShortcutFromDialogAsync(IShellPage associatedInstance)
394+
{
395+
var viewModel = new CreateShortcutDialogViewModel(associatedInstance.FilesystemViewModel.WorkingDirectory);
396+
var dialogService = Ioc.Default.GetRequiredService<IDialogService>();
397+
await dialogService.ShowDialogAsync(viewModel);
398+
}
389399
}
390400
}

src/Files.App/Interacts/BaseLayoutCommandImplementationModel.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public virtual async void CreateShortcut(RoutedEventArgs e)
9393
}
9494
}
9595

96+
public virtual async void CreateShortcutFromDialog(RoutedEventArgs e)
97+
{
98+
await UIFilesystemHelpers.CreateShortcutFromDialogAsync(associatedInstance);
99+
}
100+
96101
public virtual void SetAsLockscreenBackgroundItem(RoutedEventArgs e)
97102
{
98103
WallpaperHelpers.SetAsBackground(WallpaperType.LockScreen, SlimContentPage.SelectedItem.ItemPath);

src/Files.App/Interacts/BaseLayoutCommandsViewModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ private void InitializeCommands()
2828
{
2929
RenameItemCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.RenameItem);
3030
CreateShortcutCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.CreateShortcut);
31+
CreateShortcutFromDialogCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.CreateShortcutFromDialog);
3132
SetAsLockscreenBackgroundItemCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.SetAsLockscreenBackgroundItem);
3233
SetAsDesktopBackgroundItemCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.SetAsDesktopBackgroundItem);
3334
SetAsSlideshowItemCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.SetAsSlideshowItem);
@@ -90,6 +91,8 @@ private void InitializeCommands()
9091

9192
public ICommand CreateShortcutCommand { get; private set; }
9293

94+
public ICommand CreateShortcutFromDialogCommand { get; private set; }
95+
9396
public ICommand SetAsLockscreenBackgroundItemCommand { get; private set; }
9497

9598
public ICommand SetAsDesktopBackgroundItemCommand { get; private set; }

src/Files.App/Interacts/IBaseLayoutCommandImplementationModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public interface IBaseLayoutCommandImplementationModel : IDisposable
1212

1313
void CreateShortcut(RoutedEventArgs e);
1414

15+
void CreateShortcutFromDialog(RoutedEventArgs e);
16+
1517
void SetAsLockscreenBackgroundItem(RoutedEventArgs e);
1618

1719
void SetAsDesktopBackgroundItem(RoutedEventArgs e);

src/Files.App/ServicesImplementation/DialogService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ public DialogService()
2828
{ typeof(ElevateConfirmDialogViewModel), () => new ElevateConfirmDialog() },
2929
{ typeof(FileSystemDialogViewModel), () => new FilesystemOperationDialog() },
3030
{ typeof(DecompressArchiveDialogViewModel), () => new DecompressArchiveDialog() },
31-
{ typeof(SettingsDialogViewModel), () => new SettingsDialog() }
31+
{ typeof(SettingsDialogViewModel), () => new SettingsDialog() },
32+
{ typeof(CreateShortcutDialogViewModel), () => new CreateShortcutDialog() }
3233
};
3334
}
3435

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,18 @@
28662866
<data name="SortBy" xml:space="preserve">
28672867
<value>Sort by</value>
28682868
</data>
2869+
<data name="NewShortcutDialogTitle" xml:space="preserve">
2870+
<value>Create a new shortcut</value>
2871+
</data>
2872+
<data name="NewShortcutDialogDescription" xml:space="preserve">
2873+
<value>Create shortcuts to local or network programs, files, folders, computers or Internet addresses.</value>
2874+
</data>
2875+
<data name="NewShortcutDialogPrompt" xml:space="preserve">
2876+
<value>Enter the location of the item:</value>
2877+
</data>
2878+
<data name="AddDialogListShortcutSubHeader" xml:space="preserve">
2879+
<value>Creates a shortcut</value>
2880+
</data>
28692881
<data name="RecentFilesDisabledOnWindowsWarning" xml:space="preserve">
28702882
<value>Recently used files is currently disabled in Windows File Explorer.</value>
28712883
</data>

src/Files.App/UserControls/InnerNavigationToolbar.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@
8585
<FontIcon Glyph="&#xE7C3;" />
8686
</MenuFlyoutItem.Icon>
8787
</MenuFlyoutItem>
88+
<MenuFlyoutItem
89+
x:Name="NewShortcut"
90+
AutomationProperties.AutomationId="InnerNavigationToolbarNewShortcutButton"
91+
Command="{x:Bind ViewModel.CreateNewShortcutCommand, Mode=OneWay}"
92+
Text="{helpers:ResourceString Name=Shortcut}">
93+
<MenuFlyoutItem.Icon>
94+
<FontIcon Glyph="&#xE71B;" />
95+
</MenuFlyoutItem.Icon>
96+
</MenuFlyoutItem>
8897
<MenuFlyoutSeparator x:Name="NewMenuFileFolderSeparator" />
8998
</MenuFlyout>
9099
</AppBarButton.Flyout>

0 commit comments

Comments
 (0)