Skip to content

Advanced search #4812

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Files/Files.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
<Compile Include="Extensions\EnumExtensions.cs" />
<Compile Include="Extensions\ImageSourceExtensions.cs" />
<Compile Include="Extensions\TaskExtensions.cs" />
<Compile Include="Filesystem\Search\FolderSearchOption.cs" />
<Compile Include="Helpers\SaveImageToFile.cs" />
<Compile Include="Filesystem\FolderHelpers.cs" />
<Compile Include="Filesystem\LibraryLocationItem.cs" />
Expand Down Expand Up @@ -234,6 +235,7 @@
<Compile Include="Helpers\WidgetsHelpers.cs" />
<Compile Include="Helpers\Win32Helpers.cs" />
<Compile Include="Interacts\ItemManipulationModel.cs" />
<Compile Include="UserControls\CalendarPicker.cs" />
<Compile Include="UserControls\RestartControl.xaml.cs">
<DependentUpon>RestartControl.xaml</DependentUpon>
</Compile>
Expand Down
33 changes: 26 additions & 7 deletions Files/Filesystem/Search/FolderSearch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Search;
Expand All @@ -14,7 +15,7 @@ namespace Files.Filesystem.Search
{
internal class FolderSearch
{
public static async Task<ObservableCollection<ListedItem>> SearchForUserQueryTextAsync(string userText, string WorkingDirectory, IShellPage associatedInstance, bool searchUnindexedItems, int maxItemCount = 10, uint thumbnailSize = 24)
public static async Task<ObservableCollection<ListedItem>> SearchForUserQueryTextAsync(string userText, string WorkingDirectory, IShellPage associatedInstance, bool searchUnindexedItems, FolderSearchOption option = null, int maxItemCount = 10, uint thumbnailSize = 24)
{
var returnedItems = new ObservableCollection<ListedItem>();
maxItemCount = maxItemCount < 0 ? int.MaxValue : maxItemCount;
Expand All @@ -23,24 +24,24 @@ public static async Task<ObservableCollection<ListedItem>> SearchForUserQueryTex
{
foreach (var folder in lib.Folders)
{
await AddItemsForFolderAsync(returnedItems, userText, folder, associatedInstance, searchUnindexedItems, maxItemCount, thumbnailSize);
await AddItemsForFolderAsync(returnedItems, userText, folder, associatedInstance, searchUnindexedItems, maxItemCount, thumbnailSize, option);
}
}
else
{
await AddItemsForFolderAsync(returnedItems, userText, WorkingDirectory, associatedInstance, searchUnindexedItems, maxItemCount, thumbnailSize);
await AddItemsForFolderAsync(returnedItems, userText, WorkingDirectory, associatedInstance, searchUnindexedItems, maxItemCount, thumbnailSize, option);
}

return returnedItems;
}

private static async Task AddItemsForFolderAsync(ObservableCollection<ListedItem> returnedItems, string userText, string WorkingDirectory, IShellPage associatedInstance, bool searchUnindexedItems, int maxItemCount, uint thumbnailSize)
private static async Task AddItemsForFolderAsync(ObservableCollection<ListedItem> returnedItems, string userText, string WorkingDirectory, IShellPage associatedInstance, bool searchUnindexedItems, int maxItemCount, uint thumbnailSize, FolderSearchOption option = null)
{
var workingDir = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(WorkingDirectory);
var hiddenOnlyFromWin32 = false;
if (workingDir)
{
foreach (var item in await SearchWithStorageFolder(userText, workingDir, searchUnindexedItems, maxItemCount, thumbnailSize))
foreach (var item in await SearchWithStorageFolder(userText, workingDir, searchUnindexedItems, maxItemCount, thumbnailSize, option))
{
returnedItems.Add(item);
}
Expand Down Expand Up @@ -140,12 +141,13 @@ await Task.Run(() =>
return returnedItems;
}

private static async Task<IList<ListedItem>> SearchWithStorageFolder(string userText, StorageFolder workingDir, bool searchUnindexedItems, int maxItemCount = 10, uint thumbnailSize = 24)
private static async Task<IList<ListedItem>> SearchWithStorageFolder(string userText, StorageFolder workingDir, bool searchUnindexedItems, int maxItemCount = 10, uint thumbnailSize = 24, FolderSearchOption option = null)
{
QueryOptions options = new QueryOptions()
{
Language = "en-US",
FolderDepth = FolderDepth.Deep,
UserSearchFilter = string.IsNullOrWhiteSpace(userText) ? null : userText,
UserSearchFilter = string.IsNullOrWhiteSpace(userText) ? string.Empty : userText,
};

if (searchUnindexedItems)
Expand All @@ -157,12 +159,29 @@ private static async Task<IList<ListedItem>> SearchWithStorageFolder(string user
options.IndexerOption = IndexerOption.OnlyUseIndexerAndOptimizeForIndexedProperties;
}

if (!(option is null))
{
var filter = new StringBuilder();

if (option.MinDate.HasValue)
{
filter.Append(" System.ItemDate:>=" + option.MinDate.Value.ToString("dd/MM/yyyy"));
}
if (option.MaxDate.HasValue)
{
filter.Append(" System.ItemDate:<=" + option.MaxDate.Value.ToString("dd/MM/yyyy"));
}

options.UserSearchFilter += filter.ToString();
}

options.SortOrder.Clear();
options.SortOrder.Add(new SortEntry()
{
PropertyName = "System.Search.Rank",
AscendingOrder = false
});

options.SetPropertyPrefetch(Windows.Storage.FileProperties.PropertyPrefetchOptions.None, null);
options.SetThumbnailPrefetch(Windows.Storage.FileProperties.ThumbnailMode.ListView, 24, Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale);
var itemQueryResult = workingDir.CreateItemQueryWithOptions(options);
Expand Down
30 changes: 30 additions & 0 deletions Files/Filesystem/Search/FolderSearchOption.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using System;

namespace Files.Filesystem.Search
{
public class FolderSearchOption : ObservableObject
{
private DateTimeOffset? minDate = null;

public DateTimeOffset? MinDate
{
get => minDate;
set => SetProperty(ref minDate, value);
}

private DateTimeOffset? maxDate = null;

public DateTimeOffset? MaxDate
{
get => maxDate;
set => SetProperty(ref maxDate, value);
}

public void Clear()
{
MinDate = null;
MaxDate = null;
}
}
}
3 changes: 2 additions & 1 deletion Files/IShellPage.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Files.Filesystem;
using Files.Filesystem.Search;
using Files.Helpers;
using Files.Interacts;
using Files.UserControls;
Expand Down Expand Up @@ -43,7 +44,7 @@ public interface IShellPage : ITabItemContent, IMultiPaneInfo, IDisposable

void RemoveLastPageFromBackStack();

void SubmitSearch(string query, bool searchUnindexedItems);
void SubmitSearch(string query, bool searchUnindexedItems, FolderSearchOption option = null);

void LoadPreviewPaneChanged();
}
Expand Down
9 changes: 9 additions & 0 deletions Files/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2181,4 +2181,13 @@
<data name="ResizeElementKeyboardControl.AutomationProperties.Name" xml:space="preserve">
<value>Sidebar resizer</value>
</data>
<data name="NavToolbarSearchWhenHeader.Text" xml:space="preserve">
<value>When</value>
</data>
<data name="NavToolbarSearchWhenFrom.PlaceholderText" xml:space="preserve">
<value>From</value>
</data>
<data name="NavToolbarSearchWhenTo.PlaceholderText" xml:space="preserve">
<value>To</value>
</data>
</root>
22 changes: 22 additions & 0 deletions Files/UserControls/CalendarPicker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using Windows.UI.Xaml.Controls;

namespace Files.UserControls
{
public class CalendarPicker : CalendarDatePicker
{
public CalendarPicker()
{
DateChanged += CalendarPicker_DateChanged;
}

private void CalendarPicker_DateChanged(CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs args)
{
if (args.NewDate != null && args.NewDate.Value.Year == DateTime.Today.Year - 100)
{
SetDisplayDate(DateTimeOffset.Now);
Date = null;
}
}
}
}
70 changes: 54 additions & 16 deletions Files/UserControls/NavigationToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
xmlns:local="using:Files.UserControls.MultitaskingControl"
xmlns:local1="using:Files"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:xh="using:Files.Helpers.XamlHelpers"
xmlns:xh="using:Files.Helpers.XamlHelpers" xmlns:usercontrols="using:Files.UserControls"
d:DesignHeight="72"
d:DesignWidth="800"
mc:Ignorable="d">
Expand Down Expand Up @@ -851,6 +851,7 @@
TextBoxStyle="{StaticResource AutoSuggestBoxTextBoxStyleFixed}"
TextChanged="SearchRegion_TextChanged"
UpdateTextOnSelect="False"
Tag="{x:Bind SearchOption}"
Visibility="{x:Bind IsSearchRegionVisible, Mode=OneWay}">
<AutoSuggestBox.QueryIcon>
<FontIcon FontSize="14" Glyph="&#xE094;" />
Expand Down Expand Up @@ -899,21 +900,58 @@
</AutoSuggestBox.ItemTemplate>
</AutoSuggestBox>

<Button
x:Name="SearchButton"
x:Uid="NavSearchButton"
Grid.Column="2"
Width="36"
Height="32"
AccessKey="I"
AutomationProperties.Name="Search"
Background="Transparent"
Click="SearchButton_Click"
IsEnabled="{x:Bind IsPageTypeNotHome, Mode=OneWay}"
Style="{StaticResource ToolBarButtonStyle}"
ToolTipService.ToolTip="Search">
<FontIcon FontSize="14" Glyph="&#xE721;" />
</Button>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button
x:Name="SearchFilterButton"
Width="36" Height="32"
Background="Transparent"
AutomationProperties.Name="Filter"
Style="{StaticResource ToolBarButtonStyle}"
ToolTipService.ToolTip="Filter"
Loaded="SearchFilterButton_Loaded"
DataContext="{x:Bind SearchOption}"
IsEnabled="{x:Bind IsPageTypeNotHome, Mode=OneWay}"
Visibility="{x:Bind IsSearchRegionVisible, Mode=OneWay}">
<FontIcon FontSize="14" Glyph="&#xE71C;" />
<Button.Flyout>
<Flyout Placement="Bottom" Closed="SearchFilterButton_Closed">
<StackPanel Spacing="12">
<TextBlock
x:Uid="NavToolbarSearchWhenHeader"
FontWeight="Medium" Text="When" />
<StackPanel Spacing="4" Orientation="Horizontal">
<usercontrols:CalendarPicker
x:Name="SearchWhenFrom"
Width="140"
PlaceholderText="From"
Date="{Binding MinDate, Mode=TwoWay}"
/>
<usercontrols:CalendarPicker
x:Name="SearchWhenTo"
Width="140"
PlaceholderText="To"
Date="{Binding MaxDate, Mode=TwoWay}"
/>
</StackPanel>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<Button
x:Name="SearchButton"
x:Uid="NavSearchButton"
Grid.Column="2"
Width="36" Height="32"
AccessKey="I"
AutomationProperties.Name="Search"
Background="Transparent"
Click="SearchButton_Click"
IsEnabled="{x:Bind IsPageTypeNotHome, Mode=OneWay}"
Style="{StaticResource ToolBarButtonStyle}"
ToolTipService.ToolTip="Search">
<FontIcon FontSize="14" Glyph="&#xE721;" />
</Button>
</StackPanel>
</Grid>

<StackPanel
Expand Down
37 changes: 31 additions & 6 deletions Files/UserControls/NavigationToolbar.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Files.DataModels;
using Files.Filesystem;
using Files.Filesystem.Search;
using Files.Helpers;
using Files.Helpers.XamlHelpers;
using Files.UserControls.MultitaskingControl;
Expand Down Expand Up @@ -879,6 +880,8 @@ string INavigationToolbar.PathControlDisplayText
}
}

private FolderSearchOption SearchOption { get; } = new FolderSearchOption();

private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Expand Down Expand Up @@ -1237,19 +1240,30 @@ private void SearchRegion_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBox

private void SearchButton_Click(object sender, RoutedEventArgs e)
{
IsSearchRegionVisible = true;
if (IsSearchRegionVisible)
{
SearchRegion.Text = "";
IsSearchRegionVisible = false;
}
else
{
IsSearchRegionVisible = true;

// Given that binding and layouting might take a few cycles, when calling UpdateLayout
// we can guarantee that the focus call will be able to find an open ASB
SearchRegion.UpdateLayout();
// Given that binding and layouting might take a few cycles, when calling UpdateLayout
// we can guarantee that the focus call will be able to find an open ASB
SearchRegion.UpdateLayout();

SearchRegion.Focus(FocusState.Programmatic);
SearchRegion.Focus(FocusState.Programmatic);
}
}

private void SearchRegion_LostFocus(object sender, RoutedEventArgs e)
{
var focusedElement = FocusManager.GetFocusedElement();
if (focusedElement is FlyoutBase || focusedElement is AppBarButton)
if (focusedElement == SearchFilterButton
|| focusedElement == SearchButton
|| focusedElement is FlyoutBase
|| focusedElement is AppBarButton)
{
return;
}
Expand All @@ -1258,6 +1272,17 @@ private void SearchRegion_LostFocus(object sender, RoutedEventArgs e)
IsSearchRegionVisible = false;
}

private void SearchFilterButton_Loaded(object sender, RoutedEventArgs e)
{
SearchWhenFrom.PlaceholderText = "NavToolbarSearchWhenFrom/PlaceholderText".GetLocalized();
SearchWhenTo.PlaceholderText = "NavToolbarSearchWhenTo/PlaceholderText".GetLocalized();
}

private void SearchFilterButton_Closed(object sender, object e)
{
SearchRegion.Focus(FocusState.Pointer);
}

public void ClearSearchBoxQueryText(bool collapseSearchRegion = false)
{
SearchRegion.Text = "";
Expand Down
13 changes: 8 additions & 5 deletions Files/Views/ColumnShellPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,9 @@ private async void ColumnShellPage_SearchTextChanged(AutoSuggestBox sender, Auto
{
if (!string.IsNullOrWhiteSpace(sender.Text))
{
sender.ItemsSource = await FolderSearch.SearchForUserQueryTextAsync(sender.Text, FilesystemViewModel.WorkingDirectory, this, App.AppSettings.SearchUnindexedItems);
var option = sender.Tag as FolderSearchOption;
sender.ItemsSource = await FolderSearch.SearchForUserQueryTextAsync(sender.Text,
FilesystemViewModel.WorkingDirectory, this, App.AppSettings.SearchUnindexedItems, option);
}
else
{
Expand All @@ -322,7 +324,8 @@ private async void ColumnShellPage_SearchQuerySubmitted(AutoSuggestBox sender, A
{
if (args.ChosenSuggestion == null && !string.IsNullOrWhiteSpace(args.QueryText))
{
SubmitSearch(args.QueryText, App.AppSettings.SearchUnindexedItems);
var option = sender.Tag as FolderSearchOption;
SubmitSearch(args.QueryText, App.AppSettings.SearchUnindexedItems, option);
}
}

Expand Down Expand Up @@ -1321,7 +1324,7 @@ public void RemoveLastPageFromBackStack()
ItemDisplayFrame.BackStack.Remove(ItemDisplayFrame.BackStack.Last());
}

public async void SubmitSearch(string query, bool searchUnindexedItems)
public async void SubmitSearch(string query, bool searchUnindexedItems, FolderSearchOption option = null)
{
InstanceViewModel.CurrentSearchQuery = query;
FilesystemViewModel.IsLoadingIndicatorActive = true;
Expand All @@ -1331,8 +1334,8 @@ public async void SubmitSearch(string query, bool searchUnindexedItems)
AssociatedTabInstance = this,
IsSearchResultPage = true,
SearchPathParam = FilesystemViewModel.WorkingDirectory,
SearchResults = await FolderSearch.SearchForUserQueryTextAsync(query, FilesystemViewModel.WorkingDirectory, this, searchUnindexedItems, -1,
InstanceViewModel.FolderSettings.GetIconSize())
SearchResults = await FolderSearch.SearchForUserQueryTextAsync(query, FilesystemViewModel.WorkingDirectory,
this, searchUnindexedItems, option, -1, InstanceViewModel.FolderSettings.GetIconSize())
});
FilesystemViewModel.IsLoadingIndicatorActive = false;
}
Expand Down
Loading