mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
The rest of the settings window cleanup
This commit is contained in:
parent
baeb01f758
commit
c350c5d7cf
5 changed files with 235 additions and 1386 deletions
|
|
@ -54,7 +54,7 @@
|
|||
Margin="0 0 22 0"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding EditPluginPriorityCommand}"
|
||||
Content="{Binding Priority, UpdateSourceTrigger=PropertyChanged}"
|
||||
Content="{Binding Priority}"
|
||||
Cursor="Hand"
|
||||
ToolTip="{DynamicResource priorityToolTip}">
|
||||
<!--#region Priority Button Style-->
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
|
|
@ -11,7 +10,7 @@ using Flow.Launcher.ViewModel;
|
|||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public partial class SettingsPanePluginsViewModel : BaseModel
|
||||
public class SettingsPanePluginsViewModel : BaseModel
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
|
||||
|
|
@ -23,12 +22,18 @@ public partial class SettingsPanePluginsViewModel : BaseModel
|
|||
public string FilterText { get; set; } = string.Empty;
|
||||
|
||||
public PluginViewModel? SelectedPlugin { get; set; }
|
||||
|
||||
private IEnumerable<PluginViewModel>? _pluginViewModels;
|
||||
private IEnumerable<PluginViewModel> PluginViewModels => _pluginViewModels ??= PluginManager.AllPlugins
|
||||
.OrderBy(x => x.Metadata.Disabled)
|
||||
.ThenBy(y => y.Metadata.Name)
|
||||
.Select(p => new PluginViewModel { PluginPair = p })
|
||||
.OrderBy(plugin => plugin.Metadata.Disabled)
|
||||
.ThenBy(plugin => plugin.Metadata.Name)
|
||||
.Select(plugin => new PluginViewModel
|
||||
{
|
||||
PluginPair = plugin,
|
||||
PluginSettingsObject = _settings.PluginSettings.Plugins[plugin.Metadata.ID]
|
||||
})
|
||||
.ToList();
|
||||
|
||||
public List<PluginViewModel> FilteredPluginViewModels => PluginViewModels
|
||||
.Where(v =>
|
||||
string.IsNullOrEmpty(FilterText) ||
|
||||
|
|
@ -36,13 +41,4 @@ public partial class SettingsPanePluginsViewModel : BaseModel
|
|||
StringMatcher.FuzzySearch(FilterText, v.PluginPair.Metadata.Description).IsSearchPrecisionScoreMet()
|
||||
)
|
||||
.ToList();
|
||||
|
||||
[RelayCommand]
|
||||
private void TogglePlugin()
|
||||
{
|
||||
if (SelectedPlugin is null) return;
|
||||
var id = SelectedPlugin.PluginPair.Metadata.ID;
|
||||
// used to sync the current status from the plugin manager into the setting to keep consistency after save
|
||||
_settings.PluginSettings.Plugins[id].Disabled = SelectedPlugin.PluginPair.Metadata.Disabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,541 +1,172 @@
|
|||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Hotkey;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.ViewModel;
|
||||
using ModernWpf;
|
||||
using ModernWpf.Controls;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Configuration;
|
||||
using NHotkey;
|
||||
using Button = System.Windows.Controls.Button;
|
||||
using Control = System.Windows.Controls.Control;
|
||||
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
using ThemeManager = ModernWpf.ThemeManager;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.SettingPages.Views;
|
||||
using Flow.Launcher.ViewModel;
|
||||
using ModernWpf.Controls;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
|
||||
namespace Flow.Launcher
|
||||
namespace Flow.Launcher;
|
||||
|
||||
public partial class SettingWindow
|
||||
{
|
||||
public partial class SettingWindow
|
||||
private readonly IPublicAPI _api;
|
||||
private readonly Settings _settings;
|
||||
private readonly SettingWindowViewModel _viewModel;
|
||||
|
||||
public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel)
|
||||
{
|
||||
public readonly IPublicAPI API;
|
||||
private Settings settings;
|
||||
private SettingWindowViewModel viewModel;
|
||||
|
||||
public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel)
|
||||
{
|
||||
settings = viewModel.Settings;
|
||||
DataContext = viewModel;
|
||||
this.viewModel = viewModel;
|
||||
API = api;
|
||||
InitializePosition();
|
||||
InitializeComponent();
|
||||
NavView.SelectedItem = NavView.MenuItems[0]; /* Set First Page */
|
||||
}
|
||||
|
||||
#region General
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
// Fix (workaround) for the window freezes after lock screen (Win+L)
|
||||
// https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf
|
||||
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
|
||||
HwndTarget hwndTarget = hwndSource.CompositionTarget;
|
||||
hwndTarget.RenderMode = RenderMode.Default;
|
||||
|
||||
//pluginListView = (CollectionView)CollectionViewSource.GetDefaultView(Plugins.ItemsSource);
|
||||
//pluginListView.Filter = PluginListFilter;
|
||||
|
||||
//pluginStoreView = (CollectionView)CollectionViewSource.GetDefaultView(StoreListBox.ItemsSource);
|
||||
//pluginStoreView.Filter = PluginStoreFilter;
|
||||
|
||||
//viewModel.PropertyChanged += new PropertyChangedEventHandler(SettingsWindowViewModelChanged);
|
||||
|
||||
InitializePosition();
|
||||
}
|
||||
|
||||
//private void SettingsWindowViewModelChanged(object sender, PropertyChangedEventArgs e)
|
||||
//{
|
||||
// if (e.PropertyName == nameof(viewModel.ExternalPlugins))
|
||||
// {
|
||||
// pluginStoreView = (CollectionView)CollectionViewSource.GetDefaultView(StoreListBox.ItemsSource);
|
||||
// pluginStoreView.Filter = PluginStoreFilter;
|
||||
// pluginStoreView.Refresh();
|
||||
// }
|
||||
//}
|
||||
|
||||
private void OnSelectPythonPathClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedFile = viewModel.GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectPythonExecutable"),
|
||||
"Python|pythonw.exe");
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
settings.PluginSettings.PythonExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
private void OnSelectNodePathClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedFile = viewModel.GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectNodeExecutable"));
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
settings.PluginSettings.NodeExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
private void OnSelectFileManagerClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SelectFileManagerWindow fileManagerChangeWindow = new SelectFileManagerWindow(settings);
|
||||
fileManagerChangeWindow.ShowDialog();
|
||||
}
|
||||
|
||||
private void OnSelectDefaultBrowserClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var browserWindow = new SelectBrowserWindow(settings);
|
||||
browserWindow.ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hotkey
|
||||
|
||||
private void OnToggleHotkey(object sender, HotkeyEventArgs e)
|
||||
{
|
||||
HotKeyMapper.OnToggleHotkey(sender, e);
|
||||
}
|
||||
|
||||
private void OnDeleteCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = viewModel.SelectedCustomPluginHotkey;
|
||||
if (item == null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return;
|
||||
}
|
||||
|
||||
string deleteWarning =
|
||||
string.Format(InternationalizationManager.Instance.GetTranslation("deleteCustomHotkeyWarning"),
|
||||
item.Hotkey);
|
||||
if (
|
||||
MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
settings.CustomPluginHotkeys.Remove(item);
|
||||
HotKeyMapper.RemoveHotkey(item.Hotkey);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = viewModel.SelectedCustomPluginHotkey;
|
||||
if (item != null)
|
||||
{
|
||||
CustomQueryHotkeySetting window = new CustomQueryHotkeySetting(this, settings);
|
||||
window.UpdateItem(item);
|
||||
window.ShowDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
new CustomQueryHotkeySetting(this, settings).ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Plugin
|
||||
|
||||
private void OnPluginToggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var id = viewModel.SelectedPlugin.PluginPair.Metadata.ID;
|
||||
// used to sync the current status from the plugin manager into the setting to keep consistency after save
|
||||
settings.PluginSettings.Plugins[id].Disabled = viewModel.SelectedPlugin.PluginPair.Metadata.Disabled;
|
||||
}
|
||||
|
||||
private void OnPluginPriorityClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Control { DataContext: PluginViewModel pluginViewModel })
|
||||
{
|
||||
PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(pluginViewModel.PluginPair.Metadata.ID, pluginViewModel);
|
||||
priorityChangeWindow.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Proxy
|
||||
|
||||
private void OnTestProxyClick(object sender, RoutedEventArgs e)
|
||||
{ // TODO: change to command
|
||||
var msg = viewModel.TestProxy();
|
||||
MessageBox.Show(msg); // TODO: add message box service
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnCheckUpdates(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.UpdateApp(); // TODO: change to command
|
||||
}
|
||||
|
||||
private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
API.OpenUrl(e.Uri.AbsoluteUri);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
settings.SettingWindowState = WindowState;
|
||||
settings.SettingWindowTop = Top;
|
||||
settings.SettingWindowLeft = Left;
|
||||
viewModel.Save();
|
||||
API.SavePluginSettings();
|
||||
}
|
||||
|
||||
private void OnCloseExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OpenThemeFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PluginManager.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Themes));
|
||||
}
|
||||
|
||||
private void OpenSettingFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PluginManager.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Settings));
|
||||
}
|
||||
|
||||
private void OpenWelcomeWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var WelcomeWindow = new WelcomeWindow(settings);
|
||||
WelcomeWindow.ShowDialog();
|
||||
}
|
||||
private void OpenLogFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.OpenLogFolder();
|
||||
}
|
||||
private void ClearLogFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var confirmResult = MessageBox.Show(
|
||||
InternationalizationManager.Instance.GetTranslation("clearlogfolderMessage"),
|
||||
InternationalizationManager.Instance.GetTranslation("clearlogfolder"),
|
||||
MessageBoxButton.YesNo);
|
||||
|
||||
if (confirmResult == MessageBoxResult.Yes)
|
||||
{
|
||||
viewModel.ClearLogFolder();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExternalPluginInstallClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Button { DataContext: PluginStoreItemViewModel plugin } button)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (storeClickedButton != null)
|
||||
{
|
||||
FlyoutService.GetFlyout(storeClickedButton).Hide();
|
||||
}
|
||||
|
||||
viewModel.DisplayPluginQuery($"install {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
}
|
||||
|
||||
private void OnExternalPluginUninstallClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
var name = viewModel.SelectedPlugin.PluginPair.Metadata.Name;
|
||||
viewModel.DisplayPluginQuery($"uninstall {name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExternalPluginUninstallClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (storeClickedButton != null)
|
||||
{
|
||||
FlyoutService.GetFlyout(storeClickedButton).Hide();
|
||||
}
|
||||
|
||||
if (sender is Button { DataContext: PluginStoreItemViewModel plugin })
|
||||
viewModel.DisplayPluginQuery($"uninstall {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
|
||||
}
|
||||
|
||||
private void OnExternalPluginUpdateClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (storeClickedButton != null)
|
||||
{
|
||||
FlyoutService.GetFlyout(storeClickedButton).Hide();
|
||||
}
|
||||
if (sender is Button { DataContext: PluginStoreItemViewModel plugin })
|
||||
viewModel.DisplayPluginQuery($"update {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
|
||||
}
|
||||
|
||||
private void window_MouseDown(object sender, MouseButtonEventArgs e) /* for close hotkey popup */
|
||||
{
|
||||
if (Keyboard.FocusedElement is not TextBox textBox)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||
textBox.MoveFocus(tRequest);
|
||||
}
|
||||
|
||||
private void ColorSchemeSelectedIndexChanged(object sender, EventArgs e)
|
||||
=> ThemeManager.Current.ApplicationTheme = settings.ColorScheme switch
|
||||
{
|
||||
Constant.Light => ApplicationTheme.Light,
|
||||
Constant.Dark => ApplicationTheme.Dark,
|
||||
Constant.System => null,
|
||||
_ => ThemeManager.Current.ApplicationTheme
|
||||
};
|
||||
|
||||
/* Custom TitleBar */
|
||||
|
||||
private void OnMinimizeButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void OnMaximizeRestoreButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
|
||||
}
|
||||
|
||||
private void OnCloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private void RefreshMaximizeRestoreButton()
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
MaximizeButton.Visibility = Visibility.Collapsed;
|
||||
RestoreButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaximizeButton.Visibility = Visibility.Visible;
|
||||
RestoreButton.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
}
|
||||
|
||||
#region Shortcut
|
||||
|
||||
private void OnDeleteCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.DeleteSelectedCustomShortcut();
|
||||
}
|
||||
|
||||
private void OnEditCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (viewModel.EditSelectedCustomShortcut())
|
||||
{
|
||||
//customShortcutView.Items.Refresh(); Should Fix
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.AddCustomShortcut();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private CollectionView pluginListView;
|
||||
private CollectionView pluginStoreView;
|
||||
|
||||
//private bool PluginListFilter(object item)
|
||||
//{
|
||||
// if (string.IsNullOrEmpty(pluginFilterTxb.Text))
|
||||
// return true;
|
||||
// if (item is PluginViewModel model)
|
||||
// {
|
||||
// return StringMatcher.FuzzySearch(pluginFilterTxb.Text, model.PluginPair.Metadata.Name).IsSearchPrecisionScoreMet();
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//private bool PluginStoreFilter(object item)
|
||||
//{
|
||||
// if (string.IsNullOrEmpty(pluginStoreFilterTxb.Text))
|
||||
// return true;
|
||||
// if (item is PluginStoreItemViewModel model)
|
||||
// {
|
||||
// return StringMatcher.FuzzySearch(pluginStoreFilterTxb.Text, model.Name).IsSearchPrecisionScoreMet()
|
||||
// || StringMatcher.FuzzySearch(pluginStoreFilterTxb.Text, model.Description).IsSearchPrecisionScoreMet();
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
private string lastPluginListSearch = "";
|
||||
private string lastPluginStoreSearch = "";
|
||||
|
||||
//private void RefreshPluginListEventHandler(object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// if (pluginFilterTxb.Text != lastPluginListSearch)
|
||||
// {
|
||||
// lastPluginListSearch = pluginFilterTxb.Text;
|
||||
// pluginListView.Refresh();
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void RefreshPluginStoreEventHandler(object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// if (pluginStoreFilterTxb.Text != lastPluginStoreSearch)
|
||||
// {
|
||||
// lastPluginStoreSearch = pluginStoreFilterTxb.Text;
|
||||
// pluginStoreView.Refresh();
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void PluginFilterTxb_OnKeyDown(object sender, KeyEventArgs e)
|
||||
//{
|
||||
// if (e.Key == Key.Enter)
|
||||
// RefreshPluginListEventHandler(sender, e);
|
||||
//}
|
||||
|
||||
//private void PluginStoreFilterTxb_OnKeyDown(object sender, KeyEventArgs e)
|
||||
//{
|
||||
// if (e.Key == Key.Enter)
|
||||
// RefreshPluginStoreEventHandler(sender, e);
|
||||
//}
|
||||
|
||||
//private void OnPluginSettingKeydown(object sender, KeyEventArgs e)
|
||||
//{
|
||||
// if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control && e.Key == Key.F)
|
||||
// pluginFilterTxb.Focus();
|
||||
//}
|
||||
|
||||
//private void PluginStore_OnKeyDown(object sender, KeyEventArgs e)
|
||||
//{
|
||||
// if (e.Key == Key.F && (Keyboard.Modifiers & ModifierKeys.Control) != 0)
|
||||
// {
|
||||
// pluginStoreFilterTxb.Focus();
|
||||
// }
|
||||
//}
|
||||
|
||||
public void InitializePosition()
|
||||
{
|
||||
if (settings.SettingWindowTop >= 0 && settings.SettingWindowLeft >= 0)
|
||||
{
|
||||
Top = settings.SettingWindowTop;
|
||||
Left = settings.SettingWindowLeft;
|
||||
}
|
||||
else
|
||||
{
|
||||
Top = WindowTop();
|
||||
Left = WindowLeft();
|
||||
}
|
||||
WindowState = settings.SettingWindowState;
|
||||
}
|
||||
|
||||
public double WindowLeft()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
|
||||
var left = (dip2.X - this.ActualWidth) / 2 + dip1.X;
|
||||
return left;
|
||||
}
|
||||
|
||||
public double WindowTop()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
|
||||
var top = (dip2.Y - this.ActualHeight) / 2 + dip1.Y - 20;
|
||||
return top;
|
||||
}
|
||||
|
||||
private Button storeClickedButton;
|
||||
|
||||
private void StoreListItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Button button)
|
||||
return;
|
||||
|
||||
storeClickedButton = button;
|
||||
|
||||
var flyout = FlyoutService.GetFlyout(button);
|
||||
flyout.Closed += (_, _) =>
|
||||
{
|
||||
storeClickedButton = null;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//private void PluginStore_GotFocus(object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// Keyboard.Focus(pluginStoreFilterTxb);
|
||||
//}
|
||||
|
||||
//private void Plugin_GotFocus(object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// Keyboard.Focus(pluginFilterTxb);
|
||||
//}
|
||||
|
||||
/** For Navigation View **/
|
||||
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
|
||||
{
|
||||
if (args.IsSettingsSelected)
|
||||
{
|
||||
ContentFrame.Navigate(typeof(SettingsPaneGeneral));
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedItem = (NavigationViewItem)args.SelectedItem;
|
||||
if (selectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var pageType = selectedItem.Name switch
|
||||
{
|
||||
nameof(General) => typeof(SettingsPaneGeneral),
|
||||
nameof(Plugins) => typeof(SettingsPanePlugins),
|
||||
nameof(PluginStore) => typeof(SettingsPanePluginStore),
|
||||
nameof(Theme) => typeof(SettingsPaneTheme),
|
||||
nameof(Hotkey) => typeof(SettingsPaneHotkey),
|
||||
nameof(Proxy) => typeof(SettingsPaneProxy),
|
||||
nameof(About) => typeof(SettingsPaneAbout),
|
||||
_ => typeof(SettingsPaneGeneral)
|
||||
};
|
||||
ContentFrame.Navigate(pageType, new PaneData(settings, viewModel.Updater, viewModel.Portable));
|
||||
}
|
||||
}
|
||||
public record PaneData(Settings Settings, Updater Updater, IPortable Portable);
|
||||
_settings = viewModel.Settings;
|
||||
DataContext = viewModel;
|
||||
_viewModel = viewModel;
|
||||
_api = api;
|
||||
InitializePosition();
|
||||
InitializeComponent();
|
||||
NavView.SelectedItem = NavView.MenuItems[0]; /* Set First Page */
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
// Fix (workaround) for the window freezes after lock screen (Win+L)
|
||||
// https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf
|
||||
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
|
||||
HwndTarget hwndTarget = hwndSource.CompositionTarget;
|
||||
hwndTarget.RenderMode = RenderMode.Default;
|
||||
|
||||
InitializePosition();
|
||||
}
|
||||
|
||||
private void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
_settings.SettingWindowState = WindowState;
|
||||
_settings.SettingWindowTop = Top;
|
||||
_settings.SettingWindowLeft = Left;
|
||||
_viewModel.Save();
|
||||
_api.SavePluginSettings();
|
||||
}
|
||||
|
||||
private void OnCloseExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void window_MouseDown(object sender, MouseButtonEventArgs e) /* for close hotkey popup */
|
||||
{
|
||||
if (Keyboard.FocusedElement is not TextBox textBox)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||
textBox.MoveFocus(tRequest);
|
||||
}
|
||||
|
||||
/* Custom TitleBar */
|
||||
|
||||
private void OnMinimizeButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void OnMaximizeRestoreButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState switch
|
||||
{
|
||||
WindowState.Maximized => WindowState.Normal,
|
||||
_ => WindowState.Maximized
|
||||
};
|
||||
}
|
||||
|
||||
private void OnCloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void RefreshMaximizeRestoreButton()
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
MaximizeButton.Visibility = Visibility.Collapsed;
|
||||
RestoreButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaximizeButton.Visibility = Visibility.Visible;
|
||||
RestoreButton.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
}
|
||||
|
||||
private void InitializePosition()
|
||||
{
|
||||
if (_settings.SettingWindowTop >= 0 && _settings.SettingWindowLeft >= 0)
|
||||
{
|
||||
Top = _settings.SettingWindowTop;
|
||||
Left = _settings.SettingWindowLeft;
|
||||
}
|
||||
else
|
||||
{
|
||||
Top = WindowTop();
|
||||
Left = WindowLeft();
|
||||
}
|
||||
WindowState = _settings.SettingWindowState;
|
||||
}
|
||||
|
||||
private double WindowLeft()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
|
||||
var left = (dip2.X - this.ActualWidth) / 2 + dip1.X;
|
||||
return left;
|
||||
}
|
||||
|
||||
private double WindowTop()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
|
||||
var top = (dip2.Y - this.ActualHeight) / 2 + dip1.Y - 20;
|
||||
return top;
|
||||
}
|
||||
|
||||
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
|
||||
{
|
||||
var paneData = new PaneData(_settings, _viewModel.Updater, _viewModel.Portable);
|
||||
if (args.IsSettingsSelected)
|
||||
{
|
||||
ContentFrame.Navigate(typeof(SettingsPaneGeneral), paneData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedItem = (NavigationViewItem)args.SelectedItem;
|
||||
if (selectedItem == null) return;
|
||||
|
||||
var pageType = selectedItem.Name switch
|
||||
{
|
||||
nameof(General) => typeof(SettingsPaneGeneral),
|
||||
nameof(Plugins) => typeof(SettingsPanePlugins),
|
||||
nameof(PluginStore) => typeof(SettingsPanePluginStore),
|
||||
nameof(Theme) => typeof(SettingsPaneTheme),
|
||||
nameof(Hotkey) => typeof(SettingsPaneHotkey),
|
||||
nameof(Proxy) => typeof(SettingsPaneProxy),
|
||||
nameof(About) => typeof(SettingsPaneAbout),
|
||||
_ => typeof(SettingsPaneGeneral)
|
||||
};
|
||||
ContentFrame.Navigate(pageType, paneData);
|
||||
}
|
||||
}
|
||||
|
||||
public record PaneData(Settings Settings, Updater Updater, IPortable Portable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,11 @@ namespace Flow.Launcher.ViewModel
|
|||
public bool PluginState
|
||||
{
|
||||
get => !PluginPair.Metadata.Disabled;
|
||||
set => PluginPair.Metadata.Disabled = !value;
|
||||
set
|
||||
{
|
||||
PluginPair.Metadata.Disabled = !value;
|
||||
PluginSettingsObject.Disabled = !value;
|
||||
}
|
||||
}
|
||||
public bool IsExpanded
|
||||
{
|
||||
|
|
@ -96,6 +100,7 @@ namespace Flow.Launcher.ViewModel
|
|||
public string InitAndQueryTime => InternationalizationManager.Instance.GetTranslation("plugin_init_time") + " " + PluginPair.Metadata.InitTime + "ms, " + InternationalizationManager.Instance.GetTranslation("plugin_query_time") + " " + PluginPair.Metadata.AvgQueryTime + "ms";
|
||||
public string ActionKeywordsText => string.Join(Query.ActionKeywordSeparator, PluginPair.Metadata.ActionKeywords);
|
||||
public int Priority => PluginPair.Metadata.Priority;
|
||||
public Infrastructure.UserSettings.Plugin PluginSettingsObject { get; set; }
|
||||
|
||||
public void ChangeActionKeyword(string newActionKeyword, string oldActionKeyword)
|
||||
{
|
||||
|
|
@ -106,6 +111,7 @@ namespace Flow.Launcher.ViewModel
|
|||
public void ChangePriority(int newPriority)
|
||||
{
|
||||
PluginPair.Metadata.Priority = newPriority;
|
||||
PluginSettingsObject.Priority = newPriority;
|
||||
OnPropertyChanged(nameof(Priority));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,850 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Configuration;
|
||||
using Flow.Launcher.Core.ExternalPlugins;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Flow.Launcher.Infrastructure.Hotkey;
|
||||
using ModernWpf.Media.Animation;
|
||||
|
||||
namespace Flow.Launcher.ViewModel
|
||||
namespace Flow.Launcher.ViewModel;
|
||||
|
||||
public class SettingWindowViewModel : BaseModel
|
||||
{
|
||||
public partial class SettingWindowViewModel : BaseModel
|
||||
private readonly FlowLauncherJsonStorage<Settings> _storage;
|
||||
|
||||
public Updater Updater { get; }
|
||||
|
||||
public IPortable Portable { get; }
|
||||
|
||||
public Settings Settings { get; }
|
||||
|
||||
public SettingWindowViewModel(Updater updater, IPortable portable)
|
||||
{
|
||||
private readonly Updater _updater;
|
||||
private readonly IPortable _portable;
|
||||
private readonly FlowLauncherJsonStorage<Settings> _storage;
|
||||
|
||||
public Updater Updater => _updater;
|
||||
public IPortable Portable => _portable;
|
||||
|
||||
/* For Navigation View */
|
||||
private NavigationTransitionInfo _transitionInfo = new SlideNavigationTransitionInfo()
|
||||
{
|
||||
Effect = SlideNavigationTransitionEffect.FromBottom
|
||||
};
|
||||
|
||||
public SettingWindowViewModel(Updater updater, IPortable portable)
|
||||
{
|
||||
_updater = updater;
|
||||
_portable = portable;
|
||||
_storage = new FlowLauncherJsonStorage<Settings>();
|
||||
Settings = _storage.Load();
|
||||
Settings.PropertyChanged += (s, e) =>
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(Settings.ActivateTimes):
|
||||
OnPropertyChanged(nameof(ActivatedTimes));
|
||||
break;
|
||||
case nameof(Settings.WindowSize):
|
||||
OnPropertyChanged(nameof(WindowWidthSize));
|
||||
break;
|
||||
case nameof(Settings.UseDate):
|
||||
case nameof(Settings.DateFormat):
|
||||
OnPropertyChanged(nameof(DateText));
|
||||
break;
|
||||
case nameof(Settings.UseClock):
|
||||
case nameof(Settings.TimeFormat):
|
||||
OnPropertyChanged(nameof(ClockText));
|
||||
break;
|
||||
case nameof(Settings.Language):
|
||||
OnPropertyChanged(nameof(ClockText));
|
||||
OnPropertyChanged(nameof(DateText));
|
||||
OnPropertyChanged(nameof(AlwaysPreviewToolTip));
|
||||
break;
|
||||
case nameof(Settings.PreviewHotkey):
|
||||
OnPropertyChanged(nameof(AlwaysPreviewToolTip));
|
||||
break;
|
||||
case nameof(Settings.SoundVolume):
|
||||
OnPropertyChanged(nameof(SoundEffectVolume));
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void SetTogglingHotkey(HotkeyModel hotkey)
|
||||
{
|
||||
HotKeyMapper.SetHotkey(hotkey, HotKeyMapper.OnToggleHotkey);
|
||||
}
|
||||
|
||||
public Settings Settings { get; set; }
|
||||
|
||||
public async void UpdateApp()
|
||||
{
|
||||
await _updater.UpdateAppAsync(App.API, false);
|
||||
}
|
||||
|
||||
public bool AutoUpdates
|
||||
{
|
||||
get => Settings.AutoUpdates;
|
||||
set
|
||||
{
|
||||
Settings.AutoUpdates = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
UpdateApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CultureInfo Culture => CultureInfo.DefaultThreadCurrentCulture;
|
||||
private Internationalization _translater => InternationalizationManager.Instance;
|
||||
public string AlwaysPreviewToolTip =>
|
||||
string.Format(_translater.GetTranslation("AlwaysPreviewToolTip"), Settings.PreviewHotkey);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Save Flow settings. Plugins settings are not included.
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
foreach (var vm in PluginViewModels)
|
||||
{
|
||||
var id = vm.PluginPair.Metadata.ID;
|
||||
|
||||
Settings.PluginSettings.Plugins[id].Disabled = vm.PluginPair.Metadata.Disabled;
|
||||
Settings.PluginSettings.Plugins[id].Priority = vm.Priority;
|
||||
}
|
||||
|
||||
_storage.Save();
|
||||
}
|
||||
|
||||
public string GetFileFromDialog(string title, string filter = "")
|
||||
{
|
||||
var dlg = new System.Windows.Forms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
Multiselect = false,
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
Title = title,
|
||||
Filter = filter
|
||||
};
|
||||
|
||||
var result = dlg.ShowDialog();
|
||||
if (result == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
return dlg.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string TestProxy()
|
||||
{
|
||||
var proxyServer = Settings.Proxy.Server;
|
||||
var proxyUserName = Settings.Proxy.UserName;
|
||||
if (string.IsNullOrEmpty(proxyServer))
|
||||
{
|
||||
return InternationalizationManager.Instance.GetTranslation("serverCantBeEmpty");
|
||||
}
|
||||
|
||||
if (Settings.Proxy.Port <= 0)
|
||||
{
|
||||
return InternationalizationManager.Instance.GetTranslation("portCantBeEmpty");
|
||||
}
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_updater.GitHubRepository);
|
||||
|
||||
if (string.IsNullOrEmpty(proxyUserName) || string.IsNullOrEmpty(Settings.Proxy.Password))
|
||||
{
|
||||
request.Proxy = new WebProxy(proxyServer, Settings.Proxy.Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Proxy = new WebProxy(proxyServer, Settings.Proxy.Port)
|
||||
{
|
||||
Credentials = new NetworkCredential(proxyUserName, Settings.Proxy.Password)
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
return InternationalizationManager.Instance.GetTranslation("proxyIsCorrect");
|
||||
}
|
||||
else
|
||||
{
|
||||
return InternationalizationManager.Instance.GetTranslation("proxyConnectFailed");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return InternationalizationManager.Instance.GetTranslation("proxyConnectFailed");
|
||||
}
|
||||
}
|
||||
|
||||
#region plugin
|
||||
|
||||
public static string Plugin => @"https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest";
|
||||
public PluginViewModel SelectedPlugin { get; set; }
|
||||
|
||||
public IList<PluginViewModel> PluginViewModels
|
||||
{
|
||||
get => PluginManager.AllPlugins
|
||||
.OrderBy(x => x.Metadata.Disabled)
|
||||
.ThenBy(y => y.Metadata.Name)
|
||||
.Select(p => new PluginViewModel { PluginPair = p })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public IList<PluginStoreItemViewModel> ExternalPlugins
|
||||
{
|
||||
get
|
||||
{
|
||||
return LabelMaker(PluginsManifest.UserPlugins);
|
||||
}
|
||||
}
|
||||
|
||||
private IList<PluginStoreItemViewModel> LabelMaker(IList<UserPlugin> list)
|
||||
{
|
||||
return list.Select(p => new PluginStoreItemViewModel(p))
|
||||
.OrderByDescending(p => p.Category == PluginStoreItemViewModel.NewRelease)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.RecentlyUpdated)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.None)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.Installed)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public Control SettingProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
var settingProvider = SelectedPlugin.PluginPair.Plugin as ISettingProvider;
|
||||
if (settingProvider != null)
|
||||
{
|
||||
var control = settingProvider.CreateSettingPanel();
|
||||
control.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
control.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
return control;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Control();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task RefreshExternalPluginsAsync()
|
||||
{
|
||||
await PluginsManifest.UpdateManifestAsync();
|
||||
OnPropertyChanged(nameof(ExternalPlugins));
|
||||
}
|
||||
|
||||
|
||||
internal void DisplayPluginQuery(string queryToDisplay, PluginPair plugin, int actionKeywordPosition = 0)
|
||||
{
|
||||
var actionKeyword = plugin.Metadata.ActionKeywords.Count == 0
|
||||
? string.Empty
|
||||
: plugin.Metadata.ActionKeywords[actionKeywordPosition];
|
||||
|
||||
App.API.ChangeQuery($"{actionKeyword} {queryToDisplay}");
|
||||
App.API.ShowMainWindow();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region theme
|
||||
|
||||
public static string Theme => @"https://flowlauncher.com/docs/#/how-to-create-a-theme";
|
||||
public static string ThemeGallery => @"https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
|
||||
|
||||
public string SelectedTheme
|
||||
{
|
||||
get { return Settings.Theme; }
|
||||
set
|
||||
{
|
||||
ThemeManager.Instance.ChangeTheme(value);
|
||||
|
||||
if (ThemeManager.Instance.BlurEnabled && Settings.UseDropShadowEffect)
|
||||
DropShadowEffect = false;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Themes
|
||||
=> ThemeManager.Instance.LoadAvailableThemes().Select(Path.GetFileNameWithoutExtension).ToList();
|
||||
|
||||
public bool DropShadowEffect
|
||||
{
|
||||
get { return Settings.UseDropShadowEffect; }
|
||||
set
|
||||
{
|
||||
if (ThemeManager.Instance.BlurEnabled && value)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("shadowEffectNotAllowed"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value)
|
||||
{
|
||||
ThemeManager.Instance.AddDropShadowEffectToCurrentTheme();
|
||||
}
|
||||
else
|
||||
{
|
||||
ThemeManager.Instance.RemoveDropShadowEffectFromCurrentTheme();
|
||||
}
|
||||
|
||||
Settings.UseDropShadowEffect = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class ColorScheme
|
||||
{
|
||||
public string Display { get; set; }
|
||||
public ColorSchemes Value { get; set; }
|
||||
}
|
||||
|
||||
public List<ColorScheme> ColorSchemes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<ColorScheme> modes = new List<ColorScheme>();
|
||||
var enums = (ColorSchemes[])Enum.GetValues(typeof(ColorSchemes));
|
||||
foreach (var e in enums)
|
||||
{
|
||||
var key = $"ColorScheme{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new ColorScheme { Display = display, Value = e, };
|
||||
modes.Add(m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SearchWindowAlign
|
||||
{
|
||||
public string Display { get; set; }
|
||||
public SearchWindowAligns Value { get; set; }
|
||||
}
|
||||
|
||||
public List<SearchWindowAlign> SearchWindowAligns
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SearchWindowAlign> modes = new List<SearchWindowAlign>();
|
||||
var enums = (SearchWindowAligns[])Enum.GetValues(typeof(SearchWindowAligns));
|
||||
foreach (var e in enums)
|
||||
{
|
||||
var key = $"SearchWindowAlign{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new SearchWindowAlign { Display = display, Value = e, };
|
||||
modes.Add(m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
||||
public List<int> ScreenNumbers
|
||||
{
|
||||
get
|
||||
{
|
||||
var screens = System.Windows.Forms.Screen.AllScreens;
|
||||
var screenNumbers = new List<int>();
|
||||
for (int i = 1; i <= screens.Length; i++)
|
||||
{
|
||||
screenNumbers.Add(i);
|
||||
}
|
||||
|
||||
return screenNumbers;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> TimeFormatList { get; } = new()
|
||||
{
|
||||
"h:mm",
|
||||
"hh:mm",
|
||||
"H:mm",
|
||||
"HH:mm",
|
||||
"tt h:mm",
|
||||
"tt hh:mm",
|
||||
"h:mm tt",
|
||||
"hh:mm tt",
|
||||
"hh:mm:ss tt",
|
||||
"HH:mm:ss"
|
||||
};
|
||||
|
||||
public List<string> DateFormatList { get; } = new()
|
||||
{
|
||||
"MM'/'dd dddd",
|
||||
"MM'/'dd ddd",
|
||||
"MM'/'dd",
|
||||
"MM'-'dd",
|
||||
"MMMM', 'dd",
|
||||
"dd'/'MM",
|
||||
"dd'-'MM",
|
||||
"ddd MM'/'dd",
|
||||
"dddd MM'/'dd",
|
||||
"dddd",
|
||||
"ddd dd'/'MM",
|
||||
"dddd dd'/'MM",
|
||||
"dddd dd', 'MMMM",
|
||||
"dd', 'MMMM"
|
||||
};
|
||||
|
||||
public string TimeFormat
|
||||
{
|
||||
get => Settings.TimeFormat;
|
||||
set => Settings.TimeFormat = value;
|
||||
}
|
||||
|
||||
public string DateFormat
|
||||
{
|
||||
get => Settings.DateFormat;
|
||||
set => Settings.DateFormat = value;
|
||||
}
|
||||
|
||||
public string ClockText => DateTime.Now.ToString(TimeFormat, Culture);
|
||||
|
||||
public string DateText => DateTime.Now.ToString(DateFormat, Culture);
|
||||
|
||||
public double WindowWidthSize
|
||||
{
|
||||
get => Settings.WindowSize;
|
||||
set => Settings.WindowSize = value;
|
||||
}
|
||||
|
||||
public bool UseGlyphIcons
|
||||
{
|
||||
get => Settings.UseGlyphIcons;
|
||||
set => Settings.UseGlyphIcons = value;
|
||||
}
|
||||
|
||||
public bool UseAnimation
|
||||
{
|
||||
get => Settings.UseAnimation;
|
||||
set => Settings.UseAnimation = value;
|
||||
}
|
||||
|
||||
public class AnimationSpeed
|
||||
{
|
||||
public string Display { get; set; }
|
||||
public AnimationSpeeds Value { get; set; }
|
||||
}
|
||||
|
||||
public List<AnimationSpeed> AnimationSpeeds
|
||||
{
|
||||
get
|
||||
{
|
||||
List<AnimationSpeed> speeds = new List<AnimationSpeed>();
|
||||
var enums = (AnimationSpeeds[])Enum.GetValues(typeof(AnimationSpeeds));
|
||||
foreach (var e in enums)
|
||||
{
|
||||
var key = $"AnimationSpeed{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new AnimationSpeed { Display = display, Value = e, };
|
||||
speeds.Add(m);
|
||||
}
|
||||
|
||||
return speeds;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UseSound
|
||||
{
|
||||
get => Settings.UseSound;
|
||||
set => Settings.UseSound = value;
|
||||
}
|
||||
|
||||
public double SoundEffectVolume
|
||||
{
|
||||
get => Settings.SoundVolume;
|
||||
set => Settings.SoundVolume = value;
|
||||
}
|
||||
|
||||
public bool UseClock
|
||||
{
|
||||
get => Settings.UseClock;
|
||||
set => Settings.UseClock = value;
|
||||
}
|
||||
|
||||
public bool UseDate
|
||||
{
|
||||
get => Settings.UseDate;
|
||||
set => Settings.UseDate = value;
|
||||
}
|
||||
|
||||
public double SettingWindowWidth
|
||||
{
|
||||
get => Settings.SettingWindowWidth;
|
||||
set => Settings.SettingWindowWidth = value;
|
||||
}
|
||||
|
||||
public double SettingWindowHeight
|
||||
{
|
||||
get => Settings.SettingWindowHeight;
|
||||
set => Settings.SettingWindowHeight = value;
|
||||
}
|
||||
|
||||
public double SettingWindowTop
|
||||
{
|
||||
get => Settings.SettingWindowTop;
|
||||
set => Settings.SettingWindowTop = value;
|
||||
}
|
||||
|
||||
public double SettingWindowLeft
|
||||
{
|
||||
get => Settings.SettingWindowLeft;
|
||||
set => Settings.SettingWindowLeft = value;
|
||||
}
|
||||
|
||||
public Brush PreviewBackground
|
||||
{
|
||||
get
|
||||
{
|
||||
var wallpaper = WallpaperPathRetrieval.GetWallpaperPath();
|
||||
if (wallpaper != null && File.Exists(wallpaper))
|
||||
{
|
||||
var memStream = new MemoryStream(File.ReadAllBytes(wallpaper));
|
||||
var bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.StreamSource = memStream;
|
||||
bitmap.DecodePixelWidth = 800;
|
||||
bitmap.DecodePixelHeight = 600;
|
||||
bitmap.EndInit();
|
||||
var brush = new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
|
||||
return brush;
|
||||
}
|
||||
else
|
||||
{
|
||||
var wallpaperColor = WallpaperPathRetrieval.GetWallpaperColor();
|
||||
var brush = new SolidColorBrush(wallpaperColor);
|
||||
return brush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ResultsViewModel PreviewResults
|
||||
{
|
||||
get
|
||||
{
|
||||
var results = new List<Result>
|
||||
{
|
||||
new Result
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleExplorer"),
|
||||
SubTitle =
|
||||
InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
|
||||
IcoPath =
|
||||
Path.Combine(Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png")
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleWebSearch"),
|
||||
SubTitle =
|
||||
InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
|
||||
IcoPath =
|
||||
Path.Combine(Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProgram"),
|
||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProgram"),
|
||||
IcoPath =
|
||||
Path.Combine(Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.Program\Images\program.png")
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProcessKiller"),
|
||||
SubTitle =
|
||||
InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
|
||||
IcoPath = Path.Combine(Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
|
||||
}
|
||||
};
|
||||
var vm = new ResultsViewModel(Settings);
|
||||
vm.AddResults(results, "PREVIEW");
|
||||
return vm;
|
||||
}
|
||||
}
|
||||
|
||||
public FontFamily SelectedQueryBoxFont
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Fonts.SystemFontFamilies.Count(o =>
|
||||
o.FamilyNames.Values != null &&
|
||||
o.FamilyNames.Values.Contains(Settings.QueryBoxFont)) > 0)
|
||||
{
|
||||
var font = new FontFamily(Settings.QueryBoxFont);
|
||||
return font;
|
||||
}
|
||||
else
|
||||
{
|
||||
var font = new FontFamily("Segoe UI");
|
||||
return font;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.QueryBoxFont = value.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public FamilyTypeface SelectedQueryBoxFontFaces
|
||||
{
|
||||
get
|
||||
{
|
||||
var typeface = SyntaxSugars.CallOrRescueDefault(
|
||||
() => SelectedQueryBoxFont.ConvertFromInvariantStringsOrNormal(
|
||||
Settings.QueryBoxFontStyle,
|
||||
Settings.QueryBoxFontWeight,
|
||||
Settings.QueryBoxFontStretch
|
||||
));
|
||||
return typeface;
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.QueryBoxFontStretch = value.Stretch.ToString();
|
||||
Settings.QueryBoxFontWeight = value.Weight.ToString();
|
||||
Settings.QueryBoxFontStyle = value.Style.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public FontFamily SelectedResultFont
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Fonts.SystemFontFamilies.Count(o =>
|
||||
o.FamilyNames.Values != null &&
|
||||
o.FamilyNames.Values.Contains(Settings.ResultFont)) > 0)
|
||||
{
|
||||
var font = new FontFamily(Settings.ResultFont);
|
||||
return font;
|
||||
}
|
||||
else
|
||||
{
|
||||
var font = new FontFamily("Segoe UI");
|
||||
return font;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.ResultFont = value.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public FamilyTypeface SelectedResultFontFaces
|
||||
{
|
||||
get
|
||||
{
|
||||
var typeface = SyntaxSugars.CallOrRescueDefault(
|
||||
() => SelectedResultFont.ConvertFromInvariantStringsOrNormal(
|
||||
Settings.ResultFontStyle,
|
||||
Settings.ResultFontWeight,
|
||||
Settings.ResultFontStretch
|
||||
));
|
||||
return typeface;
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.ResultFontStretch = value.Stretch.ToString();
|
||||
Settings.ResultFontWeight = value.Weight.ToString();
|
||||
Settings.ResultFontStyle = value.Style.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public string ThemeImage => Constant.QueryTextBoxIconImagePath;
|
||||
|
||||
#endregion
|
||||
|
||||
#region hotkey
|
||||
|
||||
public CustomPluginHotkey SelectedCustomPluginHotkey { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region shortcut
|
||||
|
||||
public ObservableCollection<CustomShortcutModel> CustomShortcuts => Settings.CustomShortcuts;
|
||||
|
||||
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts => Settings.BuiltinShortcuts;
|
||||
|
||||
public CustomShortcutModel? SelectedCustomShortcut { get; set; }
|
||||
|
||||
public void DeleteSelectedCustomShortcut()
|
||||
{
|
||||
var item = SelectedCustomShortcut;
|
||||
if (item == null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return;
|
||||
}
|
||||
|
||||
string deleteWarning = string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("deleteCustomShortcutWarning"),
|
||||
item.Key, item.Value);
|
||||
if (MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
Settings.CustomShortcuts.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public bool EditSelectedCustomShortcut()
|
||||
{
|
||||
var item = SelectedCustomShortcut;
|
||||
if (item == null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return false;
|
||||
}
|
||||
|
||||
var shortcutSettingWindow = new CustomShortcutSetting(item.Key, item.Value, this);
|
||||
if (shortcutSettingWindow.ShowDialog() == true)
|
||||
{
|
||||
// Fix un-selectable shortcut item after the first selection
|
||||
// https://stackoverflow.com/questions/16789360/wpf-listbox-items-with-changing-hashcode
|
||||
SelectedCustomShortcut = null;
|
||||
item.Key = shortcutSettingWindow.Key;
|
||||
item.Value = shortcutSettingWindow.Value;
|
||||
SelectedCustomShortcut = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AddCustomShortcut()
|
||||
{
|
||||
var shortcutSettingWindow = new CustomShortcutSetting(this);
|
||||
if (shortcutSettingWindow.ShowDialog() == true)
|
||||
{
|
||||
var shortcut = new CustomShortcutModel(shortcutSettingWindow.Key, shortcutSettingWindow.Value);
|
||||
Settings.CustomShortcuts.Add(shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShortcutExists(string key)
|
||||
{
|
||||
return Settings.CustomShortcuts.Any(x => x.Key == key) || Settings.BuiltinShortcuts.Any(x => x.Key == key);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region about
|
||||
|
||||
public string Website => Constant.Website;
|
||||
public string SponsorPage => Constant.SponsorPage;
|
||||
public string ReleaseNotes => _updater.GitHubRepository + @"/releases/latest";
|
||||
public string Documentation => Constant.Documentation;
|
||||
public string Docs => Constant.Docs;
|
||||
public string Github => Constant.GitHub;
|
||||
|
||||
public string Version
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Constant.Version == "1.0.0")
|
||||
{
|
||||
return Constant.Dev;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Constant.Version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ActivatedTimes =>
|
||||
string.Format(_translater.GetTranslation("about_activate_times"), Settings.ActivateTimes);
|
||||
|
||||
public string CheckLogFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
var logFiles = GetLogFiles();
|
||||
long size = logFiles.Sum(file => file.Length);
|
||||
return string.Format("{0} ({1})", _translater.GetTranslation("clearlogfolder"),
|
||||
BytesToReadableString(size));
|
||||
}
|
||||
}
|
||||
|
||||
private static DirectoryInfo GetLogDir(string version = "")
|
||||
{
|
||||
return new DirectoryInfo(Path.Combine(DataLocation.DataDirectory(), Constant.Logs, version));
|
||||
}
|
||||
|
||||
private static List<FileInfo> GetLogFiles(string version = "")
|
||||
{
|
||||
return GetLogDir(version).EnumerateFiles("*", SearchOption.AllDirectories).ToList();
|
||||
}
|
||||
|
||||
internal void ClearLogFolder()
|
||||
{
|
||||
var logDirectory = GetLogDir();
|
||||
var logFiles = GetLogFiles();
|
||||
|
||||
logFiles.ForEach(f => f.Delete());
|
||||
|
||||
logDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
|
||||
.Where(dir => !Constant.Version.Equals(dir.Name))
|
||||
.ToList()
|
||||
.ForEach(dir => dir.Delete());
|
||||
|
||||
OnPropertyChanged(nameof(CheckLogFolder));
|
||||
}
|
||||
|
||||
internal void OpenLogFolder()
|
||||
{
|
||||
App.API.OpenDirectory(GetLogDir(Constant.Version).FullName);
|
||||
}
|
||||
|
||||
internal static string BytesToReadableString(long bytes)
|
||||
{
|
||||
const int scale = 1024;
|
||||
string[] orders = new string[] { "GB", "MB", "KB", "B" };
|
||||
long max = (long)Math.Pow(scale, orders.Length - 1);
|
||||
|
||||
foreach (string order in orders)
|
||||
{
|
||||
if (bytes > max)
|
||||
return string.Format("{0:##.##} {1}", decimal.Divide(bytes, max), order);
|
||||
|
||||
max /= scale;
|
||||
}
|
||||
|
||||
return "0 B";
|
||||
}
|
||||
|
||||
#endregion
|
||||
_storage = new FlowLauncherJsonStorage<Settings>();
|
||||
|
||||
Updater = updater;
|
||||
Portable = portable;
|
||||
Settings = _storage.Load();
|
||||
}
|
||||
|
||||
public async void UpdateApp()
|
||||
{
|
||||
await Updater.UpdateAppAsync(App.API, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Save Flow settings. Plugins settings are not included.
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
_storage.Save();
|
||||
}
|
||||
|
||||
public double SettingWindowWidth
|
||||
{
|
||||
get => Settings.SettingWindowWidth;
|
||||
set => Settings.SettingWindowWidth = value;
|
||||
}
|
||||
|
||||
public double SettingWindowHeight
|
||||
{
|
||||
get => Settings.SettingWindowHeight;
|
||||
set => Settings.SettingWindowHeight = value;
|
||||
}
|
||||
|
||||
public double SettingWindowTop
|
||||
{
|
||||
get => Settings.SettingWindowTop;
|
||||
set => Settings.SettingWindowTop = value;
|
||||
}
|
||||
|
||||
public double SettingWindowLeft
|
||||
{
|
||||
get => Settings.SettingWindowLeft;
|
||||
set => Settings.SettingWindowLeft = value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue