Skip to content

Commit 2263c94

Browse files
Merge branch 'dev' into SearchProgramsInPATH
2 parents a67e719 + ca47b4a commit 2263c94

File tree

9 files changed

+393
-395
lines changed

9 files changed

+393
-395
lines changed

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public string Language
5252
public double SettingWindowHeight { get; set; } = 700;
5353
public double SettingWindowTop { get; set; }
5454
public double SettingWindowLeft { get; set; }
55+
public System.Windows.WindowState SettingWindowState { get; set; } = WindowState.Normal;
5556

5657
public int CustomExplorerIndex { get; set; } = 0;
5758

Flow.Launcher/Flow.Launcher.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
</PackageReference>
9999
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
100100
<PackageReference Include="SharpVectors" Version="1.7.6" />
101+
<PackageReference Include="VirtualizingWrapPanel" Version="1.5.7" />
101102
</ItemGroup>
102103

103104
<ItemGroup>
@@ -120,7 +121,7 @@
120121
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
121122

122123
<ItemGroup>
123-
<FilteredAnalyzer Include="@(Analyzer->Distinct())" />
124+
<FilteredAnalyzer Include="@(Analyzer-&gt;Distinct())" />
124125
<Analyzer Remove="@(Analyzer)" />
125126
<Analyzer Include="@(FilteredAnalyzer)" />
126127
</ItemGroup>

Flow.Launcher/Resources/Dark.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969
<SolidColorBrush x:Key="CustomContextDisabled" Color="#868686" />
7070
<SolidColorBrush x:Key="ContextSeparator" Color="#3c3c3c" />
7171

72+
<SolidColorBrush x:Key="HoverStoreGrid2">#272727</SolidColorBrush>
73+
7274
<Color x:Key="Color01">#202020</Color>
7375
<Color x:Key="Color02">#2b2b2b</Color>
7476
<Color x:Key="Color03">#1d1d1d</Color>

Flow.Launcher/Resources/Light.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
<SolidColorBrush x:Key="CustomContextDisabled" Color="#868686" />
6363
<SolidColorBrush x:Key="ContextSeparator" Color="#dadada" />
6464

65+
<SolidColorBrush x:Key="HoverStoreGrid2">#f6f6f6</SolidColorBrush>
66+
6567
<Color x:Key="Color01">#f3f3f3</Color>
6668
<Color x:Key="Color02">#ffffff</Color>
6769
<Color x:Key="Color03">#e5e5e5</Color>

Flow.Launcher/SettingWindow.xaml

Lines changed: 251 additions & 323 deletions
Large diffs are not rendered by default.

Flow.Launcher/SettingWindow.xaml.cs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@
88
using Flow.Launcher.Plugin.SharedCommands;
99
using Flow.Launcher.ViewModel;
1010
using ModernWpf;
11+
using ModernWpf.Controls;
1112
using System;
13+
using System.Drawing.Printing;
1214
using System.IO;
1315
using System.Windows;
16+
using System.Windows.Controls.Primitives;
1417
using System.Windows.Data;
1518
using System.Windows.Forms;
1619
using System.Windows.Input;
1720
using System.Windows.Interop;
21+
using System.Windows.Media;
1822
using System.Windows.Navigation;
23+
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
1924
using Button = System.Windows.Controls.Button;
2025
using Control = System.Windows.Controls.Control;
2126
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
@@ -39,10 +44,6 @@ public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel)
3944
API = api;
4045
InitializePosition();
4146
InitializeComponent();
42-
43-
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(StoreListBox.ItemsSource);
44-
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Category");
45-
view.GroupDescriptions.Add(groupDescription);
4647
}
4748

4849
#region General
@@ -252,6 +253,7 @@ private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
252253

253254
private void OnClosed(object sender, EventArgs e)
254255
{
256+
settings.SettingWindowState = WindowState;
255257
settings.SettingWindowTop = Top;
256258
settings.SettingWindowLeft = Left;
257259
viewModel.Save();
@@ -296,17 +298,35 @@ private void ClearLogFolder(object sender, RoutedEventArgs e)
296298
}
297299
}
298300

299-
private void OnPluginStoreRefreshClick(object sender, RoutedEventArgs e)
301+
private static T FindParent<T>(DependencyObject child) where T : DependencyObject
300302
{
301-
_ = viewModel.RefreshExternalPluginsAsync();
302-
}
303+
//get parent item
304+
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
303305

306+
//we've reached the end of the tree
307+
if (parentObject == null) return null;
308+
309+
//check if the parent matches the type we're looking for
310+
T parent = parentObject as T;
311+
if (parent != null)
312+
return parent;
313+
else
314+
return FindParent<T>(parentObject);
315+
}
316+
304317
private void OnExternalPluginInstallClick(object sender, RoutedEventArgs e)
305318
{
306-
if (sender is Button { DataContext: PluginStoreItemViewModel plugin })
319+
if (sender is not Button { DataContext: PluginStoreItemViewModel plugin } button)
307320
{
308-
viewModel.DisplayPluginQuery($"install {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
321+
return;
309322
}
323+
324+
if (storeClickedButton != null)
325+
{
326+
FlyoutService.GetFlyout(storeClickedButton).Hide();
327+
}
328+
329+
viewModel.DisplayPluginQuery($"install {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
310330
}
311331

312332
private void OnExternalPluginUninstallClick(object sender, MouseButtonEventArgs e)
@@ -317,18 +337,30 @@ private void OnExternalPluginUninstallClick(object sender, MouseButtonEventArgs
317337
viewModel.DisplayPluginQuery($"uninstall {name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
318338
}
319339

340+
320341
}
321342

322343
private void OnExternalPluginUninstallClick(object sender, RoutedEventArgs e)
323344
{
345+
if (storeClickedButton != null)
346+
{
347+
FlyoutService.GetFlyout(storeClickedButton).Hide();
348+
}
349+
324350
if (sender is Button { DataContext: PluginStoreItemViewModel plugin })
325351
viewModel.DisplayPluginQuery($"uninstall {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
352+
326353
}
327354

328355
private void OnExternalPluginUpdateClick(object sender, RoutedEventArgs e)
329356
{
357+
if (storeClickedButton != null)
358+
{
359+
FlyoutService.GetFlyout(storeClickedButton).Hide();
360+
}
330361
if (sender is Button { DataContext: PluginStoreItemViewModel plugin })
331362
viewModel.DisplayPluginQuery($"update {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
363+
332364
}
333365

334366
private void window_MouseDown(object sender, MouseButtonEventArgs e) /* for close hotkey popup */
@@ -522,6 +554,7 @@ public void InitializePosition()
522554
Top = WindowTop();
523555
Left = WindowLeft();
524556
}
557+
WindowState = settings.SettingWindowState;
525558
}
526559
public double WindowLeft()
527560
{
@@ -541,5 +574,21 @@ public double WindowTop()
541574
return top;
542575
}
543576

577+
private Button storeClickedButton;
578+
579+
private void StoreListItem_Click(object sender, RoutedEventArgs e)
580+
{
581+
if (sender is not Button button)
582+
return;
583+
584+
storeClickedButton = button;
585+
586+
var flyout = FlyoutService.GetFlyout(button);
587+
flyout.Closed += (_, _) =>
588+
{
589+
storeClickedButton = null;
590+
};
591+
592+
}
544593
}
545594
}

Flow.Launcher/ViewModel/SettingWindowViewModel.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
using Flow.Launcher.Plugin;
2121
using Flow.Launcher.Plugin.SharedModels;
2222
using System.Collections.ObjectModel;
23+
using CommunityToolkit.Mvvm.Input;
2324

2425
namespace Flow.Launcher.ViewModel
2526
{
26-
public class SettingWindowViewModel : BaseModel
27+
public partial class SettingWindowViewModel : BaseModel
2728
{
2829
private readonly Updater _updater;
2930
private readonly IPortable _portable;
@@ -330,7 +331,8 @@ public Control SettingProvider
330331
}
331332
}
332333

