mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
fix(explorer): complete Avalonia migration and fix action keyword crashes
- Remove WPF views (ActionKeywordSetting, ExplorerSettings, PreviewPanel, QuickAccessLinkSettings) - Fix NullReferenceException in ActionKeywordModel by initializing settings - Fix (false,false) crash case in EditActionKeywordAsync - Add null-safe dialog patterns for owner window - Move Focus() to OnOpened for reliable control attachment - Add using for Avalonia PreviewPanel namespace in ResultManager - Update Main.cs to use AvaloniaControl return type
This commit is contained in:
parent
e337f9e6c5
commit
0681332238
28 changed files with 613 additions and 1925 deletions
19
Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/codemap.md
Normal file
19
Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/codemap.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<Nullable>warnings</Nullable>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
19
Plugins/Flow.Launcher.Plugin.Explorer/Helper/codemap.md
Normal file
19
Plugins/Flow.Launcher.Plugin.Explorer/Helper/codemap.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Helper/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -2,16 +2,15 @@ using Flow.Launcher.Plugin.Explorer.Helper;
|
|||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything;
|
||||
using Flow.Launcher.Plugin.Explorer.ViewModels;
|
||||
using Flow.Launcher.Plugin.Explorer.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using Flow.Launcher.Plugin.Explorer.Exceptions;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
using System.Windows.Controls;
|
||||
using AvaloniaControl = Avalonia.Controls.Control;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer
|
||||
|
|
@ -32,7 +31,7 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
|
||||
public Control CreateSettingPanel()
|
||||
{
|
||||
return new ExplorerSettings(viewModel);
|
||||
throw new NotSupportedException("WPF settings are no longer supported. Use Avalonia version instead.");
|
||||
}
|
||||
|
||||
public AvaloniaControl CreateSettingPanelAvalonia()
|
||||
|
|
@ -45,6 +44,7 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
Context = context;
|
||||
|
||||
Settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
ActionKeywordModel.Init(Settings);
|
||||
FillQuickAccessLinkNames();
|
||||
|
||||
viewModel = new SettingsViewModel(context, Settings);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything;
|
||||
using Flow.Launcher.Plugin.Explorer.Views;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
using Peter;
|
||||
|
|
@ -106,7 +105,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
{
|
||||
FilePath = path,
|
||||
},
|
||||
PreviewPanel = new Lazy<UserControl>(() => new PreviewPanel(Settings, path, ResultType.Folder)),
|
||||
Action = c =>
|
||||
{
|
||||
if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt)
|
||||
|
|
@ -305,7 +303,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
TitleHighlightData = Context.API.FuzzySearch(query.Search, title).MatchData,
|
||||
Score = score,
|
||||
CopyText = filePath,
|
||||
PreviewPanel = new Lazy<UserControl>(() => new PreviewPanel(Settings, filePath, ResultType.File)),
|
||||
Action = c =>
|
||||
{
|
||||
if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt)
|
||||
|
|
@ -371,9 +368,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
{
|
||||
try
|
||||
{
|
||||
var fileSize = PreviewPanel.GetFileSize(filePath);
|
||||
var fileCreatedAt = PreviewPanel.GetFileCreatedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
var fileModifiedAt = PreviewPanel.GetFileLastModifiedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
var fileSize = Views.Avalonia.PreviewPanel.GetFileSize(filePath);
|
||||
var fileCreatedAt = Views.Avalonia.PreviewPanel.GetFileCreatedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
var fileModifiedAt = Views.Avalonia.PreviewPanel.GetFileLastModifiedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
return Localize.plugin_explorer_plugin_tooltip_more_info(filePath, fileSize, fileCreatedAt, fileModifiedAt, Environment.NewLine);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -387,9 +384,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
{
|
||||
try
|
||||
{
|
||||
var folderSize = PreviewPanel.GetFolderSize(folderPath);
|
||||
var folderCreatedAt = PreviewPanel.GetFolderCreatedAt(folderPath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
var folderModifiedAt = PreviewPanel.GetFolderLastModifiedAt(folderPath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
var folderSize = Views.Avalonia.PreviewPanel.GetFolderSize(folderPath);
|
||||
var folderCreatedAt = Views.Avalonia.PreviewPanel.GetFolderCreatedAt(folderPath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
var folderModifiedAt = Views.Avalonia.PreviewPanel.GetFolderLastModifiedAt(folderPath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
return Localize.plugin_explorer_plugin_tooltip_more_info(folderPath, folderSize, folderCreatedAt, folderModifiedAt, Environment.NewLine);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
19
Plugins/Flow.Launcher.Plugin.Explorer/Search/codemap.md
Normal file
19
Plugins/Flow.Launcher.Plugin.Explorer/Search/codemap.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Search/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -8,26 +8,36 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Plugin.Explorer.Helper;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
||||
using Flow.Launcher.Plugin.Explorer.Views;
|
||||
using Flow.Launcher.Plugin.Explorer.Views.Avalonia;
|
||||
using AvaloniaApp = Avalonia.Application;
|
||||
using AvaloniaQuickAccessLinkSettings = Flow.Launcher.Plugin.Explorer.Views.Avalonia.QuickAccessLinkSettings;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
||||
{
|
||||
public partial class SettingsViewModel : BaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Detects if we're running in an Avalonia application context
|
||||
/// Gets the current active Avalonia window to use as dialog owner
|
||||
/// </summary>
|
||||
private static bool IsAvalonia => AvaloniaApp.Current != null;
|
||||
|
||||
private static global::Avalonia.Controls.Window? GetAvaloniaOwnerWindow()
|
||||
{
|
||||
if (AvaloniaApp.Current?.ApplicationLifetime is not global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop)
|
||||
return null;
|
||||
|
||||
// First try to find an active window
|
||||
var activeWindow = desktop.Windows.FirstOrDefault(w => w.IsActive);
|
||||
if (activeWindow != null)
|
||||
return activeWindow;
|
||||
|
||||
// Fall back to main window
|
||||
return desktop.MainWindow;
|
||||
}
|
||||
|
||||
public Settings Settings { get; set; }
|
||||
|
||||
internal PluginInitContext Context { get; set; }
|
||||
|
|
@ -41,6 +51,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Context = context;
|
||||
Settings = settings;
|
||||
|
||||
ActionKeywordModel.Init(settings);
|
||||
InitializeEngineSelection();
|
||||
InitializeActionKeywordModels();
|
||||
}
|
||||
|
|
@ -162,7 +173,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Settings.ShowCreatedDateInPreviewPanel = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(ShowPreviewPanelDateTimeChoices));
|
||||
OnPropertyChanged(nameof(PreviewPanelDateTimeChoicesVisibility));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +184,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Settings.ShowModifiedDateInPreviewPanel = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(ShowPreviewPanelDateTimeChoices));
|
||||
OnPropertyChanged(nameof(PreviewPanelDateTimeChoicesVisibility));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +195,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Settings.ShowFileAgeInPreviewPanel = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(ShowPreviewPanelDateTimeChoices));
|
||||
OnPropertyChanged(nameof(PreviewPanelDateTimeChoicesVisibility));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,9 +225,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
|
||||
public bool ShowPreviewPanelDateTimeChoices => ShowCreatedDateInPreviewPanel || ShowModifiedDateInPreviewPanel;
|
||||
|
||||
public Visibility PreviewPanelDateTimeChoicesVisibility => ShowCreatedDateInPreviewPanel || ShowModifiedDateInPreviewPanel ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
|
||||
public List<string> TimeFormatList { get; } = new()
|
||||
{
|
||||
"h:mm",
|
||||
|
|
@ -296,7 +301,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
public ActionKeywordModel? SelectedActionKeyword { get; set; }
|
||||
|
||||
[RelayCommand]
|
||||
private void EditActionKeyword(object obj)
|
||||
private async Task EditActionKeywordAsync(object obj)
|
||||
{
|
||||
if (SelectedActionKeyword is not { } actionKeyword)
|
||||
{
|
||||
|
|
@ -304,14 +309,32 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
return;
|
||||
}
|
||||
|
||||
var actionKeywordWindow = new ActionKeywordSetting(actionKeyword);
|
||||
var dialog = new ActionKeywordSetting(actionKeyword);
|
||||
var ownerWindow = GetAvaloniaOwnerWindow();
|
||||
bool dialogResult;
|
||||
if (ownerWindow != null)
|
||||
{
|
||||
dialogResult = await dialog.ShowDialog<bool?>(ownerWindow) ?? false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: show as normal window if owner is not available
|
||||
dialog.Show();
|
||||
var tcs = new TaskCompletionSource<bool?>();
|
||||
dialog.Closed += (_, _) => tcs.TrySetResult(true);
|
||||
await tcs.Task;
|
||||
dialogResult = true;
|
||||
}
|
||||
|
||||
if (!(actionKeywordWindow.ShowDialog() ?? false))
|
||||
if (!dialogResult)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (actionKeyword.Enabled, actionKeywordWindow.KeywordEnabled)
|
||||
var newKeyword = dialog.ActionKeyword;
|
||||
var newEnabled = dialog.KeywordEnabled;
|
||||
|
||||
switch (actionKeyword.Enabled, newEnabled)
|
||||
{
|
||||
case (true, false):
|
||||
Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
|
|
@ -319,18 +342,16 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
case (true, true):
|
||||
// same keyword will have dialog result false
|
||||
Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword);
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, newKeyword);
|
||||
break;
|
||||
case (false, true):
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword);
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, newKeyword);
|
||||
break;
|
||||
case (false, false):
|
||||
throw new ArgumentException(
|
||||
$"Both false in {nameof(actionKeyword)}.{nameof(actionKeyword.Enabled)} and {nameof(actionKeywordWindow)}.{nameof(actionKeywordWindow.KeywordEnabled)} should suggest that the ShowDialog() result is false");
|
||||
break;
|
||||
}
|
||||
|
||||
(actionKeyword.Keyword, actionKeyword.Enabled) = (actionKeywordWindow.ActionKeyword, actionKeywordWindow.KeywordEnabled);
|
||||
|
||||
(actionKeyword.Keyword, actionKeyword.Enabled) = (newKeyword, newEnabled);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
@ -352,7 +373,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void EditIndexSearchExcludePaths()
|
||||
private async Task EditIndexSearchExcludePathsAsync()
|
||||
{
|
||||
var selectedLink = SelectedIndexSearchExcludedPath;
|
||||
var collection = Settings.IndexSearchExcludedSubdirectoryPaths;
|
||||
|
|
@ -363,7 +384,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
return;
|
||||
}
|
||||
|
||||
var path = PromptUserSelectPath(selectedLink.Type,
|
||||
var path = await PromptUserSelectPathAsync(selectedLink.Type,
|
||||
selectedLink.Type == ResultType.Folder
|
||||
? selectedLink.Path
|
||||
: Path.GetDirectoryName(selectedLink.Path));
|
||||
|
|
@ -380,21 +401,21 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void AddIndexSearchExcludePaths()
|
||||
private async Task AddIndexSearchExcludePathsAsync()
|
||||
{
|
||||
var container = Settings.IndexSearchExcludedSubdirectoryPaths;
|
||||
|
||||
if (container is null) return;
|
||||
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
var path = await PromptUserSelectFolderAsync();
|
||||
|
||||
if (path is null)
|
||||
return;
|
||||
|
||||
var newAccessLink = new AccessLink
|
||||
{
|
||||
Name = folderBrowserDialog.SelectedPath.GetPathName(),
|
||||
Path = folderBrowserDialog.SelectedPath
|
||||
Name = path.GetPathName(),
|
||||
Path = path
|
||||
};
|
||||
|
||||
container.Add(newAccessLink);
|
||||
|
|
@ -413,50 +434,52 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
return;
|
||||
}
|
||||
|
||||
if (IsAvalonia)
|
||||
var dialog = new QuickAccessLinkSettings(collection, selectedLink);
|
||||
var ownerWindow = GetAvaloniaOwnerWindow();
|
||||
bool dialogResult;
|
||||
if (ownerWindow != null)
|
||||
{
|
||||
var dialog = new AvaloniaQuickAccessLinkSettings(collection, selectedLink);
|
||||
var mainWindow = AvaloniaApp.Current?.ApplicationLifetime is global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop
|
||||
? desktop.MainWindow
|
||||
: null;
|
||||
var result = await dialog.ShowDialog<bool?>(mainWindow!);
|
||||
if (result == true)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
dialogResult = await dialog.ShowDialog<bool?>(ownerWindow) ?? false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var quickAccessLinkSettings = new QuickAccessLinkSettings(collection, SelectedQuickAccessLink);
|
||||
if (quickAccessLinkSettings.ShowDialog() == true)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
// Fallback: show as normal window if owner is not available
|
||||
dialog.Show();
|
||||
var tcs = new TaskCompletionSource<bool?>();
|
||||
dialog.Closed += (_, _) => tcs.TrySetResult(true);
|
||||
await tcs.Task;
|
||||
dialogResult = true;
|
||||
}
|
||||
|
||||
if (dialogResult)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[RelayCommand]
|
||||
private async Task AddQuickAccessLinkAsync()
|
||||
{
|
||||
if (IsAvalonia)
|
||||
var dialog = new QuickAccessLinkSettings(Settings.QuickAccessLinks);
|
||||
var ownerWindow = GetAvaloniaOwnerWindow();
|
||||
bool dialogResult;
|
||||
if (ownerWindow != null)
|
||||
{
|
||||
var dialog = new AvaloniaQuickAccessLinkSettings(Settings.QuickAccessLinks);
|
||||
var mainWindow = AvaloniaApp.Current?.ApplicationLifetime is global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop
|
||||
? desktop.MainWindow
|
||||
: null;
|
||||
var result = await dialog.ShowDialog<bool?>(mainWindow!);
|
||||
if (result == true)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
dialogResult = await dialog.ShowDialog<bool?>(ownerWindow) ?? false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var quickAccessLinkSettings = new QuickAccessLinkSettings(Settings.QuickAccessLinks);
|
||||
if (quickAccessLinkSettings.ShowDialog() == true)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
// Fallback: show as normal window if owner is not available
|
||||
dialog.Show();
|
||||
var tcs = new TaskCompletionSource<bool?>();
|
||||
dialog.Closed += (_, _) => tcs.TrySetResult(true);
|
||||
await tcs.Task;
|
||||
dialogResult = true;
|
||||
}
|
||||
|
||||
if (dialogResult)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -492,45 +515,60 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
Save();
|
||||
}
|
||||
|
||||
|
||||
private void ShowUnselectedMessage()
|
||||
{
|
||||
var warning = Localize.plugin_explorer_make_selection_warning();
|
||||
Context.API.ShowMsgBox(warning);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static string? PromptUserSelectPath(ResultType type, string? initialDirectory = null)
|
||||
private static async Task<string?> PromptUserSelectPathAsync(ResultType type, string? initialDirectory = null)
|
||||
{
|
||||
string? path = null;
|
||||
|
||||
if (type is ResultType.Folder)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
|
||||
if (initialDirectory is not null)
|
||||
folderBrowserDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return path;
|
||||
|
||||
path = folderBrowserDialog.SelectedPath;
|
||||
path = await PromptUserSelectFolderAsync(initialDirectory);
|
||||
}
|
||||
else if (type is ResultType.File)
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog();
|
||||
if (initialDirectory is not null)
|
||||
openFileDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK)
|
||||
return path;
|
||||
|
||||
path = openFileDialog.FileName;
|
||||
path = await PromptUserSelectFileAsync(initialDirectory);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private static async Task<string?> PromptUserSelectFolderAsync(string? initialDirectory = null)
|
||||
{
|
||||
var mainWindow = AvaloniaApp.Current?.ApplicationLifetime is global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop
|
||||
? desktop.MainWindow
|
||||
: null;
|
||||
|
||||
if (mainWindow == null) return null;
|
||||
|
||||
var folders = await mainWindow.StorageProvider.OpenFolderPickerAsync(new global::Avalonia.Platform.Storage.FolderPickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false
|
||||
});
|
||||
|
||||
return folders.Count > 0 ? folders[0].Path.LocalPath : null;
|
||||
}
|
||||
|
||||
private static async Task<string?> PromptUserSelectFileAsync(string? initialDirectory = null)
|
||||
{
|
||||
var mainWindow = AvaloniaApp.Current?.ApplicationLifetime is global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop
|
||||
? desktop.MainWindow
|
||||
: null;
|
||||
|
||||
if (mainWindow == null) return null;
|
||||
|
||||
var files = await mainWindow.StorageProvider.OpenFilePickerAsync(new global::Avalonia.Platform.Storage.FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false
|
||||
});
|
||||
|
||||
return files.Count > 0 ? files[0].Path.LocalPath : null;
|
||||
}
|
||||
|
||||
internal static void OpenWindowsIndexingOptions()
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
|
|
@ -544,9 +582,9 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenFileEditorPath()
|
||||
private async Task OpenFileEditorPathAsync()
|
||||
{
|
||||
var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
|
||||
var path = await PromptUserSelectFileAsync(Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
|
||||
if (path is null)
|
||||
return;
|
||||
|
||||
|
|
@ -554,9 +592,9 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenFolderEditorPath()
|
||||
private async Task OpenFolderEditorPathAsync()
|
||||
{
|
||||
var path = PromptUserSelectPath(ResultType.File, Settings.FolderEditorPath != null ? Path.GetDirectoryName(Settings.FolderEditorPath) : null);
|
||||
var path = await PromptUserSelectFolderAsync(Settings.FolderEditorPath != null ? Path.GetDirectoryName(Settings.FolderEditorPath) : null);
|
||||
if (path is null)
|
||||
return;
|
||||
|
||||
|
|
@ -564,9 +602,9 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenShellPath()
|
||||
private async Task OpenShellPathAsync()
|
||||
{
|
||||
var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
|
||||
var path = await PromptUserSelectFileAsync(Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
|
||||
if (path is null)
|
||||
return;
|
||||
|
||||
|
|
@ -628,6 +666,8 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Everything FastSortWarning
|
||||
|
||||
public List<EverythingSortOptionLocalized> AllEverythingSortOptions { get; } = EverythingSortOptionLocalized.GetValues();
|
||||
|
|
@ -646,23 +686,23 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
public Visibility FastSortWarningVisibility
|
||||
public bool FastSortWarningVisibility
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return EverythingApi.IsFastSortOption(Settings.SortOption) ? Visibility.Collapsed : Visibility.Visible;
|
||||
return !EverythingApi.IsFastSortOption(Settings.SortOption);
|
||||
}
|
||||
catch (IPCErrorException)
|
||||
{
|
||||
// this error occurs if the Everything service is not running, in this instance show the warning and
|
||||
// update the message to let user know in the settings panel.
|
||||
return Visibility.Visible;
|
||||
return true;
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/codemap.md
Normal file
19
Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/codemap.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
<Window
|
||||
x:Class="Flow.Launcher.Plugin.Explorer.Views.ActionKeywordSetting"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="{DynamicResource plugin_explorer_manageactionkeywords_header}"
|
||||
Width="Auto"
|
||||
Height="255"
|
||||
Background="{DynamicResource PopuBGColor}"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||
Foreground="{DynamicResource PopupTextColor}"
|
||||
ResizeMode="NoResize"
|
||||
SizeToContent="Width"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<WindowChrome.WindowChrome>
|
||||
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
|
||||
</WindowChrome.WindowChrome>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="80" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0">
|
||||
<StackPanel>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button
|
||||
Grid.Column="4"
|
||||
Click="BtnCancel_OnClick"
|
||||
Style="{StaticResource TitleBarCloseButtonStyle}">
|
||||
<Path
|
||||
Width="46"
|
||||
Height="32"
|
||||
Data="M 18,11 27,20 M 18,20 27,11"
|
||||
Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
StrokeThickness="1">
|
||||
<Path.Style>
|
||||
<Style TargetType="Path">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="False">
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Path.Style>
|
||||
</Path>
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="26 0 26 0">
|
||||
<StackPanel Margin="0 0 0 12">
|
||||
<TextBlock
|
||||
Margin="0 0 0 0"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Text="{DynamicResource plugin_explorer_manageactionkeywords_header}"
|
||||
TextAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="0 10 0 0" Orientation="Horizontal">
|
||||
<TextBlock
|
||||
MinWidth="150"
|
||||
Margin="0 10 15 10"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource plugin_explorer_actionkeyword_current}" />
|
||||
<TextBox
|
||||
Name="TxtCurrentActionKeyword"
|
||||
Width="135"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
DataObject.Pasting="TextBox_Pasting"
|
||||
PreviewKeyDown="TxtCurrentActionKeyword_OnKeyDown"
|
||||
Text="{Binding ActionKeyword}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0 10 0 15" Orientation="Horizontal">
|
||||
<TextBlock
|
||||
MinWidth="150"
|
||||
Margin="0 0 18 0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource plugin_explorer_actionkeyword_enabled}" />
|
||||
<CheckBox
|
||||
Name="ChkActionKeywordEnabled"
|
||||
Width="auto"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding KeywordEnabled, Mode=TwoWay}"
|
||||
ToolTip="{DynamicResource plugin_explorer_actionkeyword_enabled_tooltip}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Background="{DynamicResource PopupButtonAreaBGColor}"
|
||||
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||
BorderThickness="0 1 0 0">
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="145"
|
||||
Height="30"
|
||||
Margin="0 0 5 0"
|
||||
Click="BtnCancel_OnClick"
|
||||
Content="{DynamicResource cancel}" />
|
||||
<Button
|
||||
Name="DownButton"
|
||||
Width="145"
|
||||
Height="30"
|
||||
Margin="5 0 0 0"
|
||||
Click="OnDoneButtonClick"
|
||||
Style="{StaticResource AccentButtonStyle}">
|
||||
<TextBlock x:Name="lblAdd" Text="{DynamicResource plugin_explorer_actionkeyword_done}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Flow.Launcher.Plugin.Explorer.ViewModels;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views
|
||||
{
|
||||
[INotifyPropertyChanged]
|
||||
public partial class ActionKeywordSetting
|
||||
{
|
||||
private ActionKeywordModel CurrentActionKeyword { get; }
|
||||
|
||||
public string ActionKeyword
|
||||
{
|
||||
get => actionKeyword;
|
||||
set
|
||||
{
|
||||
// Set Enable to be true if user change ActionKeyword
|
||||
KeywordEnabled = true;
|
||||
_ = SetProperty(ref actionKeyword, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool KeywordEnabled
|
||||
{
|
||||
get => _keywordEnabled;
|
||||
set => _ = SetProperty(ref _keywordEnabled, value);
|
||||
}
|
||||
|
||||
private string actionKeyword;
|
||||
private bool _keywordEnabled;
|
||||
|
||||
public ActionKeywordSetting(ActionKeywordModel selectedActionKeyword)
|
||||
{
|
||||
CurrentActionKeyword = selectedActionKeyword;
|
||||
ActionKeyword = selectedActionKeyword.Keyword;
|
||||
KeywordEnabled = selectedActionKeyword.Enabled;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
TxtCurrentActionKeyword.Focus();
|
||||
}
|
||||
|
||||
private void OnDoneButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ActionKeyword))
|
||||
ActionKeyword = Query.GlobalPluginWildcardSign;
|
||||
|
||||
if (CurrentActionKeyword.Keyword == ActionKeyword && CurrentActionKeyword.Enabled == KeywordEnabled)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ActionKeyword == Query.GlobalPluginWildcardSign)
|
||||
switch (CurrentActionKeyword.KeywordProperty, KeywordEnabled)
|
||||
{
|
||||
case (Settings.ActionKeyword.FileContentSearchActionKeyword, true):
|
||||
Main.Context.API.ShowMsgBox(Localize.plugin_explorer_globalActionKeywordInvalid());
|
||||
return;
|
||||
case (Settings.ActionKeyword.QuickAccessActionKeyword, true):
|
||||
Main.Context.API.ShowMsgBox(Localize.plugin_explorer_quickaccess_globalActionKeywordInvalid());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!KeywordEnabled || !Main.Context.API.ActionKeywordAssigned(ActionKeyword))
|
||||
{
|
||||
DialogResult = true;
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
// The keyword is not valid, so show message
|
||||
Main.Context.API.ShowMsgBox(Localize.plugin_explorer_new_action_keyword_assigned());
|
||||
}
|
||||
|
||||
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void TxtCurrentActionKeyword_OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
DownButton.Focus();
|
||||
OnDoneButtonClick(sender, e);
|
||||
e.Handled = true;
|
||||
}
|
||||
if (e.Key == Key.Space)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
|
||||
{
|
||||
if (e.DataObject.GetDataPresent(DataFormats.Text))
|
||||
{
|
||||
string text = e.DataObject.GetData(DataFormats.Text) as string;
|
||||
if (!string.IsNullOrEmpty(text) && text.Any(char.IsWhiteSpace))
|
||||
{
|
||||
e.CancelCommand();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e.CancelCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
Title="{DynamicResource plugin_explorer_manageactionkeywords_header}"
|
||||
Width="400"
|
||||
Height="255"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
CanResize="False">
|
||||
|
||||
<Grid RowDefinitions="*,80">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
|
@ -49,7 +50,11 @@ public partial class ActionKeywordSetting : Window, INotifyPropertyChanged
|
|||
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
protected override void OnOpened(EventArgs e)
|
||||
{
|
||||
base.OnOpened(e);
|
||||
this.FindControl<TextBox>("TxtCurrentActionKeyword")?.Focus();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="400"
|
||||
x:Class="Flow.Launcher.Plugin.Explorer.Views.Avalonia.PreviewPanel">
|
||||
|
||||
<Grid x:Name="PreviewGrid" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Preview Image and File Name -->
|
||||
<Grid Grid.Row="0" VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition MinHeight="96" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Image Grid.Row="0"
|
||||
MaxWidth="96"
|
||||
MaxHeight="96"
|
||||
Margin="5,12,8,0"
|
||||
Source="{Binding PreviewImage}" />
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<TextBlock Margin="5,6,5,16"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding FileName}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
FontWeight="SemiBold" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- File Info -->
|
||||
<StackPanel Grid.Row="1">
|
||||
<Rectangle x:Name="PreviewSep"
|
||||
Height="1"
|
||||
Margin="0,0,5,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Fill="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
|
||||
|
||||
<TextBlock Margin="5,8,8,8"
|
||||
Text="{Binding FilePath}"
|
||||
TextWrapping="Wrap"
|
||||
Opacity="0.8" />
|
||||
|
||||
<Rectangle Height="1"
|
||||
Margin="0,0,5,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Fill="{Binding ElementName=PreviewSep, Path=Fill}"
|
||||
IsVisible="{Binding FileInfoVisibility}" />
|
||||
|
||||
<Grid Margin="0,10,0,0" IsVisible="{Binding FileInfoVisibility}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- File Size -->
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Text="{DynamicResource FileSize}"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding FileSizeVisibility}" />
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,13,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding FileSize}"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding FileSizeVisibility}" />
|
||||
|
||||
<!-- Created Date -->
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="5,0,8,0"
|
||||
VerticalAlignment="Top"
|
||||
Text="{DynamicResource Created}"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding CreatedAtVisibility}" />
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,13,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding CreatedAt}"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding CreatedAtVisibility}" />
|
||||
|
||||
<!-- Last Modified Date -->
|
||||
<TextBlock Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="5,0,8,0"
|
||||
VerticalAlignment="Top"
|
||||
Text="{DynamicResource LastModified}"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding LastModifiedAtVisibility}" />
|
||||
<TextBlock Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,13,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding LastModifiedAt}"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding LastModifiedAtVisibility}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -1,59 +1,93 @@
|
|||
using System;
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views;
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views.Avalonia;
|
||||
|
||||
#nullable enable
|
||||
|
||||
[INotifyPropertyChanged]
|
||||
public partial class PreviewPanel : UserControl
|
||||
public partial class PreviewPanel : UserControl, INotifyPropertyChanged
|
||||
{
|
||||
private static readonly string ClassName = nameof(PreviewPanel);
|
||||
|
||||
public string FilePath { get; }
|
||||
public string FileName { get; }
|
||||
|
||||
[ObservableProperty]
|
||||
private string _fileSize = Localize.plugin_explorer_plugin_tooltip_more_info_unknown();
|
||||
|
||||
[ObservableProperty]
|
||||
private string _createdAt = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _lastModifiedAt = "";
|
||||
private IImage? _previewImage;
|
||||
|
||||
[ObservableProperty]
|
||||
private ImageSource _previewImage = new BitmapImage();
|
||||
public string FileSize
|
||||
{
|
||||
get => _fileSize;
|
||||
set
|
||||
{
|
||||
if (_fileSize != value)
|
||||
{
|
||||
_fileSize = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string CreatedAt
|
||||
{
|
||||
get => _createdAt;
|
||||
set
|
||||
{
|
||||
if (_createdAt != value)
|
||||
{
|
||||
_createdAt = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string LastModifiedAt
|
||||
{
|
||||
get => _lastModifiedAt;
|
||||
set
|
||||
{
|
||||
if (_lastModifiedAt != value)
|
||||
{
|
||||
_lastModifiedAt = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IImage? PreviewImage
|
||||
{
|
||||
get => _previewImage;
|
||||
set
|
||||
{
|
||||
if (_previewImage != value)
|
||||
{
|
||||
_previewImage = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Settings Settings { get; }
|
||||
|
||||
public Visibility FileSizeVisibility => Settings.ShowFileSizeInPreviewPanel
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
public Visibility CreatedAtVisibility => Settings.ShowCreatedDateInPreviewPanel
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
public Visibility LastModifiedAtVisibility => Settings.ShowModifiedDateInPreviewPanel
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
public bool FileSizeVisibility => Settings.ShowFileSizeInPreviewPanel;
|
||||
public bool CreatedAtVisibility => Settings.ShowCreatedDateInPreviewPanel;
|
||||
public bool LastModifiedAtVisibility => Settings.ShowModifiedDateInPreviewPanel;
|
||||
|
||||
public Visibility FileInfoVisibility =>
|
||||
public bool FileInfoVisibility =>
|
||||
Settings.ShowFileSizeInPreviewPanel ||
|
||||
Settings.ShowCreatedDateInPreviewPanel ||
|
||||
Settings.ShowModifiedDateInPreviewPanel
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
Settings.ShowModifiedDateInPreviewPanel;
|
||||
|
||||
public PreviewPanel(Settings settings, string filePath, ResultType type)
|
||||
{
|
||||
|
|
@ -62,6 +96,7 @@ public partial class PreviewPanel : UserControl
|
|||
FileName = Path.GetFileName(filePath);
|
||||
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
|
||||
if (Settings.ShowFileSizeInPreviewPanel)
|
||||
{
|
||||
|
|
@ -73,8 +108,8 @@ public partial class PreviewPanel : UserControl
|
|||
{
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
FileSize = GetFolderSize(filePath);
|
||||
OnPropertyChanged(nameof(FileSize));
|
||||
var size = GetFolderSize(filePath);
|
||||
global::Avalonia.Threading.Dispatcher.UIThread.Post(() => FileSize = size);
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +123,7 @@ public partial class PreviewPanel : UserControl
|
|||
|
||||
if (Settings.ShowModifiedDateInPreviewPanel)
|
||||
{
|
||||
LastModifiedAt = type == ResultType.File ?
|
||||
LastModifiedAt = type == ResultType.File ?
|
||||
GetFileLastModifiedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel) :
|
||||
GetFolderLastModifiedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||
}
|
||||
|
|
@ -98,7 +133,24 @@ public partial class PreviewPanel : UserControl
|
|||
|
||||
private async Task LoadImageAsync()
|
||||
{
|
||||
PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var imagePath = FilePath;
|
||||
if (string.IsNullOrEmpty(imagePath) || !File.Exists(imagePath))
|
||||
return;
|
||||
|
||||
var bitmap = new Bitmap(imagePath);
|
||||
global::Avalonia.Threading.Dispatcher.UIThread.Post(() => PreviewImage = bitmap);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Main.Context.API.LogException(ClassName, $"Failed to load image for {FilePath}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
global::Avalonia.Markup.Xaml.AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public static string GetFileSize(string filePath)
|
||||
|
|
@ -323,8 +375,15 @@ public partial class PreviewPanel : UserControl
|
|||
|
||||
var yearsDiff = now.Year - fileDateTime.Year;
|
||||
if (now.Month < fileDateTime.Month || (now.Month == fileDateTime.Month && now.Day < fileDateTime.Day))
|
||||
yearsDiff--;
|
||||
yearsDiff--;
|
||||
|
||||
return yearsDiff == 1 ? Localize.OneYearAgo(): Localize.YearsAgo(yearsDiff);
|
||||
return yearsDiff == 1 ? Localize.OneYearAgo() : Localize.YearsAgo(yearsDiff);
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Views/Avalonia/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
|
|
@ -1,861 +0,0 @@
|
|||
<UserControl
|
||||
x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:qa="clr-namespace:Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.Plugin.Explorer.ViewModels"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Key="ListViewTemplateAccessLinks" DataType="qa:AccessLink">
|
||||
<TextBlock Margin="0 5 0 5" Text="{Binding Path, Mode=OneTime}" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="ListViewActionKeywords" DataType="{x:Type viewModels:ActionKeywordModel}">
|
||||
<Grid>
|
||||
<TextBlock
|
||||
Margin="0 5 0 0"
|
||||
IsEnabled="{Binding Enabled}"
|
||||
Text="{Binding LocalizedDescription, Mode=OneTime}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color18B}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock
|
||||
Margin="250 5 0 0"
|
||||
IsEnabled="{Binding Enabled}"
|
||||
Text="{Binding Keyword}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color18B}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Margin="480 5 0 0">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Enabled}" Value="True">
|
||||
<Setter Property="Text" Value="{DynamicResource plugin_explorer_enabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Enabled}" Value="False">
|
||||
<Setter Property="Text" Value="{DynamicResource plugin_explorer_disabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color18B}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<Style x:Key="CustomExpanderStyle" TargetType="Expander">
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Color03B}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||
<Setter Property="BorderThickness" Value="0 0 0 1" />
|
||||
<Setter Property="Padding" Value="-8 18 24 14" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Expander">
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
SnapsToDevicePixels="true">
|
||||
<DockPanel>
|
||||
<ToggleButton
|
||||
x:Name="HeaderSite"
|
||||
MinWidth="0"
|
||||
MinHeight="0"
|
||||
Margin="0"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"
|
||||
DockPanel.Dock="Top"
|
||||
FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}"
|
||||
FontFamily="{TemplateBinding FontFamily}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
FontStretch="{TemplateBinding FontStretch}"
|
||||
FontStyle="{TemplateBinding FontStyle}"
|
||||
FontWeight="{TemplateBinding FontWeight}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Style="{StaticResource ExpanderHeaderRightArrowStyle}" />
|
||||
<Border
|
||||
x:Name="ContentPresenterBorder"
|
||||
BorderBrush="{DynamicResource Color03B}"
|
||||
BorderThickness="0 1 0 0">
|
||||
<ContentPresenter
|
||||
x:Name="ExpandSite"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
DockPanel.Dock="Bottom"
|
||||
Focusable="false" />
|
||||
<Border.LayoutTransform>
|
||||
<ScaleTransform ScaleY="0" />
|
||||
</Border.LayoutTransform>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsExpanded" Value="true">
|
||||
<Setter TargetName="ExpandSite" Property="Visibility" Value="Visible" />
|
||||
<Setter TargetName="ContentPresenterBorder" Property="BorderThickness" Value="0 1 0 0" />
|
||||
<Trigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="ContentPresenterBorder"
|
||||
Storyboard.TargetProperty="(Border.LayoutTransform).(ScaleTransform.ScaleY)"
|
||||
From="0.0"
|
||||
To="1.0"
|
||||
Duration="0:0:0" />
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="ContentPresenterBorder"
|
||||
Storyboard.TargetProperty="(Border.Opacity)"
|
||||
From="0.0"
|
||||
To="1.0"
|
||||
Duration="0:0:0" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.EnterActions>
|
||||
<Trigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="ContentPresenterBorder"
|
||||
Storyboard.TargetProperty="(Border.LayoutTransform).(ScaleTransform.ScaleY)"
|
||||
From="1.0"
|
||||
To="0.0"
|
||||
Duration="0:0:0" />
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="ContentPresenterBorder"
|
||||
Storyboard.TargetProperty="(Border.Opacity)"
|
||||
From="1.0"
|
||||
To="0.0"
|
||||
Duration="0:0:0" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.ExitActions>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<!-- Margin="-2 0 -2 0" is to make sure separator between expanders are expanded to left & right boarder -->
|
||||
<StackPanel x:Name="ExpanderContainer" Margin="-2 0 -2 0">
|
||||
<!-- General Settings Expander -->
|
||||
<Expander
|
||||
x:Name="GeneralSettingsExpander"
|
||||
Expanded="Expander_Expanded"
|
||||
Header="{DynamicResource plugin_explorer_generalsetting_header}"
|
||||
IsExpanded="False"
|
||||
Style="{StaticResource CustomExpanderStyle}">
|
||||
|
||||
<!-- Margin="32 -10 0 0" is to make sure elements is left aligned to the text in the expander text -->
|
||||
<Grid Margin="32 -10 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Content="{DynamicResource plugin_explorer_use_location_as_working_dir}"
|
||||
IsChecked="{Binding Settings.UseLocationAsWorkingDir}" />
|
||||
|
||||
<CheckBox
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Content="{DynamicResource plugin_explorer_default_open_in_file_manager}"
|
||||
IsChecked="{Binding Settings.DefaultOpenFolderInFileManager}" />
|
||||
|
||||
<CheckBox
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Content="{DynamicResource plugin_explorer_display_more_info_in_tooltip}"
|
||||
IsChecked="{Binding Settings.DisplayMoreInformationInToolTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_file_editor_path}" />
|
||||
<StackPanel
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
Orientation="Horizontal">
|
||||
<TextBox
|
||||
Width="{StaticResource SettingPanelPathTextBoxWidth}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding FileEditorPath}"
|
||||
TextWrapping="NoWrap" />
|
||||
<Button
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenFileEditorPathCommand}"
|
||||
Content="{DynamicResource select}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_folder_editor_path}" />
|
||||
<StackPanel
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
Orientation="Horizontal">
|
||||
<TextBox
|
||||
Width="{StaticResource SettingPanelPathTextBoxWidth}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding FolderEditorPath}"
|
||||
TextWrapping="NoWrap" />
|
||||
<Button
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenFolderEditorPathCommand}"
|
||||
Content="{DynamicResource select}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_shell_path}" />
|
||||
<StackPanel
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
Orientation="Horizontal">
|
||||
<TextBox
|
||||
Width="{StaticResource SettingPanelPathTextBoxWidth}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding ShellPath}"
|
||||
TextWrapping="NoWrap" />
|
||||
<Button
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenShellPathCommand}"
|
||||
Content="{DynamicResource select}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_Index_Search_Engine}" />
|
||||
<ComboBox
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
DisplayMemberPath="Description"
|
||||
ItemsSource="{Binding IndexSearchEngines}"
|
||||
SelectedItem="{Binding SelectedIndexSearchEngine}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_Content_Search_Engine}" />
|
||||
<ComboBox
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
DisplayMemberPath="Description"
|
||||
ItemsSource="{Binding ContentIndexSearchEngines}"
|
||||
SelectedItem="{Binding SelectedContentSearchEngine}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_Directory_Recursive_Search_Engine}" />
|
||||
<ComboBox
|
||||
Grid.Row="8"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
DisplayMemberPath="Description"
|
||||
ItemsSource="{Binding PathEnumerationEngines}"
|
||||
SelectedItem="{Binding SelectedPathEnumerationEngine}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_Excluded_File_Types}" />
|
||||
<TextBox
|
||||
Grid.Row="9"
|
||||
Grid.Column="1"
|
||||
MinWidth="{StaticResource SettingPanelTextBoxMinWidth}"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding ExcludedFileTypes}"
|
||||
ToolTip="{DynamicResource plugin_explorer_Excluded_File_Types_Tooltip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_Maximum_Results}" />
|
||||
<TextBox
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
MinWidth="{StaticResource SettingPanelTextBoxMinWidth}"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
MaxLength="6"
|
||||
PreviewTextInput="AllowOnlyNumericInput"
|
||||
Text="{Binding MaxResult}"
|
||||
ToolTip="{DynamicResource plugin_explorer_Maximum_Results_Tooltip}" />
|
||||
|
||||
<Button
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
Click="btnOpenIndexingOptions_Click"
|
||||
Content="{DynamicResource plugin_explorer_Open_Window_Index_Option}" />
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<!-- Native Context Menu Expander -->
|
||||
<Expander
|
||||
x:Name="ContextMenuExpander"
|
||||
Expanded="Expander_Expanded"
|
||||
Header="{DynamicResource plugin_explorer_native_context_menu_header}"
|
||||
IsExpanded="False"
|
||||
Style="{StaticResource CustomExpanderStyle}">
|
||||
<Grid Margin="32 -10 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
Content="{DynamicResource plugin_explorer_native_context_menu_display_context_menu}"
|
||||
IsChecked="{Binding ShowWindowsContextMenu}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_native_context_menu_include_patterns_guide}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBox
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="{StaticResource SettingPanelAreaTextBoxMinHeight}"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Stretch"
|
||||
AcceptsReturn="True"
|
||||
Text="{Binding WindowsContextMenuIncludedItems}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_native_context_menu_exclude_patterns_guide}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBox
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="{StaticResource SettingPanelAreaTextBoxMinHeight}"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Stretch"
|
||||
AcceptsReturn="True"
|
||||
Text="{Binding WindowsContextMenuExcludedItems}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<!-- Preview Panel Settings Expander -->
|
||||
<Expander
|
||||
x:Name="PreviewPanelExpander"
|
||||
Expanded="Expander_Expanded"
|
||||
Header="{DynamicResource plugin_explorer_previewpanel_setting_header}"
|
||||
IsExpanded="False"
|
||||
Style="{StaticResource CustomExpanderStyle}">
|
||||
<Grid Margin="32 -10 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<DockPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
LastChildFill="True">
|
||||
<TextBlock
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_previewpanel_file_info_label}" />
|
||||
<WrapPanel
|
||||
Width="Auto"
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Right">
|
||||
<CheckBox
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
Content="{DynamicResource plugin_explorer_previewpanel_display_file_size_checkbox}"
|
||||
IsChecked="{Binding ShowFileSizeInPreviewPanel}" />
|
||||
<CheckBox
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
Content="{DynamicResource plugin_explorer_previewpanel_display_file_creation_checkbox}"
|
||||
IsChecked="{Binding ShowCreatedDateInPreviewPanel}" />
|
||||
<CheckBox
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
Content="{DynamicResource plugin_explorer_previewpanel_display_file_modification_checkbox}"
|
||||
IsChecked="{Binding ShowModifiedDateInPreviewPanel}" />
|
||||
<CheckBox
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
Content="{DynamicResource plugin_explorer_previewpanel_display_file_age_checkbox}"
|
||||
IsChecked="{Binding ShowFileAgeInPreviewPanel}" />
|
||||
</WrapPanel>
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
LastChildFill="True">
|
||||
<TextBlock
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
IsEnabled="{Binding ShowPreviewPanelDateTimeChoices}"
|
||||
Text="{DynamicResource plugin_explorer_previewpanel_date_and_time_format_label}"
|
||||
Visibility="{Binding PreviewPanelDateTimeChoicesVisibility}" />
|
||||
<WrapPanel
|
||||
Width="Auto"
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Right"
|
||||
IsEnabled="{Binding ShowPreviewPanelDateTimeChoices}"
|
||||
Visibility="{Binding PreviewPanelDateTimeChoicesVisibility}">
|
||||
<StackPanel Margin="{StaticResource SettingPanelItemTopBottomMargin}" Orientation="Horizontal">
|
||||
<ComboBox
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
ItemsSource="{Binding DateFormatList}"
|
||||
SelectedItem="{Binding PreviewPanelDateFormat}" />
|
||||
<TextBlock
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding PreviewPanelDateFormatDemo}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="{StaticResource SettingPanelItemTopBottomMargin}" Orientation="Horizontal">
|
||||
<ComboBox
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
ItemsSource="{Binding TimeFormatList}"
|
||||
SelectedItem="{Binding PreviewPanelTimeFormat}" />
|
||||
<TextBlock
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding PreviewPanelTimeFormatDemo}" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<!-- Everything Settings Expander -->
|
||||
<Expander
|
||||
x:Name="EverythingExpander"
|
||||
Expanded="Expander_Expanded"
|
||||
Header="{DynamicResource plugin_explorer_everything_setting_header}"
|
||||
IsExpanded="False"
|
||||
Style="{StaticResource CustomExpanderStyle}">
|
||||
<Grid Margin="32 -10 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Content="{DynamicResource flowlauncher_plugin_everything_search_fullpath}"
|
||||
IsChecked="{Binding Settings.EverythingSearchFullPath}" />
|
||||
|
||||
<CheckBox
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Content="{DynamicResource flowlauncher_plugin_everything_enable_run_count}"
|
||||
IsChecked="{Binding Settings.EverythingEnableRunCount}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_everything_sort_option}" />
|
||||
<ComboBox
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding AllEverythingSortOptions}"
|
||||
SelectedValue="{Binding SelectedEverythingSortOption, Mode=TwoWay}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Display">
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource plugin_explorer_everything_installed_path}" />
|
||||
<TextBox
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="{StaticResource SettingPanelPathTextBoxWidth}"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding EverythingInstalledPath}" />
|
||||
|
||||
<TextBlock
|
||||
Name="tbFastSortWarning"
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="Orange"
|
||||
Text="{Binding SortOptionWarningMessage, Mode=OneWay}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding FastSortWarningVisibility, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<!-- Manage Action Keywords Expander -->
|
||||
<Expander
|
||||
x:Name="ActionKeywordsExpander"
|
||||
Expanded="Expander_Expanded"
|
||||
Header="{DynamicResource plugin_explorer_manageactionkeywords_header}"
|
||||
IsExpanded="False"
|
||||
Style="{StaticResource CustomExpanderStyle}">
|
||||
<Grid Margin="32 -10 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||
BorderThickness="1">
|
||||
<ListView
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}"
|
||||
ItemsSource="{Binding ActionKeywordsModels}"
|
||||
SelectedItem="{Binding SelectedActionKeyword}" />
|
||||
</Border>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Command="{Binding EditActionKeywordCommand}"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<!-- Quick Access Links Expander -->
|
||||
<Expander
|
||||
x:Name="QuickAccessExpander"
|
||||
Expanded="Expander_Expanded"
|
||||
Header="{DynamicResource plugin_explorer_quickaccesslinks_header}"
|
||||
IsExpanded="False"
|
||||
Style="{StaticResource CustomExpanderStyle}">
|
||||
<Grid Margin="32 -10 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||
BorderThickness="1">
|
||||
<ListView
|
||||
x:Name="lbxAccessLinks"
|
||||
Height="200"
|
||||
AllowDrop="True"
|
||||
BorderThickness="1"
|
||||
DragEnter="lbxAccessLinks_DragEnter"
|
||||
Drop="LbxAccessLinks_OnDrop"
|
||||
ItemsSource="{Binding Settings.QuickAccessLinks}"
|
||||
Loaded="lbxAccessLinks_Loaded"
|
||||
SelectedItem="{Binding SelectedQuickAccessLink}"
|
||||
SizeChanged="lbxAccessLinks_SizeChanged">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Width="600" Header="{DynamicResource plugin_explorer_name}">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Width="900" Header="{DynamicResource plugin_explorer_path}">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path}" TextTrimming="CharacterEllipsis" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</Border>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
Command="{Binding EditQuickAccessLinkCommand}"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
Command="{Binding AddQuickAccessLinkCommand}"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<!-- Index Search Excluded Paths Expander -->
|
||||
<Expander
|
||||
x:Name="ExcludedPathsExpander"
|
||||
Margin="0"
|
||||
BorderThickness="0 0 0 0"
|
||||
Expanded="Expander_Expanded"
|
||||
Header="{DynamicResource plugin_explorer_indexsearchexcludedpaths_header}"
|
||||
IsExpanded="False"
|
||||
Style="{StaticResource CustomExpanderStyle}">
|
||||
<Grid Margin="32 -10 0 0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||
BorderThickness="1">
|
||||
<ListView
|
||||
Name="lbxExcludedPaths"
|
||||
Height="200"
|
||||
AllowDrop="True"
|
||||
DragEnter="lbxAccessLinks_DragEnter"
|
||||
Drop="LbxExcludedPaths_OnDrop"
|
||||
ItemTemplate="{StaticResource ListViewTemplateAccessLinks}"
|
||||
ItemsSource="{Binding Settings.IndexSearchExcludedSubdirectoryPaths}"
|
||||
Loaded="lbxExcludedPaths_Loaded"
|
||||
SelectedItem="{Binding SelectedIndexSearchExcludedPath}" />
|
||||
</Border>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
Command="{Binding EditIndexSearchExcludePathsCommand}"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||
Command="{Binding AddIndexSearchExcludePathsCommand}"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
||||
using Flow.Launcher.Plugin.Explorer.ViewModels;
|
||||
using DataFormats = System.Windows.DataFormats;
|
||||
using DragDropEffects = System.Windows.DragDropEffects;
|
||||
using DragEventArgs = System.Windows.DragEventArgs;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views
|
||||
{
|
||||
public partial class ExplorerSettings
|
||||
{
|
||||
private readonly SettingsViewModel _viewModel;
|
||||
private readonly List<Expander> _expanders;
|
||||
|
||||
public ExplorerSettings(SettingsViewModel viewModel)
|
||||
{
|
||||
_viewModel = viewModel;
|
||||
DataContext = viewModel;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
DataContext = viewModel;
|
||||
|
||||
ActionKeywordModel.Init(viewModel.Settings);
|
||||
|
||||
_expanders = new List<Expander>
|
||||
{
|
||||
GeneralSettingsExpander,
|
||||
ContextMenuExpander,
|
||||
PreviewPanelExpander,
|
||||
EverythingExpander,
|
||||
ActionKeywordsExpander,
|
||||
QuickAccessExpander,
|
||||
ExcludedPathsExpander
|
||||
};
|
||||
}
|
||||
|
||||
private void AccessLinkDragDrop(string containerName, DragEventArgs e)
|
||||
{
|
||||
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
|
||||
if (files == null || files.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var s in files)
|
||||
{
|
||||
if (Directory.Exists(s))
|
||||
{
|
||||
var newFolderLink = new AccessLink
|
||||
{
|
||||
Path = s
|
||||
};
|
||||
_viewModel.AppendLink(containerName, newFolderLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void lbxAccessLinks_DragEnter(object sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
{
|
||||
e.Effects = DragDropEffects.Link;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Effects = DragDropEffects.None;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOpenIndexingOptions_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SettingsViewModel.OpenWindowsIndexingOptions();
|
||||
}
|
||||
|
||||
private void LbxAccessLinks_OnDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
AccessLinkDragDrop("QuickAccessLink", e);
|
||||
}
|
||||
private void LbxExcludedPaths_OnDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
AccessLinkDragDrop("IndexSearchExcludedPath", e);
|
||||
}
|
||||
|
||||
private void AllowOnlyNumericInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
|
||||
{
|
||||
e.Handled = e.Text.ToCharArray().Any(c => !char.IsDigit(c));
|
||||
}
|
||||
|
||||
private void Expander_Expanded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Expander expandedExpander)
|
||||
{
|
||||
// Ensure _expanders is not null and contains items
|
||||
if (_expanders == null || _expanders.Count == 0) return;
|
||||
|
||||
foreach (var expander in _expanders)
|
||||
{
|
||||
if (expander != null && expander != expandedExpander && expander.IsExpanded)
|
||||
{
|
||||
expander.IsExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void lbxAccessLinks_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
lbxAccessLinks.Items.SortDescriptions.Add(new SortDescription("Path", ListSortDirection.Ascending));
|
||||
}
|
||||
|
||||
private void lbxExcludedPaths_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
lbxExcludedPaths.Items.SortDescriptions.Add(new SortDescription("Path", ListSortDirection.Ascending));
|
||||
}
|
||||
|
||||
private void lbxAccessLinks_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (sender is not ListView listView) return;
|
||||
if (listView.View is not GridView gView) return;
|
||||
|
||||
var workingWidth =
|
||||
listView.ActualWidth - SystemParameters.VerticalScrollBarWidth; // take into account vertical scrollbar
|
||||
|
||||
if (workingWidth <= 0) return;
|
||||
|
||||
var col1 = 0.4;
|
||||
var col2 = 0.6;
|
||||
|
||||
gView.Columns[0].Width = workingWidth * col1;
|
||||
gView.Columns[1].Width = workingWidth * col2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
<UserControl
|
||||
x:Class="Flow.Launcher.Plugin.Explorer.Views.PreviewPanel"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||
mc:Ignorable="d">
|
||||
<Grid x:Name="PreviewGrid" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition MinHeight="96" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
MaxWidth="96"
|
||||
MaxHeight="96"
|
||||
Margin="5 12 8 0"
|
||||
Source="{Binding PreviewImage, IsAsync=True, Mode=OneWay}" />
|
||||
<Grid Grid.Row="1">
|
||||
<TextBlock
|
||||
Margin="5 6 5 16"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Style="{DynamicResource PreviewItemTitleStyle}"
|
||||
Text="{Binding FileName, Mode=OneTime}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<StackPanel Grid.Row="1">
|
||||
<Rectangle
|
||||
x:Name="PreviewSep"
|
||||
Width="Auto"
|
||||
Height="1"
|
||||
Margin="0 0 5 0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Style="{DynamicResource SeparatorStyle}" />
|
||||
<TextBlock
|
||||
Margin="5 8 8 8"
|
||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||
Text="{Binding FilePath, Mode=OneTime}" />
|
||||
<Rectangle
|
||||
Width="Auto"
|
||||
Height="1"
|
||||
Margin="0 0 5 0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Fill="{Binding ElementName=PreviewSep, Path=Fill}">
|
||||
<Rectangle.Style>
|
||||
<Style TargetType="Rectangle">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding FileSizeVisibility}" Value="Collapsed" />
|
||||
<Condition Binding="{Binding CreatedAtVisibility}" Value="Collapsed" />
|
||||
<Condition Binding="{Binding LastModifiedAtVisibility}" Value="Collapsed" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Rectangle.Style>
|
||||
</Rectangle>
|
||||
<Grid Margin="0 10 0 0" Visibility="{Binding FileInfoVisibility, Mode=OneTime}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="5 0 0 0"
|
||||
VerticalAlignment="Top"
|
||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||
Text="{DynamicResource FileSize}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding FileSizeVisibility, Mode=OneTime}" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0 0 13 0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||
Text="{Binding FileSize, Mode=OneWay}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding FileSizeVisibility, Mode=OneTime}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="5 0 8 0"
|
||||
VerticalAlignment="Top"
|
||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||
Text="{DynamicResource Created}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding CreatedAtVisibility, Mode=OneTime}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="0 0 13 0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||
Text="{Binding CreatedAt, Mode=OneWay}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding CreatedAtVisibility, Mode=OneTime}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="5 0 8 0"
|
||||
VerticalAlignment="Top"
|
||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||
Text="{DynamicResource LastModified}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding LastModifiedAtVisibility, Mode=OneTime}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="0 0 13 0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||
Text="{Binding LastModifiedAt, Mode=OneWay}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding LastModifiedAtVisibility, Mode=OneTime}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
<Window
|
||||
x:Class="Flow.Launcher.Plugin.Explorer.Views.QuickAccessLinkSettings"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="{DynamicResource plugin_explorer_manage_quick_access_links_header}"
|
||||
Width="Auto"
|
||||
Height="300"
|
||||
Background="{DynamicResource PopuBGColor}"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||
Foreground="{DynamicResource PopupTextColor}"
|
||||
ResizeMode="NoResize"
|
||||
SizeToContent="Width"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<WindowChrome.WindowChrome>
|
||||
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
|
||||
</WindowChrome.WindowChrome>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="80" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<StackPanel>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button
|
||||
Grid.Column="4"
|
||||
Click="BtnCancel_OnClick"
|
||||
Style="{StaticResource TitleBarCloseButtonStyle}">
|
||||
<Path
|
||||
Width="46"
|
||||
Height="32"
|
||||
Data="M 18,11 27,20 M 18,20 27,11"
|
||||
Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
StrokeThickness="1">
|
||||
<Path.Style>
|
||||
<Style TargetType="Path">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="False">
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Path.Style>
|
||||
</Path>
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="26 0 26 0">
|
||||
<StackPanel Margin="0 0 0 12">
|
||||
<TextBlock
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Text="{DynamicResource plugin_explorer_manage_quick_access_links_header}"
|
||||
TextAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Name -->
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="0 10 0 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource plugin_explorer_name}" />
|
||||
<TextBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="10 10 0 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Text="{Binding SelectedName, Mode=TwoWay}" />
|
||||
|
||||
<!-- Type -->
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="0 10 0 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource plugin_explorer_type}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
<RadioButton
|
||||
Margin="10 10 0 0"
|
||||
Content="{DynamicResource plugin_explorer_file}"
|
||||
GroupName="PathType"
|
||||
IsChecked="{Binding IsFileSelected}" />
|
||||
<RadioButton
|
||||
Margin="10 10 0 0"
|
||||
Content="{DynamicResource plugin_explorer_folder}"
|
||||
GroupName="PathType"
|
||||
IsChecked="{Binding IsFolderSelected}" />
|
||||
</StackPanel>
|
||||
<!-- Path -->
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="0 10 0 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource plugin_explorer_path}" />
|
||||
<TextBox
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="250"
|
||||
Margin="10 10 0 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
IsReadOnly="True"
|
||||
Text="{Binding SelectedPath, Mode=TwoWay}" />
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Height="Auto"
|
||||
MinWidth="80"
|
||||
Margin="10 10 0 0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Click="SelectPath_OnClick"
|
||||
Content="{DynamicResource select}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Background="{DynamicResource PopupButtonAreaBGColor}"
|
||||
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||
BorderThickness="0 1 0 0">
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="145"
|
||||
Height="34"
|
||||
Margin="0 0 5 1"
|
||||
Click="BtnCancel_OnClick"
|
||||
Content="{DynamicResource cancel}" />
|
||||
<Button
|
||||
Name="DownButton"
|
||||
Width="145"
|
||||
Height="34"
|
||||
Margin="5 0 0 1"
|
||||
Click="OnDoneButtonClick"
|
||||
Style="{StaticResource AccentButtonStyle}">
|
||||
<TextBlock x:Name="lblAdd" Text="{DynamicResource done}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using Flow.Launcher.Plugin.Explorer.Helper;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views;
|
||||
|
||||
[INotifyPropertyChanged]
|
||||
public partial class QuickAccessLinkSettings
|
||||
{
|
||||
private static readonly string ClassName = nameof(QuickAccessLinkSettings);
|
||||
|
||||
private string _selectedPath;
|
||||
public string SelectedPath
|
||||
{
|
||||
get => _selectedPath;
|
||||
set
|
||||
{
|
||||
if (_selectedPath != value)
|
||||
{
|
||||
_selectedPath = value;
|
||||
OnPropertyChanged();
|
||||
if (string.IsNullOrEmpty(_selectedName))
|
||||
{
|
||||
SelectedName = _selectedPath.GetPathName();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(_selectedPath))
|
||||
{
|
||||
_accessLinkType = GetResultType(_selectedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _selectedName;
|
||||
public string SelectedName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.IsNullOrEmpty(_selectedName) ? _selectedPath.GetPathName() : _selectedName;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_selectedName != value)
|
||||
{
|
||||
_selectedName = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFileSelected { get; set; }
|
||||
public bool IsFolderSelected { get; set; } = true; // Default to Folder
|
||||
|
||||
private bool IsEdit { get; }
|
||||
private AccessLink SelectedAccessLink { get; }
|
||||
|
||||
public ObservableCollection<AccessLink> QuickAccessLinks { get; }
|
||||
|
||||
private ResultType _accessLinkType = ResultType.Folder; // Default to Folder
|
||||
|
||||
public QuickAccessLinkSettings(ObservableCollection<AccessLink> quickAccessLinks)
|
||||
{
|
||||
IsEdit = false;
|
||||
QuickAccessLinks = quickAccessLinks;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public QuickAccessLinkSettings(ObservableCollection<AccessLink> quickAccessLinks, AccessLink selectedAccessLink)
|
||||
{
|
||||
IsEdit = true;
|
||||
_selectedName = selectedAccessLink.Name;
|
||||
_selectedPath = selectedAccessLink.Path;
|
||||
_accessLinkType = GetResultType(_selectedPath); // Initialize link type
|
||||
IsFileSelected = selectedAccessLink.Type == ResultType.File; // Initialize default selection
|
||||
IsFolderSelected = !IsFileSelected;
|
||||
SelectedAccessLink = selectedAccessLink;
|
||||
QuickAccessLinks = quickAccessLinks;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnDoneButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Validate the input before proceeding
|
||||
if (string.IsNullOrEmpty(SelectedName) || string.IsNullOrEmpty(SelectedPath))
|
||||
{
|
||||
var warning = Localize.plugin_explorer_quick_access_link_no_folder_selected();
|
||||
Main.Context.API.ShowMsgBox(warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the path already exists in the quick access links
|
||||
if (QuickAccessLinks.Any(x =>
|
||||
x.Path.Equals(SelectedPath, StringComparison.OrdinalIgnoreCase) &&
|
||||
x.Name.Equals(SelectedName, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var warning = Localize.plugin_explorer_quick_access_link_path_already_exists();
|
||||
Main.Context.API.ShowMsgBox(warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// If editing, update the existing link
|
||||
if (IsEdit)
|
||||
{
|
||||
if (SelectedAccessLink != null)
|
||||
{
|
||||
var index = QuickAccessLinks.IndexOf(SelectedAccessLink);
|
||||
if (index >= 0)
|
||||
{
|
||||
var updatedLink = new AccessLink
|
||||
{
|
||||
Name = SelectedName,
|
||||
Type = _accessLinkType,
|
||||
Path = SelectedPath
|
||||
};
|
||||
QuickAccessLinks[index] = updatedLink;
|
||||
}
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
// Add a new one if the selected access link is null (should not happen in edit mode, but just in case)
|
||||
else
|
||||
{
|
||||
AddNewAccessLink();
|
||||
}
|
||||
}
|
||||
// Otherwise, add a new one
|
||||
else
|
||||
{
|
||||
AddNewAccessLink();
|
||||
}
|
||||
|
||||
void AddNewAccessLink()
|
||||
{
|
||||
var newAccessLink = new AccessLink
|
||||
{
|
||||
Name = SelectedName,
|
||||
Type = _accessLinkType,
|
||||
Path = SelectedPath
|
||||
};
|
||||
QuickAccessLinks.Add(newAccessLink);
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectPath_OnClick(object commandParameter, RoutedEventArgs e)
|
||||
{
|
||||
// Open file or folder selection dialog based on the selected radio button
|
||||
if (IsFileSelected)
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog
|
||||
{
|
||||
Multiselect = false,
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true
|
||||
};
|
||||
|
||||
if (openFileDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK ||
|
||||
string.IsNullOrEmpty(openFileDialog.FileName))
|
||||
return;
|
||||
|
||||
SelectedPath = openFileDialog.FileName;
|
||||
}
|
||||
else // Folder selection
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog
|
||||
{
|
||||
ShowNewFolderButton = true
|
||||
};
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK ||
|
||||
string.IsNullOrEmpty(folderBrowserDialog.SelectedPath))
|
||||
return;
|
||||
|
||||
SelectedPath = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
||||
private static ResultType GetResultType(string path)
|
||||
{
|
||||
// Check if the path is a file or folder
|
||||
if (File.Exists(path))
|
||||
{
|
||||
return ResultType.File;
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
if (string.Equals(Path.GetPathRoot(path), path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ResultType.Volume;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ResultType.Folder;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This should not happen, but just in case, we assume it's a folder
|
||||
Main.Context.API.LogError(ClassName, $"The path '{path}' does not exist or is invalid. Defaulting to Folder type.");
|
||||
return ResultType.Folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Plugins/Flow.Launcher.Plugin.Explorer/Views/codemap.md
Normal file
19
Plugins/Flow.Launcher.Plugin.Explorer/Views/codemap.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/Views/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
19
Plugins/Flow.Launcher.Plugin.Explorer/codemap.md
Normal file
19
Plugins/Flow.Launcher.Plugin.Explorer/codemap.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Plugins/Flow.Launcher.Plugin.Explorer/
|
||||
|
||||
<!-- Explorer: Fill in this section with architectural understanding -->
|
||||
|
||||
## Responsibility
|
||||
|
||||
<!-- What is this folder's job in the system? -->
|
||||
|
||||
## Design
|
||||
|
||||
<!-- Key patterns, abstractions, architectural decisions -->
|
||||
|
||||
## Flow
|
||||
|
||||
<!-- How does data/control flow through this module? -->
|
||||
|
||||
## Integration
|
||||
|
||||
<!-- How does it connect to other parts of the system? -->
|
||||
Loading…
Reference in a new issue