Skip to content

Commit e4c425a

Browse files
committed
Add ability to jump to directory item by typing
Allows the user to select an item in the directory by typing its first few characters. Also fixes a bug where pressing enter upon renaming an item will both rename the item and launch it (file) or navigate into it (folder).
1 parent b556239 commit e4c425a

File tree

5 files changed

+136
-21
lines changed

5 files changed

+136
-21
lines changed

Files UWP/Filesystem/ItemViewModel.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public class ItemViewModel : INotifyPropertyChanged
4848
private const int _step = 250;
4949
public event PropertyChangedEventHandler PropertyChanged;
5050

51+
private string _jumpString = "";
52+
private DispatcherTimer jumpTimer = new DispatcherTimer();
53+
5154
private SortOption _directorySortOption = SortOption.Name;
5255
private SortDirection _directorySortDirection = SortDirection.Ascending;
5356

@@ -171,6 +174,46 @@ public bool IsSortedDescending
171174
}
172175
}
173176

177+
public string JumpString
178+
{
179+
get
180+
{
181+
return _jumpString;
182+
}
183+
set
184+
{
185+
if (value != "")
186+
{
187+
ListedItem jumpedToItem = null;
188+
try
189+
{
190+
jumpedToItem = _filesAndFolders.Where(f => f.FileName.Substring(0, value.Length).ToUpper() == value).First();
191+
}
192+
catch (ArgumentOutOfRangeException) { }
193+
catch (InvalidOperationException) { }
194+
195+
if (jumpedToItem != null)
196+
{
197+
if (App.selectedTabInstance.accessibleContentFrame.SourcePageType == typeof(GenericFileBrowser))
198+
{
199+
(App.selectedTabInstance.accessibleContentFrame.Content as GenericFileBrowser).AllView.SelectedItem = jumpedToItem;
200+
(App.selectedTabInstance.accessibleContentFrame.Content as GenericFileBrowser).AllView.ScrollIntoView(jumpedToItem, null);
201+
}
202+
else if (App.selectedTabInstance.accessibleContentFrame.SourcePageType == typeof(PhotoAlbum))
203+
{
204+
(App.selectedTabInstance.accessibleContentFrame.Content as PhotoAlbum).gv.SelectedItem = jumpedToItem;
205+
(App.selectedTabInstance.accessibleContentFrame.Content as PhotoAlbum).gv.ScrollIntoView(jumpedToItem);
206+
}
207+
208+
}
209+
210+
// Restart the timer
211+
jumpTimer.Start();
212+
}
213+
_jumpString = value;
214+
}
215+
}
216+
174217
public ItemViewModel()
175218
{
176219
_filesAndFolders = new ObservableCollection<ListedItem>();
@@ -204,14 +247,22 @@ public ItemViewModel()
204247
_cancellationTokenSource = new CancellationTokenSource();
205248

206249
Universal.PropertyChanged += Universal_PropertyChanged;
250+
251+
jumpTimer.Interval = TimeSpan.FromSeconds(0.8);
252+
jumpTimer.Tick += JumpTimer_Tick;
253+
}
254+
255+
private void JumpTimer_Tick(object sender, object e)
256+
{
257+
_jumpString = "";
258+
jumpTimer.Stop();
207259
}
208260