333-
public async Task RefreshExternalPluginsAsync()
334+
[RelayCommand]
335+
private async Task RefreshExternalPluginsAsync()
334336
{
335337
await PluginsManifest.UpdateManifestAsync();
336338
OnPropertyChanged(nameof(ExternalPlugins));
@@ -535,6 +537,8 @@ public Brush PreviewBackground
535537
var bitmap = new BitmapImage();
536538
bitmap.BeginInit();
537539
bitmap.StreamSource = memStream;
540+
bitmap.DecodePixelWidth = 800;
541+
bitmap.DecodePixelHeight = 600;
538542
bitmap.EndInit();
539543
var brush = new ImageBrush(bitmap)
540544
{

Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -601,92 +601,97 @@ internal string LogoPathFromUri(string uri)
601601
// windows 8.1 https://msdn.microsoft.com/en-us/library/windows/apps/hh965372.aspx#target_size
602602
// windows 8 https://msdn.microsoft.com/en-us/library/windows/apps/br211475.aspx
603603

604-
string path;
605-
if (uri.Contains("\\"))
606-
{
607-
path = Path.Combine(Package.Location, uri);
608-
}
609-
else
604+
string path = Path.Combine(Package.Location, uri);
605+
606+
var logoPath = TryToFindLogo(uri, path);
607+
if (String.IsNullOrEmpty(logoPath))
610608
{
609+
// TODO: Don't know why, just keep it at the moment
610+
// Maybe on older version of Windows 10?
611611
// for C:\Windows\MiracastView etc
612-
path = Path.Combine(Package.Location, "Assets", uri);
612+
return TryToFindLogo(uri, Path.Combine(Package.Location, "Assets", uri));
613613
}
614+
return logoPath;
614615

615-
var extension = Path.GetExtension(path);
616-
if (extension != null)
616+
string TryToFindLogo(string uri, string path)
617617
{
618-
var end = path.Length - extension.Length;
619-
var prefix = path.Substring(0, end);
620-
var paths = new List<string>
618+
var extension = Path.GetExtension(path);
619+
if (extension != null)
621620
{
622-
path
623-
};
624-
625-
var scaleFactors = new Dictionary<PackageVersion, List<int>>
626-
{
627-
// scale factors on win10: https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets#asset-size-tables,
621+
//if (File.Exists(path))
622+
//{
623+
// return path; // shortcut, avoid enumerating files
624+
//}
625+
626+
var logoNamePrefix = Path.GetFileNameWithoutExtension(uri); // e.g Square44x44
627+
var logoDir = Path.GetDirectoryName(path); // e.g ..\..\Assets
628+
if (String.IsNullOrEmpty(logoNamePrefix) || String.IsNullOrEmpty(logoDir) || !Directory.Exists(logoDir))
628629
{
629-
PackageVersion.Windows10, new List<int>
630-
{
631-
100,
632-
125,
633-
150,
634-
200,
635-
400
636-
}
637-
},
638-
{
639-
PackageVersion.Windows81, new List<int>
640-
{
641-
100,
642-
120,
643-
140,
644-
160,
645-
180
646-
}
647-
},
630+
// Known issue: Edge always triggers it since logo is not at uri
631+
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
632+
$"|{UserModelId} can't find logo uri for {uri} in package location (logo name or directory not found): {Package.Location}", new FileNotFoundException());
633+
return string.Empty;
634+
}
635+
636+
var files = Directory.EnumerateFiles(logoDir);
637+
638+
// Currently we don't care which one to choose
639+
// Just ignore all qualifiers
640+
// select like logo.[xxx_yyy].png
641+
// https://learn.microsoft.com/en-us/windows/uwp/app-resources/tailor-resources-lang-scale-contrast
642+
var logos = files.Where(file =>
643+
Path.GetFileName(file)?.StartsWith(logoNamePrefix, StringComparison.OrdinalIgnoreCase) ?? false
644+
&& extension.Equals(Path.GetExtension(file), StringComparison.OrdinalIgnoreCase)
645+
);
646+
647+
var selected = logos.FirstOrDefault();
648+
var closest = selected;
649+
int min = int.MaxValue;
650+
foreach(var logo in logos)
648651
{
649-
PackageVersion.Windows8, new List<int>
652+
653+
var imageStream = File.OpenRead(logo);
654+
var decoder = BitmapDecoder.Create(imageStream, BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.None);
655+
var height = decoder.Frames[0].PixelHeight;
656+
var width = decoder.Frames[0].PixelWidth;
657+
int pixelCountDiff = Math.Abs(height * width - 1936); // 44*44=1936
658+
if(pixelCountDiff < min)
650659
{
651-
100
660+
// try to find the closest to 44x44 logo
661+
closest = logo;
662+
if (pixelCountDiff == 0)
663+
break; // found 44x44
664+
min = pixelCountDiff;
652665
}
653666
}
654-
};
655667

656-
if (scaleFactors.ContainsKey(Package.Version))
657-
{
658-
foreach (var factor in scaleFactors[Package.Version])
668+
selected = closest;
669+
if (!string.IsNullOrEmpty(selected))
659670
{
660-
paths.Add($"{prefix}.scale-{factor}{extension}");
671+
return selected;
672+
}
673+
else
674+
{
675+
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
676+
$"|{UserModelId} can't find logo uri for {uri} in package location (can't find specified logo): {Package.Location}", new FileNotFoundException());
677+
return string.Empty;
661678
}
662-
}
663-
664-
var selected = paths.FirstOrDefault(File.Exists);
665-
if (!string.IsNullOrEmpty(selected))
666-
{
667-
return selected;
668679
}
669680
else
670681
{
671682
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
672-
$"|{UserModelId} can't find logo uri for {uri} in package location: {Package.Location}", new FileNotFoundException());
683+
$"|Unable to find extension from {uri} for {UserModelId} " +
684+
$"in package location {Package.Location}", new FileNotFoundException());
673685
return string.Empty;
674686
}
675687
}
676-
else
677-
{
678-
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
679-
$"|Unable to find extension from {uri} for {UserModelId} " +
680-
$"in package location {Package.Location}", new FileNotFoundException());
681-
return string.Empty;
682-
}
683688
}
684689

685690

686691
public ImageSource Logo()
687692
{
688693
var logo = ImageFromPath(LogoPath);
689-
var plated = PlatedImage(logo);
694+
var plated = PlatedImage(logo); // TODO: maybe get plated directly from app package?
690695

691696
// todo magic! temp fix for cross thread object
692697
plated.Freeze();

appveyor.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ init:
77
- sc config WSearch start= auto # Starts Windows Search service- Needed for running ExplorerTest
88
- net start WSearch
99

10+
cache:
11+
- '%USERPROFILE%\.nuget\packages -> **.sln, **.csproj' # preserve nuget folder (packages) unless the solution or projects change
12+
13+
1014
assembly_info:
1115
patch: true
1216
file: SolutionAssemblyInfo.cs
@@ -28,7 +32,9 @@ before_build:
2832
build:
2933
project: Flow.Launcher.sln
3034
verbosity: minimal
31-
after_build:
35+
test_script:
36+
- dotnet test --no-build -c Release
37+
after_test:
3238
- ps: .\Scripts\post_build.ps1
3339

3440
artifacts:

0 commit comments

Comments
 (0)