From 5102770ad5ea25e59addeb85869266fefd0ff038 Mon Sep 17 00:00:00 2001 From: bao-qian Date: Thu, 23 Jun 2016 00:22:41 +0100 Subject: [PATCH 1/3] move properties into models --- Wox/ResultListBox.xaml | 8 ++-- Wox/ViewModel/MainViewModel.cs | 14 +++--- Wox/ViewModel/ResultViewModel.cs | 71 +++++-------------------------- Wox/ViewModel/ResultsViewModel.cs | 22 +++++----- 4 files changed, 34 insertions(+), 81 deletions(-) diff --git a/Wox/ResultListBox.xaml b/Wox/ResultListBox.xaml index 53801bc9e..6327842e6 100644 --- a/Wox/ResultListBox.xaml +++ b/Wox/ResultListBox.xaml @@ -41,10 +41,10 @@ - + VerticalAlignment="Center" ToolTip="{Binding Result.Title}" x:Name="Title" + Text="{Binding Result.Title}" /> + diff --git a/Wox/ViewModel/MainViewModel.cs b/Wox/ViewModel/MainViewModel.cs index 528126560..842faf6da 100644 --- a/Wox/ViewModel/MainViewModel.cs +++ b/Wox/ViewModel/MainViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -168,7 +169,7 @@ namespace Wox.ViewModel results.SelectedIndex = int.Parse(index.ToString()); } - var result = results.SelectedItem?.RawResult; + var result = results.SelectedItem?.Result; if (result != null) // SelectedItem returns null if selection is empty. { bool hideWindow = result.Action != null && result.Action(new ActionContext @@ -193,7 +194,7 @@ namespace Wox.ViewModel { if (!ContextMenuVisibility.IsVisible()) { - var result = Results.SelectedItem?.RawResult; + var result = Results.SelectedItem?.Result; if (result != null) // SelectedItem returns null if selection is empty. { @@ -340,12 +341,13 @@ namespace Wox.ViewModel { List filterResults = new List(); - foreach (var contextMenu in ContextMenu.Results) + foreach (var result in ContextMenu.Results.Select(r => r.Result)) { - if (StringMatcher.IsMatch(contextMenu.Title, query) - || StringMatcher.IsMatch(contextMenu.SubTitle, query)) + var matched = StringMatcher.IsMatch(result.Title, query) || + StringMatcher.IsMatch(result.SubTitle, query); + if (matched) { - filterResults.Add(contextMenu.RawResult); + filterResults.Add(result); } } ContextMenu.Clear(); diff --git a/Wox/ViewModel/ResultViewModel.cs b/Wox/ViewModel/ResultViewModel.cs index bebbf5aa7..9cbf7a5c5 100644 --- a/Wox/ViewModel/ResultViewModel.cs +++ b/Wox/ViewModel/ResultViewModel.cs @@ -1,6 +1,4 @@ -using System; -using System.Windows.Media; -using System.Windows; +using System.Windows.Media; using Wox.Infrastructure.Image; using Wox.Plugin; @@ -9,86 +7,39 @@ namespace Wox.ViewModel { public class ResultViewModel : BaseModel { - #region Private Fields - - private bool _isSelected; - - #endregion - - #region Constructor - public ResultViewModel(Result result) { if (result != null) { - RawResult = result; + Result = result; } } + public ImageSource Image => ImageLoader.Load(Result.IcoPath); - #endregion - - #region ViewModel Properties - - public string Title => RawResult.Title; - - public string SubTitle => RawResult.SubTitle; - - public string PluginID => RawResult.PluginID; - - public ImageSource Image => ImageLoader.Load(RawResult.IcoPath); - - public int Score - { - get { return RawResult.Score; } - set { RawResult.Score = value; } - } - - public Query OriginQuery - { - get { return RawResult.OriginQuery; } - set { RawResult.OriginQuery = value; } - } - - public Func Action - { - get { return RawResult.Action; } - set { RawResult.Action = value; } - } - - #endregion - - #region Properties - - internal Result RawResult { get; } - - #endregion - - public void Update(ResultViewModel newResult) - { - RawResult.Score = newResult.RawResult.Score; - RawResult.OriginQuery = newResult.RawResult.OriginQuery; - } + public Result Result { get; } public override bool Equals(object obj) { ResultViewModel r = obj as ResultViewModel; if (r != null) { - return RawResult.Equals(r.RawResult); + return Result.Equals(r.Result); + } + else + { + return false; } - - return false; } public override int GetHashCode() { - return RawResult.GetHashCode(); + return Result.GetHashCode(); } public override string ToString() { - return RawResult.ToString(); + return Result.ToString(); } } diff --git a/Wox/ViewModel/ResultsViewModel.cs b/Wox/ViewModel/ResultsViewModel.cs index 3a0743143..8d6802405 100644 --- a/Wox/ViewModel/ResultsViewModel.cs +++ b/Wox/ViewModel/ResultsViewModel.cs @@ -58,7 +58,7 @@ namespace Wox.ViewModel for (; index < list.Count; index++) { var result = list[index]; - if (newScore > result.RawResult.Score) + if (newScore > result.Result.Score) { break; } @@ -113,12 +113,12 @@ namespace Wox.ViewModel public void RemoveResultsExcept(PluginMetadata metadata) { - Results.RemoveAll(r => r.RawResult.PluginID != metadata.ID); + Results.RemoveAll(r => r.Result.PluginID != metadata.ID); } public void RemoveResultsFor(PluginMetadata metadata) { - Results.RemoveAll(r => r.PluginID == metadata.ID); + Results.RemoveAll(r => r.Result.PluginID == metadata.ID); } /// @@ -149,7 +149,7 @@ namespace Wox.ViewModel { var newResults = newRawResults.Select(r => new ResultViewModel(r)).ToList(); var results = Results.ToList(); - var oldResults = results.Where(r => r.PluginID == resultId).ToList(); + var oldResults = results.Where(r => r.Result.PluginID == resultId).ToList(); // intersection of A (old results) and B (new newResults) var intersection = oldResults.Intersect(newResults).ToList(); @@ -164,15 +164,15 @@ namespace Wox.ViewModel foreach (var commonResult in intersection) { int oldIndex = results.IndexOf(commonResult); - int oldScore = results[oldIndex].Score; + int oldScore = results[oldIndex].Result.Score; var newResult = newResults[newResults.IndexOf(commonResult)]; - int newScore = newResult.Score; + int newScore = newResult.Result.Score; if (newScore != oldScore) { var oldResult = results[oldIndex]; - oldResult.Score = newScore; - oldResult.OriginQuery = newResult.OriginQuery; + oldResult.Result.Score = newScore; + oldResult.Result.OriginQuery = newResult.Result.OriginQuery; results.RemoveAt(oldIndex); int newIndex = InsertIndexOf(newScore, results); @@ -183,7 +183,7 @@ namespace Wox.ViewModel // insert result in relative complement of A in B foreach (var result in newResults.Except(intersection)) { - int newIndex = InsertIndexOf(result.Score, results); + int newIndex = InsertIndexOf(result.Result.Score, results); results.Insert(newIndex, result); } @@ -223,9 +223,9 @@ namespace Wox.ViewModel { this[i] = newResult; } - else if (oldResult.Score != newResult.Score) + else if (oldResult.Result.Score != newResult.Result.Score) { - this[i].Score = newResult.Score; + this[i].Result.Score = newResult.Result.Score; } } From b589a1a13ed43ec79ea5f1bad757dcb9dd15cf0f Mon Sep 17 00:00:00 2001 From: bao-qian Date: Thu, 23 Jun 2016 00:26:57 +0100 Subject: [PATCH 2/3] Move ResultListBox Visibility 1. Move ResultListBox Visibility from MainViewModel to ResultsViewModel 2. Refactoring --- Wox/Helper/VisibilityExtensions.cs | 12 -- Wox/MainWindow.xaml | 5 +- Wox/MainWindow.xaml.cs | 7 +- Wox/ResultListBox.xaml | 1 + Wox/ViewModel/MainViewModel.cs | 217 ++++++++++++----------------- Wox/ViewModel/ResultViewModel.cs | 2 +- Wox/ViewModel/ResultsViewModel.cs | 3 +- Wox/Wox.csproj | 1 - 8 files changed, 101 insertions(+), 147 deletions(-) delete mode 100644 Wox/Helper/VisibilityExtensions.cs diff --git a/Wox/Helper/VisibilityExtensions.cs b/Wox/Helper/VisibilityExtensions.cs deleted file mode 100644 index 63ecb74b4..000000000 --- a/Wox/Helper/VisibilityExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Windows; - -namespace Wox.Helper -{ - public static class VisibilityExtensions - { - public static bool IsVisible(this Visibility visibility) - { - return visibility == Visibility.Visible; - } - } -} diff --git a/Wox/MainWindow.xaml b/Wox/MainWindow.xaml index f5787f8bf..575eb9616 100644 --- a/Wox/MainWindow.xaml +++ b/Wox/MainWindow.xaml @@ -53,6 +53,7 @@ @@ -70,10 +71,10 @@ Style="{DynamicResource PendingLineStyle}" Visibility="{Binding ProgressBarVisibility, Mode=TwoWay}" Y1="0" Y2="0" X2="100" Height="2" Width="752" StrokeThickness="1"> - + - + diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index 1d41cfcbb..1a130c71b 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -57,7 +57,7 @@ namespace Wox { if (e.PropertyName == nameof(MainViewModel.MainWindowVisibility)) { - if (_viewModel.MainWindowVisibility.IsVisible()) + if (Visibility == Visibility.Visible) { Activate(); QueryTextBox.Focus(); @@ -227,5 +227,10 @@ namespace Wox e.Handled = true; } } + + private void OnTextChanged(object sender, TextChangedEventArgs e) + { + QueryTextBox.CaretIndex = QueryTextBox.Text.Length; + } } } \ No newline at end of file diff --git a/Wox/ResultListBox.xaml b/Wox/ResultListBox.xaml index 6327842e6..ad6a22e87 100644 --- a/Wox/ResultListBox.xaml +++ b/Wox/ResultListBox.xaml @@ -11,6 +11,7 @@ SelectedItem="{Binding SelectedItem, Mode=OneWayToSource}" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Results}" Margin="{Binding Margin}" + Visibility="{Binding Visbility}" Style="{DynamicResource BaseListboxStyle}" Focusable="False" KeyboardNavigation.DirectionalNavigation="Cycle" SelectionMode="Single" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Standard" diff --git a/Wox/ViewModel/MainViewModel.cs b/Wox/ViewModel/MainViewModel.cs index 842faf6da..530e66972 100644 --- a/Wox/ViewModel/MainViewModel.cs +++ b/Wox/ViewModel/MainViewModel.cs @@ -25,11 +25,8 @@ namespace Wox.ViewModel { #region Private Fields - private Visibility _contextMenuVisibility; - private bool _queryHasReturn; private Query _lastQuery; - private bool _ignoreTextChange; private string _queryTextBeforeLoadContextMenu; private string _queryText; @@ -65,8 +62,10 @@ namespace Wox.ViewModel _userSelectedRecord = _userSelectedRecordStorage.Load(); _topMostRecord = _topMostRecordStorage.Load(); - InitializeResultListBox(); - InitializeContextMenu(); + ContextMenu = new ResultsViewModel(_settings); + Results = new ResultsViewModel(_settings); + _selectedResults = Results; + InitializeKeyCommands(); RegisterResultsUpdatedEvent(); @@ -78,7 +77,7 @@ namespace Wox.ViewModel { foreach (var pair in PluginManager.GetPluginsForInterface()) { - var plugin = (IResultUpdated) pair.Plugin; + var plugin = (IResultUpdated)pair.Plugin; plugin.ResultsUpdated += (s, e) => { Task.Run(() => @@ -96,9 +95,9 @@ namespace Wox.ViewModel { EscCommand = new RelayCommand(_ => { - if (ContextMenuVisibility.IsVisible()) + if (!ResultsSelected()) { - ContextMenuVisibility = Visibility.Collapsed; + SelectedResults = Results; } else { @@ -108,26 +107,12 @@ namespace Wox.ViewModel SelectNextItemCommand = new RelayCommand(_ => { - if (ContextMenuVisibility.IsVisible()) - { - ContextMenu.SelectNextResult(); - } - else - { - Results.SelectNextResult(); - } + SelectedResults.SelectNextResult(); }); SelectPrevItemCommand = new RelayCommand(_ => { - if (ContextMenuVisibility.IsVisible()) - { - ContextMenu.SelectPrevResult(); - } - else - { - Results.SelectPrevResult(); - } + SelectedResults.SelectPrevResult(); }); @@ -147,12 +132,12 @@ namespace Wox.ViewModel SelectNextPageCommand = new RelayCommand(_ => { - Results.SelectNextPage(); + SelectedResults.SelectNextPage(); }); SelectPrevPageCommand = new RelayCommand(_ => { - Results.SelectPrevPage(); + SelectedResults.SelectPrevPage(); }); StartHelpCommand = new RelayCommand(_ => @@ -162,7 +147,7 @@ namespace Wox.ViewModel OpenResultCommand = new RelayCommand(index => { - var results = ContextMenuVisibility.IsVisible() ? ContextMenu : Results; + var results = SelectedResults; if (index != null) { @@ -182,7 +167,7 @@ namespace Wox.ViewModel MainWindowVisibility = Visibility.Collapsed; } - if (!ContextMenuVisibility.IsVisible()) + if (ResultsSelected()) { _userSelectedRecord.Add(result); _queryHistory.Add(result.OriginQuery.RawQuery); @@ -192,75 +177,18 @@ namespace Wox.ViewModel LoadContextMenuCommand = new RelayCommand(_ => { - if (!ContextMenuVisibility.IsVisible()) + if (ResultsSelected()) { - var result = Results.SelectedItem?.Result; - - if (result != null) // SelectedItem returns null if selection is empty. - { - var id = result.PluginID; - - var menus = PluginManager.GetContextMenusForPlugin(result); - menus.Add(ContextMenuTopMost(result)); - menus.Add(ContextMenuPluginInfo(id)); - - ContextMenu.Clear(); - Task.Run(() => - { - ContextMenu.AddResults(menus, id); - }, _updateToken); - ContextMenuVisibility = Visibility.Visible; - } + SelectedResults = ContextMenu; } else { - ContextMenuVisibility = Visibility.Collapsed; + SelectedResults = Results; } }); } - private void InitializeResultListBox() - { - Results = new ResultsViewModel(_settings); - ResultListBoxVisibility = Visibility.Collapsed; - } - - - private void InitializeContextMenu() - { - ContextMenu = new ResultsViewModel(_settings); - ContextMenuVisibility = Visibility.Collapsed; - } - - private void HandleQueryTextUpdated() - { - ProgressBarVisibility = Visibility.Hidden; - _updateSource?.Cancel(); - _updateSource = new CancellationTokenSource(); - _updateToken = _updateSource.Token; - - if (ContextMenuVisibility.IsVisible()) - { - QueryContextMenu(); - } - else - { - string query = QueryText.Trim(); - if (!string.IsNullOrEmpty(query)) - { - Query(query); - //reset query history index after user start new query - ResetQueryHistoryIndex(); - } - else - { - Results.Clear(); - ResultListBoxVisibility = Visibility.Collapsed; - } - } - } - #endregion #region ViewModel Properties @@ -275,46 +203,52 @@ namespace Wox.ViewModel set { _queryText = value; - if (_ignoreTextChange) + ProgressBarVisibility = Visibility.Hidden; + + _updateSource?.Cancel(); + _updateSource = new CancellationTokenSource(); + _updateToken = _updateSource.Token; + + if (ResultsSelected()) { - _ignoreTextChange = false; + QueryResults(); } else { - HandleQueryTextUpdated(); + QueryContextMenu(); } } } + + public bool QueryTextSelected { get; set; } - public Visibility ContextMenuVisibility + private ResultsViewModel _selectedResults; + private ResultsViewModel SelectedResults { - get { return _contextMenuVisibility; } + get { return _selectedResults; } set { - _contextMenuVisibility = value; - - _ignoreTextChange = true; - if (!value.IsVisible()) + _selectedResults = value; + if (ResultsSelected()) { QueryText = _queryTextBeforeLoadContextMenu; - ResultListBoxVisibility = Visibility.Visible; + ContextMenu.Visbility = Visibility.Collapsed; } else { _queryTextBeforeLoadContextMenu = QueryText; QueryText = ""; - ResultListBoxVisibility = Visibility.Collapsed; + Results.Visbility = Visibility.Collapsed; } + _selectedResults.Visbility = Visibility.Visible; } } public Visibility ProgressBarVisibility { get; set; } - public Visibility ResultListBoxVisibility { get; set; } - public Visibility MainWindowVisibility { get; set; } public ICommand EscCommand { get; set; } @@ -335,26 +269,48 @@ namespace Wox.ViewModel private void QueryContextMenu() { - var contextMenuId = "Context Menu Id"; - var query = QueryText.ToLower(); - if (!string.IsNullOrEmpty(query)) - { + const string contextMenuId = "Context Menu Id"; + var query = QueryText.ToLower().Trim(); + ContextMenu.Clear(); - List filterResults = new List(); - foreach (var result in ContextMenu.Results.Select(r => r.Result)) + var selected = Results.SelectedItem?.Result; + + if (selected != null) // SelectedItem returns null if selection is empty. + { + var id = selected.PluginID; + + var results = PluginManager.GetContextMenusForPlugin(selected); + results.Add(ContextMenuTopMost(selected)); + results.Add(ContextMenuPluginInfo(id)); + + if (!string.IsNullOrEmpty(query)) { - var matched = StringMatcher.IsMatch(result.Title, query) || - StringMatcher.IsMatch(result.SubTitle, query); - if (matched) - { - filterResults.Add(result); - } + var filtered = results.Where + ( + r => StringMatcher.IsMatch(r.Title, query) || + StringMatcher.IsMatch(r.SubTitle, query) + ).ToList(); + ContextMenu.AddResults(filtered, contextMenuId); } - ContextMenu.Clear(); - Task.Run(() => + else { - ContextMenu.AddResults(filterResults, contextMenuId); - }, _updateToken); + ContextMenu.AddResults(results, contextMenuId); + } + } + } + + private void QueryResults() + { + if (!string.IsNullOrEmpty(QueryText)) + { + Query(QueryText.Trim()); + //reset query history index after user start new query + ResetQueryHistoryIndex(); + } + else + { + Results.Clear(); + Results.Visbility = Visibility.Collapsed; } } @@ -409,9 +365,6 @@ namespace Wox.ViewModel } }); }, _updateToken); - - - } } @@ -463,7 +416,7 @@ namespace Wox.ViewModel { Title = InternationalizationManager.Instance.GetTranslation("cancelTopMostInThisQuery"), IcoPath = "Images\\down.png", - PluginDirectory = Infrastructure.Constant.ProgramDirectory, + PluginDirectory = Constant.ProgramDirectory, Action = _ => { _topMostRecord.Remove(result); @@ -478,7 +431,7 @@ namespace Wox.ViewModel { Title = InternationalizationManager.Instance.GetTranslation("setAsTopMostInThisQuery"), IcoPath = "Images\\up.png", - PluginDirectory = Infrastructure.Constant.ProgramDirectory, + PluginDirectory = Constant.ProgramDirectory, Action = _ => { _topMostRecord.AddOrUpdate(result); @@ -514,16 +467,22 @@ namespace Wox.ViewModel return menu; } + private bool ResultsSelected() + { + var selected = SelectedResults == Results; + return selected; + } + #endregion #region Hotkey - internal void SetHotkey(string hotkeyStr, EventHandler action) + private void SetHotkey(string hotkeyStr, EventHandler action) { var hotkey = new HotkeyModel(hotkeyStr); SetHotkey(hotkey, action); } - public void SetHotkey(HotkeyModel hotkey, EventHandler action) + private void SetHotkey(HotkeyModel hotkey, EventHandler action) { string hotkeyStr = hotkey.ToString(); try @@ -584,7 +543,7 @@ namespace Wox.ViewModel private void ToggleWox() { - if (!MainWindowVisibility.IsVisible()) + if (MainWindowVisibility != Visibility.Visible) { MainWindowVisibility = Visibility.Visible; } @@ -629,7 +588,7 @@ namespace Wox.ViewModel } else { - result.Score += _userSelectedRecord.GetSelectedCount(result)*5; + result.Score += _userSelectedRecord.GetSelectedCount(result) * 5; } } @@ -638,12 +597,12 @@ namespace Wox.ViewModel Results.AddResults(list, metadata.ID); } - if (list.Count > 0 && !ResultListBoxVisibility.IsVisible()) + if (Results.Visbility != Visibility.Visible && list.Count > 0) { - ResultListBoxVisibility = Visibility.Visible; + Results.Visbility = Visibility.Visible; } } #endregion } -} \ No newline at end of file +} \ No newline at end of file diff --git a/Wox/ViewModel/ResultViewModel.cs b/Wox/ViewModel/ResultViewModel.cs index 9cbf7a5c5..62e6383d5 100644 --- a/Wox/ViewModel/ResultViewModel.cs +++ b/Wox/ViewModel/ResultViewModel.cs @@ -21,7 +21,7 @@ namespace Wox.ViewModel public override bool Equals(object obj) { - ResultViewModel r = obj as ResultViewModel; + var r = obj as ResultViewModel; if (r != null) { return Result.Equals(r.Result); diff --git a/Wox/ViewModel/ResultsViewModel.cs b/Wox/ViewModel/ResultsViewModel.cs index 8d6802405..a92b84930 100644 --- a/Wox/ViewModel/ResultsViewModel.cs +++ b/Wox/ViewModel/ResultsViewModel.cs @@ -39,7 +39,7 @@ namespace Wox.ViewModel #endregion - #region ViewModel Properties + #region Properties public int MaxHeight => MaxResults * 50; @@ -47,6 +47,7 @@ namespace Wox.ViewModel public ResultViewModel SelectedItem { get; set; } public Thickness Margin { get; set; } + public Visibility Visbility { get; set; } = Visibility.Collapsed; #endregion diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index 4f394fe14..fc4207128 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -159,7 +159,6 @@ Properties\SolutionAssemblyInfo.cs - From 15c5e9833a7d7bf18e7b086e511181fb5f03b1ac Mon Sep 17 00:00:00 2001 From: bao-qian Date: Thu, 23 Jun 2016 22:17:47 +0100 Subject: [PATCH 3/3] Bring history back 1. bring history back, disabled in 56d08663410916df0a4e408da6e4af3d2a2722c0 2. fix #632 #722 3. hotkey: ctrl+H --- Wox/MainWindow.xaml | 4 + Wox/Storage/HistoryItem.cs | 45 +++++ Wox/Storage/QueryHistory.cs | 91 +-------- Wox/ViewModel/MainViewModel.cs | 327 +++++++++++++++++---------------- Wox/Wox.csproj | 1 + 5 files changed, 231 insertions(+), 237 deletions(-) create mode 100644 Wox/Storage/HistoryItem.cs diff --git a/Wox/MainWindow.xaml b/Wox/MainWindow.xaml index 575eb9616..3412cd0ac 100644 --- a/Wox/MainWindow.xaml +++ b/Wox/MainWindow.xaml @@ -36,6 +36,7 @@ + @@ -77,6 +78,9 @@ + + + \ No newline at end of file diff --git a/Wox/Storage/HistoryItem.cs b/Wox/Storage/HistoryItem.cs new file mode 100644 index 000000000..084fa2882 --- /dev/null +++ b/Wox/Storage/HistoryItem.cs @@ -0,0 +1,45 @@ +using System; + +namespace Wox.Storage +{ + public class HistoryItem + { + public string Query { get; set; } + public DateTime ExecutedDateTime { get; set; } + + public string GetTimeAgo() + { + return DateTimeAgo(ExecutedDateTime); + } + + private string DateTimeAgo(DateTime dt) + { + var span = DateTime.Now - dt; + if (span.Days > 365) + { + int years = (span.Days / 365); + if (span.Days % 365 != 0) + years += 1; + return $"about {years} {(years == 1 ? "year" : "years")} ago"; + } + if (span.Days > 30) + { + int months = (span.Days / 30); + if (span.Days % 31 != 0) + months += 1; + return $"about {months} {(months == 1 ? "month" : "months")} ago"; + } + if (span.Days > 0) + return $"about {span.Days} {(span.Days == 1 ? "day" : "days")} ago"; + if (span.Hours > 0) + return $"about {span.Hours} {(span.Hours == 1 ? "hour" : "hours")} ago"; + if (span.Minutes > 0) + return $"about {span.Minutes} {(span.Minutes == 1 ? "minute" : "minutes")} ago"; + if (span.Seconds > 5) + return $"about {span.Seconds} seconds ago"; + if (span.Seconds <= 5) + return "just now"; + return string.Empty; + } + } +} \ No newline at end of file diff --git a/Wox/Storage/QueryHistory.cs b/Wox/Storage/QueryHistory.cs index d66113fe7..fc3f5250b 100644 --- a/Wox/Storage/QueryHistory.cs +++ b/Wox/Storage/QueryHistory.cs @@ -2,111 +2,36 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using Wox.Infrastructure.Storage; using Wox.Plugin; namespace Wox.Storage { - public class QueryHistory + public class History { - public List History = new List(); + public List Items { get; set; } = new List(); - private int MaxHistory = 300; - private int cursor; - - public static PluginMetadata MetaData { get; } = new PluginMetadata - { ID = "Query history", Name = "Query history" }; - - public HistoryItem Previous() - { - if (History.Count == 0 || cursor == 0) return null; - return History[--cursor]; - } - - public HistoryItem Next() - { - if (History.Count == 0 || cursor >= History.Count - 1) return null; - return History[++cursor]; - } - - public void Reset() - { - cursor = History.Count; - } + private int _maxHistory = 300; public void Add(string query) { if (string.IsNullOrEmpty(query)) return; - if (History.Count > MaxHistory) + if (Items.Count > _maxHistory) { - History.RemoveAt(0); + Items.RemoveAt(0); } - if (History.Count > 0 && History.Last().Query == query) + if (Items.Count > 0 && Items.Last().Query == query) { - History.Last().ExecutedDateTime = DateTime.Now; + Items.Last().ExecutedDateTime = DateTime.Now; } else { - History.Add(new HistoryItem + Items.Add(new HistoryItem { Query = query, ExecutedDateTime = DateTime.Now }); } - - Reset(); - } - - public List GetHistory() - { - return History.OrderByDescending(o => o.ExecutedDateTime).ToList(); - } - } - - public class HistoryItem - { - public string Query { get; set; } - public DateTime ExecutedDateTime { get; set; } - - public string GetTimeAgo() - { - return DateTimeAgo(ExecutedDateTime); - } - - private string DateTimeAgo(DateTime dt) - { - TimeSpan span = DateTime.Now - dt; - if (span.Days > 365) - { - int years = (span.Days / 365); - if (span.Days % 365 != 0) - years += 1; - return String.Format("about {0} {1} ago", - years, years == 1 ? "year" : "years"); - } - if (span.Days > 30) - { - int months = (span.Days / 30); - if (span.Days % 31 != 0) - months += 1; - return String.Format("about {0} {1} ago", - months, months == 1 ? "month" : "months"); - } - if (span.Days > 0) - return String.Format("about {0} {1} ago", - span.Days, span.Days == 1 ? "day" : "days"); - if (span.Hours > 0) - return String.Format("about {0} {1} ago", - span.Hours, span.Hours == 1 ? "hour" : "hours"); - if (span.Minutes > 0) - return String.Format("about {0} {1} ago", - span.Minutes, span.Minutes == 1 ? "minute" : "minutes"); - if (span.Seconds > 5) - return String.Format("about {0} seconds ago", span.Seconds); - if (span.Seconds <= 5) - return "just now"; - return string.Empty; } } } diff --git a/Wox/ViewModel/MainViewModel.cs b/Wox/ViewModel/MainViewModel.cs index 530e66972..d5fa307f6 100644 --- a/Wox/ViewModel/MainViewModel.cs +++ b/Wox/ViewModel/MainViewModel.cs @@ -27,14 +27,13 @@ namespace Wox.ViewModel private bool _queryHasReturn; private Query _lastQuery; - private string _queryTextBeforeLoadContextMenu; - private string _queryText; + private string _queryTextBeforeLeaveResults; - private readonly JsonStrorage _queryHistoryStorage; + private readonly JsonStrorage _historyItemsStorage; private readonly JsonStrorage _userSelectedRecordStorage; private readonly JsonStrorage _topMostRecordStorage; private readonly Settings _settings; - private readonly QueryHistory _queryHistory; + private readonly History _history; private readonly UserSelectedRecord _userSelectedRecord; private readonly TopMostRecord _topMostRecord; @@ -42,6 +41,8 @@ namespace Wox.ViewModel private CancellationToken _updateToken; private bool _saved; + private Internationalization _translator = InternationalizationManager.Instance; + #endregion #region Constructor @@ -49,21 +50,22 @@ namespace Wox.ViewModel public MainViewModel(Settings settings) { _saved = false; - _queryTextBeforeLoadContextMenu = ""; + _queryTextBeforeLeaveResults = ""; _queryText = ""; _lastQuery = new Query(); _settings = settings; - _queryHistoryStorage = new JsonStrorage(); + _historyItemsStorage = new JsonStrorage(); _userSelectedRecordStorage = new JsonStrorage(); _topMostRecordStorage = new JsonStrorage(); - _queryHistory = _queryHistoryStorage.Load(); + _history = _historyItemsStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load(); _topMostRecord = _topMostRecordStorage.Load(); ContextMenu = new ResultsViewModel(_settings); Results = new ResultsViewModel(_settings); + History = new ResultsViewModel(_settings); _selectedResults = Results; InitializeKeyCommands(); @@ -82,7 +84,6 @@ namespace Wox.ViewModel { Task.Run(() => { - PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); UpdateResultView(e.Results, pair.Metadata, e.Query); }, _updateToken); @@ -115,21 +116,6 @@ namespace Wox.ViewModel SelectedResults.SelectPrevResult(); }); - - /** - DisplayNextQueryCommand = new RelayCommand(_ => - { - var nextQuery = _queryHistory.Next(); - DisplayQueryHistory(nextQuery); - }); - - DisplayPrevQueryCommand = new RelayCommand(_ => - { - var prev = _queryHistory.Previous(); - DisplayQueryHistory(prev); - }); - **/ - SelectNextPageCommand = new RelayCommand(_ => { SelectedResults.SelectNextPage(); @@ -170,7 +156,7 @@ namespace Wox.ViewModel if (ResultsSelected()) { _userSelectedRecord.Add(result); - _queryHistory.Add(result.OriginQuery.RawQuery); + _history.Add(result.OriginQuery.RawQuery); } } }); @@ -187,6 +173,18 @@ namespace Wox.ViewModel } }); + LoadHistoryCommand = new RelayCommand(_ => + { + if (ResultsSelected()) + { + SelectedResults = History; + History.SelectedIndex = _history.Items.Count - 1; + } + else + { + SelectedResults = Results; + } + }); } #endregion @@ -194,38 +192,22 @@ namespace Wox.ViewModel #region ViewModel Properties public ResultsViewModel Results { get; private set; } - public ResultsViewModel ContextMenu { get; private set; } + public ResultsViewModel History { get; private set; } + private string _queryText; public string QueryText { get { return _queryText; } set { _queryText = value; - ProgressBarVisibility = Visibility.Hidden; - - _updateSource?.Cancel(); - _updateSource = new CancellationTokenSource(); - _updateToken = _updateSource.Token; - - if (ResultsSelected()) - { - QueryResults(); - } - else - { - QueryContextMenu(); - } + Query(); } } - - - public bool QueryTextSelected { get; set; } private ResultsViewModel _selectedResults; - private ResultsViewModel SelectedResults { get { return _selectedResults; } @@ -234,14 +216,28 @@ namespace Wox.ViewModel _selectedResults = value; if (ResultsSelected()) { - QueryText = _queryTextBeforeLoadContextMenu; ContextMenu.Visbility = Visibility.Collapsed; + History.Visbility = Visibility.Collapsed; + QueryText = _queryTextBeforeLeaveResults; } else { - _queryTextBeforeLoadContextMenu = QueryText; - QueryText = ""; Results.Visbility = Visibility.Collapsed; + _queryTextBeforeLeaveResults = QueryText; + + + // Because of Fody's optimization + // setter won't be called when property value is not changed. + // so we need manually call Query() + // http://stackoverflow.com/posts/25895769/revisions + if (string.IsNullOrEmpty(QueryText)) + { + Query(); + } + else + { + QueryText = string.Empty; + } } _selectedResults.Visbility = Visibility.Visible; } @@ -254,22 +250,34 @@ namespace Wox.ViewModel public ICommand EscCommand { get; set; } public ICommand SelectNextItemCommand { get; set; } public ICommand SelectPrevItemCommand { get; set; } - //todo happlebao restore history command - public ICommand DisplayNextQueryCommand { get; set; } - public ICommand DisplayPrevQueryCommand { get; set; } public ICommand SelectNextPageCommand { get; set; } public ICommand SelectPrevPageCommand { get; set; } public ICommand StartHelpCommand { get; set; } public ICommand LoadContextMenuCommand { get; set; } + public ICommand LoadHistoryCommand { get; set; } public ICommand OpenResultCommand { get; set; } #endregion - #region Private Methods + public void Query() + { + if (ResultsSelected()) + { + QueryResults(); + } + else if (ContextMenuSelected()) + { + QueryContextMenu(); + } + else if (HistorySelected()) + { + QueryHistory(); + } + } private void QueryContextMenu() { - const string contextMenuId = "Context Menu Id"; + const string id = "Context Menu ID"; var query = QueryText.ToLower().Trim(); ContextMenu.Clear(); @@ -277,11 +285,9 @@ namespace Wox.ViewModel if (selected != null) // SelectedItem returns null if selection is empty. { - var id = selected.PluginID; - var results = PluginManager.GetContextMenusForPlugin(selected); results.Add(ContextMenuTopMost(selected)); - results.Add(ContextMenuPluginInfo(id)); + results.Add(ContextMenuPluginInfo(selected.PluginID)); if (!string.IsNullOrEmpty(query)) { @@ -290,22 +296,116 @@ namespace Wox.ViewModel r => StringMatcher.IsMatch(r.Title, query) || StringMatcher.IsMatch(r.SubTitle, query) ).ToList(); - ContextMenu.AddResults(filtered, contextMenuId); + ContextMenu.AddResults(filtered, id); } else { - ContextMenu.AddResults(results, contextMenuId); + ContextMenu.AddResults(results, id); } } } + private void QueryHistory() + { + const string id = "Query History ID"; + var query = QueryText.ToLower().Trim(); + History.Clear(); + + var results = new List(); + foreach (var h in _history.Items) + { + var title = _translator.GetTranslation("executeQuery"); + var time = _translator.GetTranslation("lastExecuteTime"); + var result = new Result + { + Title = string.Format(title, h.Query), + SubTitle = string.Format(time, h.ExecutedDateTime), + IcoPath = "Images\\history.png", + OriginQuery = new Query { RawQuery = h.Query }, + Action = _ => + { + SelectedResults = Results; + QueryText = h.Query; + return false; + } + }; + results.Add(result); + } + + if (!string.IsNullOrEmpty(query)) + { + var filtered = results.Where + ( + r => StringMatcher.IsMatch(r.Title, query) || + StringMatcher.IsMatch(r.SubTitle, query) + ).ToList(); + History.AddResults(filtered, id); + } + else + { + History.AddResults(results, id); + } + } + private void QueryResults() { if (!string.IsNullOrEmpty(QueryText)) { - Query(QueryText.Trim()); - //reset query history index after user start new query - ResetQueryHistoryIndex(); + _updateSource?.Cancel(); + _updateSource = new CancellationTokenSource(); + _updateToken = _updateSource.Token; + + ProgressBarVisibility = Visibility.Hidden; + _queryHasReturn = false; + var query = PluginManager.QueryInit(QueryText.Trim()); + if (query != null) + { + // handle the exclusiveness of plugin using action keyword + string lastKeyword = _lastQuery.ActionKeyword; + string keyword = query.ActionKeyword; + if (string.IsNullOrEmpty(lastKeyword)) + { + if (!string.IsNullOrEmpty(keyword)) + { + Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata); + } + } + else + { + if (string.IsNullOrEmpty(keyword)) + { + Results.RemoveResultsFor(PluginManager.NonGlobalPlugins[lastKeyword].Metadata); + } + else if (lastKeyword != keyword) + { + Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata); + } + } + + _lastQuery = query; + Task.Delay(200, _updateToken).ContinueWith(_ => + { + if (query.RawQuery == _lastQuery.RawQuery && !_queryHasReturn) + { + ProgressBarVisibility = Visibility.Visible; + } + }, _updateToken); + + var plugins = PluginManager.ValidPluginsForQuery(query); + Task.Run(() => + { + Parallel.ForEach(plugins, plugin => + { + var config = _settings.PluginSettings.Plugins[plugin.Metadata.ID]; + if (!config.Disabled) + { + + var results = PluginManager.QueryForPlugin(plugin, query); + UpdateResultView(results, plugin.Metadata, query); + } + }); + }, _updateToken); + } } else { @@ -314,98 +414,6 @@ namespace Wox.ViewModel } } - private void Query(string text) - { - _queryHasReturn = false; - var query = PluginManager.QueryInit(text); - if (query != null) - { - // handle the exclusiveness of plugin using action keyword - string lastKeyword = _lastQuery.ActionKeyword; - string keyword = query.ActionKeyword; - if (string.IsNullOrEmpty(lastKeyword)) - { - if (!string.IsNullOrEmpty(keyword)) - { - Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata); - } - } - else - { - if (string.IsNullOrEmpty(keyword)) - { - Results.RemoveResultsFor(PluginManager.NonGlobalPlugins[lastKeyword].Metadata); - } - else if (lastKeyword != keyword) - { - Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata); - } - } - - _lastQuery = query; - Task.Delay(200, _updateToken).ContinueWith(_ => - { - if (query.RawQuery == _lastQuery.RawQuery && !_queryHasReturn) - { - ProgressBarVisibility = Visibility.Visible; - } - }, _updateToken); - - var plugins = PluginManager.ValidPluginsForQuery(query); - Task.Run(() => - { - Parallel.ForEach(plugins, plugin => - { - var config = _settings.PluginSettings.Plugins[plugin.Metadata.ID]; - if (!config.Disabled) - { - - var results = PluginManager.QueryForPlugin(plugin, query); - UpdateResultView(results, plugin.Metadata, query); - } - }); - }, _updateToken); - } - } - - private void ResetQueryHistoryIndex() - { - Results.RemoveResultsFor(QueryHistory.MetaData); - _queryHistory.Reset(); - } - /** - private void DisplayQueryHistory(HistoryItem history) - { - if (history != null) - { - var historyMetadata = QueryHistory.MetaData; - - QueryText = history.Query; - OnTextBoxSelected(); - - var executeQueryHistoryTitle = InternationalizationManager.Instance.GetTranslation("executeQuery"); - var lastExecuteTime = InternationalizationManager.Instance.GetTranslation("lastExecuteTime"); - Results.RemoveResultsExcept(historyMetadata); - var result = new Result - { - Title = string.Format(executeQueryHistoryTitle, history.Query), - SubTitle = string.Format(lastExecuteTime, history.ExecutedDateTime), - IcoPath = "Images\\history.png", - PluginDirectory = Infrastructure.Constant.ProgramDirectory, - Action = _ => - { - QueryText = history.Query; - OnTextBoxSelected(); - return false; - } - }; - Task.Run(() => - { - Results.AddResults(new List {result}, historyMetadata.ID); - }, _updateToken); - } - } - **/ private Result ContextMenuTopMost(Result result) { @@ -473,7 +481,18 @@ namespace Wox.ViewModel return selected; } - #endregion + private bool ContextMenuSelected() + { + var selected = SelectedResults == ContextMenu; + return selected; + } + + + private bool HistorySelected() + { + var selected = SelectedResults == History; + return selected; + } #region Hotkey private void SetHotkey(string hotkeyStr, EventHandler action) @@ -527,8 +546,8 @@ namespace Wox.ViewModel SetHotkey(hotkey.Hotkey, (s, e) => { if (ShouldIgnoreHotkeys()) return; - QueryText = hotkey.ActionKeyword; MainWindowVisibility = Visibility.Visible; + QueryText = hotkey.ActionKeyword; }); } } @@ -561,7 +580,7 @@ namespace Wox.ViewModel { if (!_saved) { - _queryHistoryStorage.Save(); + _historyItemsStorage.Save(); _userSelectedRecordStorage.Save(); _topMostRecordStorage.Save(); diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index fc4207128..306fa0ec3 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -165,6 +165,7 @@ ResultListBox.xaml +