209261
/*
210262
* Ensure that the path bar gets updated for user interaction
211263
* whenever the path changes. We will get the individual directories from
212264
* the updated, most-current path and add them to the UI.
213265
*/
214-
215266
private void Universal_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
216267
{
217268
// Clear the path UI

Files UWP/GenericFileBrowser.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@
212212
</Grid.ContextFlyout>
213213
<ProgressBar x:Name="progBar" Height="10" VerticalAlignment="Top" IsIndeterminate="True"/>
214214
<TextBlock Visibility="{x:Bind Mode=TwoWay, Path=TextState.isVisible, UpdateSourceTrigger=PropertyChanged}" x:Name="EmptyText" HorizontalAlignment="Center" Text="This folder is empty." TextWrapping="Wrap" VerticalAlignment="Top" Margin="0,125,0,0"/>
215-
<controls:DataGrid ItemsSource="{x:Bind viewModelInstance.FilesAndFolders}" PreviewKeyDown="AllView_PreviewKeyDown" ScrollViewer.IsScrollInertiaEnabled="True" ClipboardCopyMode="None" RowDetailsVisibilityMode="Collapsed" AllowDrop="True" Drop="AllView_DropAsync" DragLeave="AllView_DragLeave" DragStarting="AllView_DragStarting" SelectionChanged="AllView_SelectionChanged" Margin="24,24,0,0" Grid.Row="3" PreparingCellForEdit="AllView_PreparingCellForEdit" CellEditEnding="AllView_CellEditEnding" FocusVisualPrimaryThickness="0" SelectionMode="Extended" IsDoubleTapEnabled="True" x:FieldModifier="public" x:Name="AllView" AutoGenerateColumns="False" CanDrag="True" DragOver="AllView_DragOver" IsRightTapEnabled="True" CanUserReorderColumns="False" CanUserSortColumns="True" Sorting="AllView_Sorting" HorizontalAlignment="Left">
215+
<controls:DataGrid ItemsSource="{x:Bind viewModelInstance.FilesAndFolders}" PreviewKeyDown="AllView_PreviewKeyDown" ScrollViewer.IsScrollInertiaEnabled="True" ClipboardCopyMode="None" RowDetailsVisibilityMode="Collapsed" AllowDrop="True" Drop="AllView_DropAsync" DragLeave="AllView_DragLeave" DragStarting="AllView_DragStarting" SelectionChanged="AllView_SelectionChanged" Margin="24,24,0,0" Grid.Row="3" PreparingCellForEdit="AllView_PreparingCellForEdit" CellEditEnding="AllView_CellEditEnding" CellEditEnded="AllView_CellEditEnded" FocusVisualPrimaryThickness="0" SelectionMode="Extended" IsDoubleTapEnabled="True" x:FieldModifier="public" x:Name="AllView" AutoGenerateColumns="False" CanDrag="True" DragOver="AllView_DragOver" IsRightTapEnabled="True" CanUserReorderColumns="False" CanUserSortColumns="True" Sorting="AllView_Sorting" HorizontalAlignment="Left">
216216
<controls:DataGrid.Resources>
217217
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="Transparent"/>
218218
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="Transparent"/>

Files UWP/GenericFileBrowser.xaml.cs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using System.Runtime.CompilerServices;
1515
using Windows.System;
1616
using Windows.UI.Xaml.Input;
17+
using Windows.UI.Core;
1718

1819
namespace Files
1920
{
@@ -35,6 +36,7 @@ public sealed partial class GenericFileBrowser : Page
3536
public Grid grid;
3637
public ProgressBar progressBar;
3738
private DataGridColumn _sortedColumn;
39+
private bool isEditing = false;
3840
ItemViewModel viewModelInstance;
3941
ProHome tabInstance;
4042

@@ -110,7 +112,7 @@ public GenericFileBrowser()
110112
NewTextDocument.Click += tabInstance.instanceInteraction.NewTextDocument_Click;
111113
PropertiesItem.Click += tabInstance.ShowPropertiesButton_Click;
112114
OpenInNewWindowItem.Click += tabInstance.instanceInteraction.OpenInNewWindowItem_Click;
113-
115+
114116
switch (viewModelInstance.DirectorySortOption)
115117
{
116118
case SortOption.Name:
@@ -252,7 +254,9 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs)
252254
data.Columns[0].GetCellContent(dataGridRow).Opacity = 1;
253255
}
254256
}
255-
257+
258+
// Add item jumping handler
259+
Window.Current.CoreWindow.KeyDown += Page_KeyDown;
256260
}
257261

258262
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
@@ -264,6 +268,9 @@ protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
264268
}
265269

