Somil55/merge custom ui into launcher (#2271)

* Remove Autosuggest box (#2192)

* Update Settings.Designer.cs

* Revert "Update Settings.Designer.cs"

This reverts commit a1bc0dda56.

* Updated LauncherControl XAML to add textbox and listview

* List View displayed

* Hooking up execution on the selected index, removing two way binding on selection, and experimenting with popup that doesn't work

* Updated MainViewModel to Remove context menu and history

* Added Resultist XAML Island project

* Updated SelectedItem and SelectedList Binding.
Issues :  List box doesn't open when query is written for first time but opens in subsequent queries.

* 1. Mouse Click working
2. List View is can't be focused
3. Fixed width of Launcher

* Removed two way QueryText box binding

* Removed SelectedItem two way binding and replaced with a callback

* [Cleaning] Remove redundant UWP project

* [Cleaning] Updated files to keep only atomic changes against dev/powerLauncher

* Thmbnail fixed for NEW UI

* Removed PreviewMouseDown function required by older WOX code

Co-authored-by: ryanbodrug-microsoft <56318517+ryanbodrug-microsoft@users.noreply.github.com>

* Added the auto-complete feature

* Removing ContextMenuPluginInfo, and ContextMenuTopMost as these commands are not used int the new design.

* Fixed merge conflicts

* Set only when index is 0

* One way binding

* Removed unnecessary binding

* Deleting unused (commented out code) that was legacy from wox project.

* Binding Buttons to appropriate context menu commands.
1. Buttons are dynamically loaded in a listview based on the actions supported be each plugin.

This change also deletes unused commands.

Note:  Most button events don't seem to be getting routed to the Selected Item.  Currently using 'PointerEntered' to validate the behavior.  The actions should be trigged by the button command property in the future.

* manually handling tab in mainwindow

* Loading context buttons on Selecting a suggestion list item

* Allowing hover event to load content menu items and display them as well.

* Adding context buttons to Indexer plugin.  This allows for the following:
1. [Files] Open Containing folder
2. [Folders/Files] Copy Path

* Remove White background of list (#2218)

* Remove white background of list

* Removed comments

* Changed to ContainerContentChanging event

* add const variables instead of numbers

* Added comment before the updatelistSize function

* Search box UI (#2224)

* Added backdrop and rounded corner

* Fix for two alt+space press to bring searchbox issue

* Fixed merge conflict

* Clean Mainwindow.xaml code

* Fix for textbox focus on first visible

* Allowing users to tab between the context buttons for the selected resut.  Also allowing users to press 'enter' to action on the selected items.

* Renaming SelectedIndex to ContextMenuSelectedIndex

* Enabling key accelerators on context buttons.
1. Add new object ContextMenuResult instead instead of reusing Result for both query results and context menu results.
2. Binding KeyboardAccelerator keys to contextmenuitemviewmodel
3. Enabling and disabling contextmenu items when selecting or deselecting each row.  Because we are manually maintaining selectionwe can't use ScopeOwners as the textbox is really the only item ever in focus.

* Launching explorer instead of the UWP application when selecting 'open file location'.

* Added fix for border showing up when result count is zero

* Updated fix for border on no result

* Adding visibility  after clearing result in MainViewmodel

* Launcher Light/Dark mode (#2235)

* Fixed issue with list view background not updating with Windows theme change

* Added theme change for WPF

* updated ShadowDepth for dropshadow

* Updated border thicknes of searchbox and listview

* Diff issue with ResultList.xaml

* Removed change in result delay

* Added code to pull colors from UWP

* Updated border resource to use system based SystemControlHighlightAccentBrush

* Updated corner radius in dark mode

* Updated Launcher description text

Co-authored-by: ryanbodrug-microsoft <56318517+ryanbodrug-microsoft@users.noreply.github.com>
Co-authored-by: Alekhya Reddy <reddykalekhya@gmail.com>
This commit is contained in:
Divyansh Srivastava
2020-04-20 19:53:20 -07:00
committed by GitHub
parent afd22768fc
commit 7da8689bf2
30 changed files with 1285 additions and 638 deletions

View File

@@ -0,0 +1,17 @@
using System.Drawing;
using System.Windows.Input;
using Wox.Plugin;
namespace Wox.ViewModel
{
public class ContextMenuItemViewModel : BaseModel
{
public string Title { get; set; }
public string Glyph { get; set; }
public string FontFamily { get; set; }
public ICommand Command { get; set; }
public string AcceleratorKey { get; set; }
public string AcceleratorModifiers { get; set; }
public bool IsEnabled { get; set; }
}
}

View File

@@ -114,6 +114,16 @@ namespace Wox.ViewModel
SelectPrevItemCommand = new RelayCommand(_ =>
{
SelectedResults.SelectPrevResult();
});
SelectNextTabItemCommand = new RelayCommand(_ =>
{
SelectedResults.SelectNextTabItem();
});
SelectPrevTabItemCommand = new RelayCommand(_ =>
{
SelectedResults.SelectPrevTabItem();
});
SelectNextPageCommand = new RelayCommand(_ =>
@@ -142,27 +152,33 @@ namespace Wox.ViewModel
results.SelectedIndex = int.Parse(index.ToString());
}
var result = results.SelectedItem?.Result;
if (result != null) // SelectedItem returns null if selection is empty.
{
bool hideWindow = result.Action != null && result.Action(new ActionContext
{
SpecialKeyState = GlobalHotkey.Instance.CheckModifiers()
});
//If there is a context button selected fire the action for that button before the main command.
bool didExecuteContextButton = results.SelectedItem?.ExecuteSelectedContextButton() ?? false;
if (hideWindow)
if (!didExecuteContextButton)
{
var result = results.SelectedItem?.Result;
if (result != null) // SelectedItem returns null if selection is empty.
{
MainWindowVisibility = Visibility.Collapsed;
}
bool hideWindow = result.Action != null && result.Action(new ActionContext
{
SpecialKeyState = GlobalHotkey.Instance.CheckModifiers()
});
if (SelectedIsFromQueryResults())
{
_userSelectedRecord.Add(result);
_history.Add(result.OriginQuery.RawQuery);
}
else
{
SelectedResults = Results;
if (hideWindow)
{
MainWindowVisibility = Visibility.Collapsed;
}
if (SelectedIsFromQueryResults())
{
_userSelectedRecord.Add(result);
_history.Add(result.OriginQuery.RawQuery);
}
else
{
SelectedResults = Results;
}
}
}
});
@@ -270,7 +286,11 @@ namespace Wox.ViewModel
public ICommand EscCommand { get; set; }
public ICommand SelectNextItemCommand { get; set; }
public ICommand SelectPrevItemCommand { get; set; }
public ICommand SelectPrevItemCommand { get; set; }
public ICommand SelectNextTabItemCommand { get; set; }
public ICommand SelectPrevTabItemCommand { get; set; }
public ICommand SelectNextPageCommand { get; set; }
public ICommand SelectPrevPageCommand { get; set; }
public ICommand SelectFirstResultCommand { get; set; }
@@ -287,46 +307,12 @@ namespace Wox.ViewModel
{
QueryResults();
}
else if (ContextMenuSelected())
{
QueryContextMenu();
}
else if (HistorySelected())
{
QueryHistory();
}
}
private void QueryContextMenu()
{
const string id = "Context Menu ID";
var query = QueryText.ToLower().Trim();
ContextMenu.Clear();
var selected = Results.SelectedItem?.Result;
if (selected != null) // SelectedItem returns null if selection is empty.
{
var results = PluginManager.GetContextMenusForPlugin(selected);
results.Add(ContextMenuTopMost(selected));
results.Add(ContextMenuPluginInfo(selected.PluginID));
if (!string.IsNullOrEmpty(query))
{
var filtered = results.Where
(
r => StringMatcher.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet()
|| StringMatcher.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet()
).ToList();
ContextMenu.AddResults(filtered, id);
}
else
{
ContextMenu.AddResults(results, id);
}
}
}
private void QueryHistory()
{
const string id = "Query History ID";
@@ -387,9 +373,9 @@ namespace Wox.ViewModel
// handle the exclusiveness of plugin using action keyword
RemoveOldQueryResults(query);
_lastQuery = query;
_lastQuery = query;
var plugins = PluginManager.ValidPluginsForQuery(query);
Task.Run(() =>
{
// so looping will stop once it was cancelled
@@ -463,66 +449,6 @@ namespace Wox.ViewModel
}
private Result ContextMenuTopMost(Result result)
{
Result menu;
if (_topMostRecord.IsTopMost(result))
{
menu = new Result
{
Title = InternationalizationManager.Instance.GetTranslation("cancelTopMostInThisQuery"),
IcoPath = "Images\\down.png",
PluginDirectory = Constant.ProgramDirectory,
Action = _ =>
{
_topMostRecord.Remove(result);
App.API.ShowMsg("Success");
return false;
}
};
}
else
{
menu = new Result
{
Title = InternationalizationManager.Instance.GetTranslation("setAsTopMostInThisQuery"),
IcoPath = "Images\\up.png",
PluginDirectory = Constant.ProgramDirectory,
Action = _ =>
{
_topMostRecord.AddOrUpdate(result);
App.API.ShowMsg("Success");
return false;
}
};
}
return menu;
}
private Result ContextMenuPluginInfo(string id)
{
var metadata = PluginManager.GetPluginForId(id).Metadata;
var translator = InternationalizationManager.Instance;
var author = translator.GetTranslation("author");
var website = translator.GetTranslation("website");
var version = translator.GetTranslation("version");
var plugin = translator.GetTranslation("plugin");
var title = $"{plugin}: {metadata.Name}";
var icon = metadata.IcoPath;
var subtitle = $"{author}: {metadata.Author}, {website}: {metadata.Website} {version}: {metadata.Version}";
var menu = new Result
{
Title = title,
IcoPath = icon,
SubTitle = subtitle,
PluginDirectory = metadata.PluginDirectory,
Action = _ => false
};
return menu;
}
private bool SelectedIsFromQueryResults()
{
var selected = SelectedResults == Results;

View File

@@ -1,69 +1,186 @@
using System;
using Wox.Infrastructure;
using Wox.Infrastructure.Image;
using Wox.Infrastructure.Logger;
using Wox.Plugin;
using Windows.UI.Xaml.Media;
namespace Wox.ViewModel
{
public class ResultViewModel : BaseModel
{
public ResultViewModel(Result result)
{
if (result != null)
{
Result = result;
}
}
public ImageSource Image
{
get
{
var imagePath = Result.IcoPath;
if (string.IsNullOrEmpty(imagePath) && Result.Icon != null)
{
try
{
return Result.Icon();
}
catch (Exception e)
{
Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e);
imagePath = Constant.ErrorIcon;
}
}
// will get here either when icoPath has value\icon delegate is null\when had exception in delegate
return ImageLoader.Load(imagePath);
}
}
public Result Result { get; }
public override bool Equals(object obj)
{
var r = obj as ResultViewModel;
if (r != null)
{
return Result.Equals(r.Result);
}
else
{
return false;
}
}
public override int GetHashCode()
{
return Result.GetHashCode();
}
public override string ToString()
{
return Result.Title.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls.Ribbon;
using System.Windows.Input;
using Wox.Core.Plugin;
using Wox.Infrastructure;
using Wox.Infrastructure.Hotkey;
using Wox.Infrastructure.Image;
using Wox.Infrastructure.Logger;
using Wox.Plugin;
using Windows.UI.Xaml.Media;
namespace Wox.ViewModel
{
public class ResultViewModel : BaseModel
{
public List<ContextMenuItemViewModel> ContextMenuItems { get; set; }
public ICommand LoadContextMenuCommand { get; set; }
public bool IsSelected { get; set; }
public int ContextMenuSelectedIndex { get; set; }
const int NoSelectionIndex = -1;
public ResultViewModel(Result result)
{
if (result != null)
{
Result = result;
}
ContextMenuSelectedIndex = NoSelectionIndex;
LoadContextMenuCommand = new RelayCommand(LoadContextMenu);
}
public void LoadContextMenu(object sender=null)
{
var results = PluginManager.GetContextMenusForPlugin(Result);
var newItems = new List<ContextMenuItemViewModel>();
foreach (var r in results)
{
newItems.Add(new ContextMenuItemViewModel
{
Title = r.Title,
Glyph = r.Glyph,
FontFamily = r.FontFamily,
AcceleratorKey = r.AcceleratorKey,
AcceleratorModifiers = r.AcceleratorModifiers,
Command = new RelayCommand(_ =>
{
bool hideWindow = r.Action != null && r.Action(new ActionContext
{
SpecialKeyState = GlobalHotkey.Instance.CheckModifiers()
});
if (hideWindow)
{
//TODO - Do we hide the window
// MainWindowVisibility = Visibility.Collapsed;
}
})
});
}
ContextMenuItems = newItems;
}
internal void EnableContextMenu()
{
foreach(var i in ContextMenuItems)
{
i.IsEnabled = true;
}
}
internal void DisableContextMenu()
{
foreach (var i in ContextMenuItems)
{
i.IsEnabled = false;
}
}
public ImageSource Image
{
get
{
var imagePath = Result.IcoPath;
if (string.IsNullOrEmpty(imagePath) && Result.Icon != null)
{
try
{
return Result.Icon();
}
catch (Exception e)
{
Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e);
imagePath = Constant.ErrorIcon;
}
}
// will get here either when icoPath has value\icon delegate is null\when had exception in delegate
return ImageLoader.Load(imagePath);
}
}
//Returns false if we've already reached the last item.
public bool SelectNextContextButton()
{
if(ContextMenuSelectedIndex == (ContextMenuItems.Count -1))
{
ContextMenuSelectedIndex = NoSelectionIndex;
return false;
}
ContextMenuSelectedIndex++;
return true;
}
//Returns false if we've already reached the first item.
public bool SelectPrevContextButton()
{
if (ContextMenuSelectedIndex == NoSelectionIndex)
{
return false;
}
ContextMenuSelectedIndex--;
return true;
}
public void SelectLastContextButton()
{
ContextMenuSelectedIndex = ContextMenuItems.Count - 1;
}
public bool HasSelectedContextButton()
{
var isContextSelected = (ContextMenuSelectedIndex != NoSelectionIndex);
return isContextSelected;
}
/// <summary>
/// Triggers the action on the selected context button
/// </summary>
/// <returns>False if there is nothing selected, oherwise true</returns>
public bool ExecuteSelectedContextButton()
{
if (HasSelectedContextButton())
{
ContextMenuItems[ContextMenuSelectedIndex].Command.Execute(null);
return true;
}
return false;
}
public Result Result { get; }
public override bool Equals(object obj)
{
var r = obj as ResultViewModel;
if (r != null)
{
return Result.Equals(r.Result);
}
else
{
return false;
}
}
public override int GetHashCode()
{
return Result.GetHashCode();
}
public override string ToString()
{
return Result.Title.ToString();
}
}
}

View File

@@ -6,6 +6,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using Wox.Infrastructure.UserSettings;
using Wox.Plugin;
@@ -47,9 +48,33 @@ namespace Wox.ViewModel
public int SelectedIndex { get; set; }
public ResultViewModel SelectedItem { get; set; }
private ResultViewModel _selectedItem;
public ResultViewModel SelectedItem
{
get { return _selectedItem; }
set
{
//value can be null when selecting an item in a virtualized list
if (value != null)
{
if (_selectedItem != null)
{
_selectedItem.IsSelected = false;
_selectedItem.DisableContextMenu();
}
_selectedItem = value;
_selectedItem.LoadContextMenu();
_selectedItem.EnableContextMenu();
_selectedItem.IsSelected = true;
}
}
}
public Thickness Margin { get; set; }
public Visibility Visbility { get; set; } = Visibility.Collapsed;
public Visibility Visbility { get; set; } = Visibility.Hidden;
#endregion
@@ -127,8 +152,26 @@ namespace Wox.ViewModel
public void RemoveResultsFor(PluginMetadata metadata)
{
Results.RemoveAll(r => r.Result.PluginID == metadata.ID);
}
}
public void SelectNextTabItem()
{
if(!SelectedItem.SelectNextContextButton())
{
SelectNextResult();
}
}
public void SelectPrevTabItem()
{
if (!SelectedItem.SelectPrevContextButton())
{
//Tabbing backwards should highlight the last item of the previous row
SelectPrevResult();
SelectedItem.SelectLastContextButton();
}
}
/// <summary>
/// To avoid deadlock, this method should not called from main thread
/// </summary>
@@ -149,6 +192,7 @@ namespace Wox.ViewModel
else
{
Margin = new Thickness { Top = 0 };
Visbility = Visibility.Collapsed;
}
}
}