266270
//this.Bindings.StopTracking();
271+
272+
// Remove item jumping handler
273+
Window.Current.CoreWindow.KeyDown -= Page_KeyDown;
267274
}
268275

269276
private void AllView_DragOver(object sender, DragEventArgs e)
@@ -304,6 +311,7 @@ private void AllView_PreparingCellForEdit(object sender, DataGridPreparingCellFo
304311
previousFileName = selectedItem.FileName;
305312
textBox.Focus(FocusState.Programmatic); // Without this, cannot edit text box when renaming via right-click
306313
textBox.Select(0, selectedItem.FileName.Length - extensionLength);
314+
isEditing = true;
307315
}
308316

309317
private async void AllView_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
@@ -323,6 +331,11 @@ private async void AllView_CellEditEnding(object sender, DataGridCellEditEndingE
323331
}
324332
}
325333

334+
private void AllView_CellEditEnded(object sender, DataGridCellEditEndedEventArgs e)
335+
{
336+
isEditing = false;
337+
}
338+
326339
private void ContentDialog_Loaded(object sender, RoutedEventArgs e)
327340
{
328341
//AddDialogFrame.Navigate(typeof(AddItem), new SuppressNavigationTransitionInfo());
@@ -405,12 +418,33 @@ private void AllView_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
405418
{
406419
if (e.Key == VirtualKey.Enter)
407420
{
408-
tabInstance.instanceInteraction.List_ItemClick(null, null);
421+
if (isEditing)
422+
{
423+
AllView.CommitEdit();
424+
}
425+
else
426+
{
427+
tabInstance.instanceInteraction.List_ItemClick(null, null);
428+
}
429+
e.Handled = true;
430+
}
431+
}
432+
433+
private void Page_KeyDown(object sender, KeyEventArgs e)
434+
{
435+
var focusedElement = FocusManager.GetFocusedElement(XamlRoot) as FrameworkElement;
436+
if (focusedElement is TextBox)
437+
return;
438+
if (e.VirtualKey >= VirtualKey.A && e.VirtualKey <= VirtualKey.Z)
439+
{
440+
char letterPressed = Convert.ToChar(e.VirtualKey);
441+
AllView.Focus(FocusState.Keyboard);
442+
tabInstance.instanceInteraction.PushJumpChar(letterPressed);
409443
e.Handled = true;
410444
}
411445
}
412446
}
413-
447+
414448
public class EmptyFolderTextState : INotifyPropertyChanged
415449
{
416450
public Visibility _isVisible;

Files UWP/Interacts/Interaction.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
1-
using System;
1+
using Files.Filesystem;
2+
using Microsoft.Toolkit.Uwp.UI.Controls;
3+
using System;
4+
using System.Collections;
25
using System.Collections.Generic;
36
using System.Collections.ObjectModel;
47
using System.Diagnostics;
8+
using System.IO;
9+
using System.Reflection;
10+
using System.Threading.Tasks;
11+
using Windows.ApplicationModel;
512
using Windows.ApplicationModel.DataTransfer;
13+
using Windows.Foundation;
614
using Windows.Storage;
715
using Windows.System;
16+
using Windows.UI.Popups;
817
using Windows.UI.Xaml;
918
using Windows.UI.Xaml.Controls;
1019
using Windows.UI.Xaml.Input;
11-
using Windows.UI.Popups;
1220
using Windows.UI.Xaml.Media;
1321
using Windows.UI.Xaml.Media.Animation;
14-
using System.ComponentModel;
15-
using Files.Filesystem;
16-
using Files.Navigation;
17-
using Microsoft.Toolkit.Uwp.UI.Controls;
18-
using System.Threading.Tasks;
19-
using Windows.ApplicationModel;
20-
using System.Collections;
21-
using Windows.Foundation;
22-
using Windows.UI.Xaml.Controls.Primitives;
23-
using System.IO;
24-
using System.Reflection;
25-
using Files.Dialogs;
2622

2723
namespace Files.Interacts
2824
{
@@ -929,5 +925,10 @@ public void ClearAllItems()
929925
(tabInstance.accessibleContentFrame.Content as PhotoAlbum).gv.SelectedItems.Clear();
930926
}
931927
}
928+
929+
public void PushJumpChar(char letter)
930+
{
931+
tabInstance.instanceViewModel.JumpString += letter;
932+
}
932933
}
933934
}

Files UWP/PhotoAlbum.xaml.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
using System.Text.RegularExpressions;
2727
using Interaction = Files.Interacts.Interaction;
2828
using Files.Dialogs;
29+
using Windows.UI.Core;
2930

3031
namespace Files
3132
{
@@ -44,6 +45,7 @@ public sealed partial class PhotoAlbum : Page
4445
public string inputForRename;
4546
public ProgressBar progressBar;
4647
public ListedItem renamingItem;
48+
private bool isRenaming = false;
4749
ItemViewModel viewModelInstance;
4850
ProHome tabInstance;
4951
public EmptyFolderTextState TextState { get; set; } = new EmptyFolderTextState();
@@ -144,6 +146,9 @@ protected override void OnNavigatedTo(NavigationEventArgs eventArgs)
144146
{
145147
App.PS.isEnabled = false;
146148
}
149+
150+
// Add item jumping handler
151+
Window.Current.CoreWindow.KeyDown += Page_KeyDown;
147152
}
148153

149154
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
@@ -153,6 +158,9 @@ protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
153158
{
154159
tabInstance.instanceViewModel._fileQueryResult.ContentsChanged -= tabInstance.instanceViewModel.FileContentsChanged;
155160
}
161+
162+
// Remove item jumping handler
163+
Window.Current.CoreWindow.KeyDown -= Page_KeyDown;
156164
}
157165

158166
private void Clipboard_ContentChanged(object sender, object e)
@@ -323,6 +331,7 @@ public void StartRename()
323331
textBox.LostFocus += RenameTextBox_LostFocus;
324332
textBox.KeyDown += RenameTextBox_KeyDown;
325333
textBox.Select(0, renamingItem.FileName.Length - extensionLength);
334+
isRenaming = true;
326335
}
327336

328337
private void RenameTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
@@ -332,11 +341,13 @@ private void RenameTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
332341
TextBox textBox = sender as TextBox;
333342
textBox.LostFocus -= RenameTextBox_LostFocus;
334343
EndRename(textBox);
344+
e.Handled = true;
335345
}
336346
else if (e.Key == VirtualKey.Enter)
337347
{
338348
TextBox textBox = sender as TextBox;
339349
CommitRename(textBox);
350+
e.Handled = true;
340351
}
341352
}
342353

@@ -375,13 +386,31 @@ private void EndRename(TextBox textBox)
375386
textBlock.Visibility = Visibility.Visible;
376387
textBox.LostFocus -= RenameTextBox_LostFocus;
377388
textBox.KeyDown += RenameTextBox_KeyDown;
389+
isRenaming = false;
378390
}
379391

380392
private void FileList_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
381393
{
382394
if (e.Key == VirtualKey.Enter)
383395
{
384-
tabInstance.instanceInteraction.List_ItemClick(null, null);
396+
if (!isRenaming)
397+
{
398+
tabInstance.instanceInteraction.List_ItemClick(null, null);
399+
e.Handled = true;
400+
}
401+
}
402+
}
403+
404+
private void Page_KeyDown(object sender, KeyEventArgs e)
405+
{
406+
var focusedElement = FocusManager.GetFocusedElement(XamlRoot) as FrameworkElement;
407+
if (focusedElement is TextBox)
408+
return;
409+
if (e.VirtualKey >= VirtualKey.A && e.VirtualKey <= VirtualKey.Z)
410+
{
411+
char letterPressed = Convert.ToChar(e.VirtualKey);
412+
gv.Focus(FocusState.Keyboard);
413+
tabInstance.instanceInteraction.PushJumpChar(letterPressed);
385414
e.Handled = true;
386415
}
387416
}

0 commit comments

Comments
 (0)