mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #967 from Flow-Launcher/filewatcher
Auto re-index for Program and Bookmark plugins
This commit is contained in:
commit
c74eafb9d5
8 changed files with 333 additions and 123 deletions
|
|
@ -21,6 +21,8 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
if (!File.Exists(bookmarkPath))
|
if (!File.Exists(bookmarkPath))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Main.RegisterBookmarkFile(bookmarkPath);
|
||||||
|
|
||||||
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
||||||
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
||||||
}
|
}
|
||||||
|
|
@ -31,6 +33,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
{
|
{
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
return new();
|
return new();
|
||||||
|
|
||||||
var bookmarks = new List<Bookmark>();
|
var bookmarks = new List<Bookmark>();
|
||||||
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
||||||
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
private const string queryAllBookmarks = @"SELECT moz_places.url, moz_bookmarks.title
|
private const string queryAllBookmarks = @"SELECT moz_places.url, moz_bookmarks.title
|
||||||
FROM moz_places
|
FROM moz_places
|
||||||
INNER JOIN moz_bookmarks ON (
|
INNER JOIN moz_bookmarks ON (
|
||||||
moz_bookmarks.fk NOT NULL AND moz_bookmarks.fk = moz_places.id
|
moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id
|
||||||
)
|
)
|
||||||
ORDER BY moz_places.visit_count DESC
|
ORDER BY moz_places.visit_count DESC
|
||||||
";
|
";
|
||||||
|
|
@ -30,20 +30,20 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
|
|
||||||
var bookmarkList = new List<Bookmark>();
|
var bookmarkList = new List<Bookmark>();
|
||||||
|
|
||||||
|
Main.RegisterBookmarkFile(PlacesPath);
|
||||||
|
|
||||||
// create the connection string and init the connection
|
// create the connection string and init the connection
|
||||||
string dbPath = string.Format(dbPathFormat, PlacesPath);
|
string dbPath = string.Format(dbPathFormat, PlacesPath);
|
||||||
using (var dbConnection = new SQLiteConnection(dbPath))
|
using var dbConnection = new SQLiteConnection(dbPath);
|
||||||
{
|
// Open connection to the database file and execute the query
|
||||||
// Open connection to the database file and execute the query
|
dbConnection.Open();
|
||||||
dbConnection.Open();
|
var reader = new SQLiteCommand(queryAllBookmarks, dbConnection).ExecuteReader();
|
||||||
var reader = new SQLiteCommand(queryAllBookmarks, dbConnection).ExecuteReader();
|
|
||||||
|
|
||||||
// return results in List<Bookmark> format
|
// return results in List<Bookmark> format
|
||||||
bookmarkList = reader.Select(
|
bookmarkList = reader.Select(
|
||||||
x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||||
x["url"].ToString())
|
x["url"].ToString())
|
||||||
).ToList();
|
).ToList();
|
||||||
}
|
|
||||||
|
|
||||||
return bookmarkList;
|
return bookmarkList;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,19 @@ using Flow.Launcher.Plugin.BrowserBookmark.Commands;
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Views;
|
using Flow.Launcher.Plugin.BrowserBookmark.Views;
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
{
|
{
|
||||||
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu
|
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu, IDisposable
|
||||||
{
|
{
|
||||||
private PluginInitContext context;
|
private PluginInitContext context;
|
||||||
|
|
||||||
private List<Bookmark> cachedBookmarks = new List<Bookmark>();
|
private List<Bookmark> cachedBookmarks = new List<Bookmark>();
|
||||||
|
|
||||||
private Settings _settings { get; set;}
|
private Settings _settings { get; set; }
|
||||||
|
|
||||||
public void Init(PluginInitContext context)
|
public void Init(PluginInitContext context)
|
||||||
{
|
{
|
||||||
|
|
@ -27,6 +30,8 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||||
|
|
||||||
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
||||||
|
|
||||||
|
_ = MonitorRefreshQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Result> Query(Query query)
|
public List<Result> Query(Query query)
|
||||||
|
|
@ -52,7 +57,10 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
ContextData = new BookmarkAttributes { Url = c.Url }
|
ContextData = new BookmarkAttributes
|
||||||
|
{
|
||||||
|
Url = c.Url
|
||||||
|
}
|
||||||
}).Where(r => r.Score > 0);
|
}).Where(r => r.Score > 0);
|
||||||
return returnList.ToList();
|
return returnList.ToList();
|
||||||
}
|
}
|
||||||
|
|
@ -69,11 +77,64 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
context.API.OpenUrl(c.Url);
|
context.API.OpenUrl(c.Url);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
ContextData = new BookmarkAttributes { Url = c.Url }
|
ContextData = new BookmarkAttributes
|
||||||
|
{
|
||||||
|
Url = c.Url
|
||||||
|
}
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Channel<byte> refreshQueue = Channel.CreateBounded<byte>(1);
|
||||||
|
|
||||||
|
private async Task MonitorRefreshQueue()
|
||||||
|
{
|
||||||
|
var reader = refreshQueue.Reader;
|
||||||
|
while (await reader.WaitToReadAsync())
|
||||||
|
{
|
||||||
|
await Task.Delay(2000);
|
||||||
|
if (reader.TryRead(out _))
|
||||||
|
{
|
||||||
|
ReloadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly List<FileSystemWatcher> Watchers = new();
|
||||||
|
|
||||||
|
internal static void RegisterBookmarkFile(string path)
|
||||||
|
{
|
||||||
|
var directory = Path.GetDirectoryName(path);
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
|
return;
|
||||||
|
var watcher = new FileSystemWatcher(directory!);
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var fileName = Path.GetFileName(path);
|
||||||
|
watcher.Filter = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher.NotifyFilter = NotifyFilters.FileName |
|
||||||
|
NotifyFilters.LastAccess |
|
||||||
|
NotifyFilters.LastWrite |
|
||||||
|
NotifyFilters.Size;
|
||||||
|
|
||||||
|
watcher.Changed += static (_, _) =>
|
||||||
|
{
|
||||||
|
refreshQueue.Writer.TryWrite(default);
|
||||||
|
};
|
||||||
|
|
||||||
|
watcher.Renamed += static (_, _) =>
|
||||||
|
{
|
||||||
|
refreshQueue.Writer.TryWrite(default);
|
||||||
|
};
|
||||||
|
|
||||||
|
watcher.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
Watchers.Add(watcher);
|
||||||
|
}
|
||||||
|
|
||||||
public void ReloadData()
|
public void ReloadData()
|
||||||
{
|
{
|
||||||
cachedBookmarks.Clear();
|
cachedBookmarks.Clear();
|
||||||
|
|
@ -98,7 +159,8 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
|
|
||||||
public List<Result> LoadContextMenus(Result selectedResult)
|
public List<Result> LoadContextMenus(Result selectedResult)
|
||||||
{
|
{
|
||||||
return new List<Result>() {
|
return new List<Result>()
|
||||||
|
{
|
||||||
new Result
|
new Result
|
||||||
{
|
{
|
||||||
Title = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"),
|
Title = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"),
|
||||||
|
|
@ -114,7 +176,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
var message = "Failed to set url in clipboard";
|
var message = "Failed to set url in clipboard";
|
||||||
Log.Exception("Main",message, e, "LoadContextMenus");
|
Log.Exception("Main", message, e, "LoadContextMenus");
|
||||||
|
|
||||||
context.API.ShowMsg(message);
|
context.API.ShowMsg(message);
|
||||||
|
|
||||||
|
|
@ -122,12 +184,20 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
IcoPath = "Images\\copylink.png"
|
IcoPath = "Images\\copylink.png"
|
||||||
}};
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class BookmarkAttributes
|
internal class BookmarkAttributes
|
||||||
{
|
{
|
||||||
internal string Url { get; set; }
|
internal string Url { get; set; }
|
||||||
}
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var watcher in Watchers)
|
||||||
|
{
|
||||||
|
watcher.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"Name": "Browser Bookmarks",
|
"Name": "Browser Bookmarks",
|
||||||
"Description": "Search your browser bookmarks",
|
"Description": "Search your browser bookmarks",
|
||||||
"Author": "qianlifeng, Ioannis G.",
|
"Author": "qianlifeng, Ioannis G.",
|
||||||
"Version": "1.6.3",
|
"Version": "1.7.0",
|
||||||
"Language": "csharp",
|
"Language": "csharp",
|
||||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||||
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
|
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,12 @@ using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program
|
namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, ISavable, IAsyncReloadable
|
public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, ISavable, IAsyncReloadable, IDisposable
|
||||||
{
|
{
|
||||||
internal static Win32[] _win32s { get; set; }
|
internal static Win32[] _win32s { get; set; }
|
||||||
internal static UWP.Application[] _uwps { get; set; }
|
internal static UWP.Application[] _uwps { get; set; }
|
||||||
internal static Settings _settings { get; set; }
|
internal static Settings _settings { get; set; }
|
||||||
|
|
||||||
private static bool IsStartupIndexProgramsRequired => _settings.LastIndexTime.AddDays(3) < DateTime.Today;
|
|
||||||
|
|
||||||
internal static PluginInitContext Context { get; private set; }
|
internal static PluginInitContext Context { get; private set; }
|
||||||
|
|
||||||
|
|
@ -51,29 +50,25 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
|
|
||||||
public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
|
public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (IsStartupIndexProgramsRequired)
|
|
||||||
_ = IndexProgramsAsync();
|
|
||||||
|
|
||||||
var result = await cache.GetOrCreateAsync(query.Search, async entry =>
|
var result = await cache.GetOrCreateAsync(query.Search, async entry =>
|
||||||
{
|
{
|
||||||
var resultList = await Task.Run(() =>
|
var resultList = await Task.Run(() =>
|
||||||
_win32s.Cast<IProgram>()
|
_win32s.Cast<IProgram>()
|
||||||
.Concat(_uwps)
|
.Concat(_uwps)
|
||||||
.AsParallel()
|
.AsParallel()
|
||||||
.WithCancellation(token)
|
.WithCancellation(token)
|
||||||
.Where(p => p.Enabled)
|
.Where(p => p.Enabled)
|
||||||
.Select(p => p.Result(query.Search, Context.API))
|
.Select(p => p.Result(query.Search, Context.API))
|
||||||
.Where(r => r?.Score > 0)
|
.Where(r => r?.Score > 0)
|
||||||
.ToList());
|
.ToList());
|
||||||
|
|
||||||
resultList = resultList.Any() ? resultList : emptyResults;
|
resultList = resultList.Any() ? resultList : emptyResults;
|
||||||
|
|
||||||
entry.SetSize(resultList.Count);
|
entry.SetSize(resultList.Count);
|
||||||
entry.SetSlidingExpiration(TimeSpan.FromHours(8));
|
entry.SetSlidingExpiration(TimeSpan.FromHours(8));
|
||||||
|
|
||||||
return resultList;
|
return resultList;
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -84,62 +79,55 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
|
|
||||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||||
|
|
||||||
await Task.Yield();
|
|
||||||
|
|
||||||
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
|
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
|
||||||
{
|
{
|
||||||
_win32Storage = new BinaryStorage<Win32[]>("Win32");
|
_win32Storage = new BinaryStorage<Win32[]>("Win32");
|
||||||
_win32s = _win32Storage.TryLoad(new Win32[] { });
|
_win32s = _win32Storage.TryLoad(new Win32[]
|
||||||
|
{
|
||||||
|
});
|
||||||
_uwpStorage = new BinaryStorage<UWP.Application[]>("UWP");
|
_uwpStorage = new BinaryStorage<UWP.Application[]>("UWP");
|
||||||
_uwps = _uwpStorage.TryLoad(new UWP.Application[] { });
|
_uwps = _uwpStorage.TryLoad(new UWP.Application[]
|
||||||
|
{
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Length}>");
|
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Length}>");
|
||||||
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Length}>");
|
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Length}>");
|
||||||
|
|
||||||
|
bool cacheEmpty = !_win32s.Any() && !_uwps.Any();
|
||||||
bool indexedWinApps = false;
|
|
||||||
bool indexedUWPApps = false;
|
|
||||||
|
|
||||||
var a = Task.Run(() =>
|
var a = Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (IsStartupIndexProgramsRequired || !_win32s.Any())
|
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32Programs);
|
||||||
{
|
|
||||||
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32Programs);
|
|
||||||
indexedWinApps = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var b = Task.Run(() =>
|
var b = Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (IsStartupIndexProgramsRequired || !_uwps.Any())
|
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms);
|
||||||
{
|
|
||||||
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms);
|
|
||||||
indexedUWPApps = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var indexTask = Task.WhenAll(a, b).ContinueWith(t =>
|
if (cacheEmpty)
|
||||||
{
|
await Task.WhenAll(a, b);
|
||||||
if (indexedWinApps && indexedUWPApps)
|
|
||||||
_settings.LastIndexTime = DateTime.Today;
|
|
||||||
}, TaskScheduler.Current);
|
|
||||||
|
|
||||||
if (!(_win32s.Any() && _uwps.Any()))
|
Win32.WatchProgramUpdate(_settings);
|
||||||
await indexTask;
|
UWP.WatchPackageChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void IndexWin32Programs()
|
public static void IndexWin32Programs()
|
||||||
{
|
{
|
||||||
var win32S = Win32.All(_settings);
|
var win32S = Win32.All(_settings);
|
||||||
_win32s = win32S;
|
_win32s = win32S;
|
||||||
|
ResetCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void IndexUwpPrograms()
|
public static void IndexUwpPrograms()
|
||||||
{
|
{
|
||||||
var windows10 = new Version(10, 0);
|
var windows10 = new Version(10, 0);
|
||||||
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
||||||
var applications = support ? UWP.All() : new UWP.Application[] { };
|
var applications = support ? UWP.All() : new UWP.Application[]
|
||||||
|
{
|
||||||
|
};
|
||||||
_uwps = applications;
|
_uwps = applications;
|
||||||
|
ResetCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task IndexProgramsAsync()
|
public static async Task IndexProgramsAsync()
|
||||||
|
|
@ -147,7 +135,6 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
var t1 = Task.Run(IndexWin32Programs);
|
var t1 = Task.Run(IndexWin32Programs);
|
||||||
var t2 = Task.Run(IndexUwpPrograms);
|
var t2 = Task.Run(IndexUwpPrograms);
|
||||||
await Task.WhenAll(t1, t2).ConfigureAwait(false);
|
await Task.WhenAll(t1, t2).ConfigureAwait(false);
|
||||||
ResetCache();
|
|
||||||
_settings.LastIndexTime = DateTime.Today;
|
_settings.LastIndexTime = DateTime.Today;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,13 +196,11 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
_uwps.Where(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
|
_uwps.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
|
||||||
.FirstOrDefault()
|
|
||||||
.Enabled = false;
|
.Enabled = false;
|
||||||
|
|
||||||
if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
_win32s.Where(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
|
_win32s.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
|
||||||
.FirstOrDefault()
|
|
||||||
.Enabled = false;
|
.Enabled = false;
|
||||||
|
|
||||||
_settings.DisabledProgramSources
|
_settings.DisabledProgramSources
|
||||||
|
|
@ -248,5 +233,9 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
await IndexProgramsAsync();
|
await IndexProgramsAsync();
|
||||||
}
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Win32.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ using Flow.Launcher.Plugin.Program.Logger;
|
||||||
using Rect = System.Windows.Rect;
|
using Rect = System.Windows.Rect;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Programs
|
namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +80,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
var e = Marshal.GetExceptionForHR((int)hResult);
|
var e = Marshal.GetExceptionForHR((int)hResult);
|
||||||
ProgramLogger.LogException($"|UWP|InitializeAppInfo|{path}" +
|
ProgramLogger.LogException($"|UWP|InitializeAppInfo|{path}" +
|
||||||
"|Error caused while trying to get the details of the UWP program", e);
|
"|Error caused while trying to get the details of the UWP program", e);
|
||||||
|
|
||||||
Apps = new List<Application>().ToArray();
|
Apps = new List<Application>().ToArray();
|
||||||
}
|
}
|
||||||
|
|
@ -89,30 +91,28 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
|
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
|
||||||
private string[] XmlNamespaces(string path)
|
private string[] XmlNamespaces(string path)
|
||||||
{
|
{
|
||||||
XDocument z = XDocument.Load(path);
|
XDocument z = XDocument.Load(path);
|
||||||
if (z.Root != null)
|
if (z.Root != null)
|
||||||
{
|
{
|
||||||
var namespaces = z.Root.Attributes().
|
var namespaces = z.Root.Attributes().Where(a => a.IsNamespaceDeclaration).GroupBy(
|
||||||
Where(a => a.IsNamespaceDeclaration).
|
a => a.Name.Namespace == XNamespace.None ? string.Empty : a.Name.LocalName,
|
||||||
GroupBy(
|
a => XNamespace.Get(a.Value)
|
||||||
a => a.Name.Namespace == XNamespace.None ? string.Empty : a.Name.LocalName,
|
).Select(
|
||||||
a => XNamespace.Get(a.Value)
|
g => g.First().ToString()
|
||||||
).Select(
|
).ToArray();
|
||||||
g => g.First().ToString()
|
|
||||||
).ToArray();
|
|
||||||
return namespaces;
|
return namespaces;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramLogger.LogException($"|UWP|XmlNamespaces|{path}" +
|
ProgramLogger.LogException($"|UWP|XmlNamespaces|{path}" +
|
||||||
$"|Error occured while trying to get the XML from {path}", new ArgumentNullException());
|
$"|Error occured while trying to get the XML from {path}", new ArgumentNullException());
|
||||||
|
|
||||||
return new string[] { };
|
return new string[]
|
||||||
|
{
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,9 +120,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
var versionFromNamespace = new Dictionary<string, PackageVersion>
|
var versionFromNamespace = new Dictionary<string, PackageVersion>
|
||||||
{
|
{
|
||||||
{"http://schemas.microsoft.com/appx/manifest/foundation/windows10", PackageVersion.Windows10},
|
{
|
||||||
{"http://schemas.microsoft.com/appx/2013/manifest", PackageVersion.Windows81},
|
"http://schemas.microsoft.com/appx/manifest/foundation/windows10", PackageVersion.Windows10
|
||||||
{"http://schemas.microsoft.com/appx/2010/manifest", PackageVersion.Windows8},
|
},
|
||||||
|
{
|
||||||
|
"http://schemas.microsoft.com/appx/2013/manifest", PackageVersion.Windows81
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"http://schemas.microsoft.com/appx/2010/manifest", PackageVersion.Windows8
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var n in versionFromNamespace.Keys)
|
foreach (var n in versionFromNamespace.Keys)
|
||||||
|
|
@ -135,8 +141,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramLogger.LogException($"|UWP|XmlNamespaces|{Location}" +
|
ProgramLogger.LogException($"|UWP|XmlNamespaces|{Location}" +
|
||||||
"|Trying to get the package version of the UWP program, but a unknown UWP appmanifest version "
|
"|Trying to get the package version of the UWP program, but a unknown UWP appmanifest version "
|
||||||
+ $"{FullName} from location {Location} is returned.", new FormatException());
|
+ $"{FullName} from location {Location} is returned.", new FormatException());
|
||||||
|
|
||||||
Version = PackageVersion.Unknown;
|
Version = PackageVersion.Unknown;
|
||||||
}
|
}
|
||||||
|
|
@ -171,15 +177,17 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
var updatedListWithoutDisabledApps = applications
|
var updatedListWithoutDisabledApps = applications
|
||||||
.Where(t1 => !Main._settings.DisabledProgramSources
|
.Where(t1 => !Main._settings.DisabledProgramSources
|
||||||
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
||||||
.Select(x => x);
|
.Select(x => x);
|
||||||
|
|
||||||
return updatedListWithoutDisabledApps.ToArray();
|
return updatedListWithoutDisabledApps.ToArray();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Application[] { };
|
return new Application[]
|
||||||
|
{
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,7 +223,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ProgramLogger.LogException("UWP", "CurrentUserPackages", $"id", "An unexpected error occured and "
|
ProgramLogger.LogException("UWP", "CurrentUserPackages", $"id", "An unexpected error occured and "
|
||||||
+ $"unable to verify if package is valid", e);
|
+ $"unable to verify if package is valid", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,7 +233,42 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Package[] { };
|
return new Package[]
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Channel<byte> PackageChangeChannel = Channel.CreateBounded<byte>(1);
|
||||||
|
|
||||||
|
public static async Task WatchPackageChange()
|
||||||
|
{
|
||||||
|
if (Environment.OSVersion.Version.Major >= 10)
|
||||||
|
{
|
||||||
|
var catalog = PackageCatalog.OpenForCurrentUser();
|
||||||
|
catalog.PackageInstalling += (_, args) =>
|
||||||
|
{
|
||||||
|
if (args.IsComplete)
|
||||||
|
PackageChangeChannel.Writer.TryWrite(default);
|
||||||
|
};
|
||||||
|
catalog.PackageUninstalling += (_, args) =>
|
||||||
|
{
|
||||||
|
if (args.IsComplete)
|
||||||
|
PackageChangeChannel.Writer.TryWrite(default);
|
||||||
|
};
|
||||||
|
catalog.PackageUpdating += (_, args) =>
|
||||||
|
{
|
||||||
|
if (args.IsComplete)
|
||||||
|
PackageChangeChannel.Writer.TryWrite(default);
|
||||||
|
};
|
||||||
|
|
||||||
|
while (await PackageChangeChannel.Reader.WaitToReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await Task.Delay(3000).ConfigureAwait(false);
|
||||||
|
PackageChangeChannel.Reader.TryRead(out _);
|
||||||
|
await Task.Run(Main.IndexUwpPrograms);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,7 +368,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
e.SpecialKeyState.ShiftPressed &&
|
e.SpecialKeyState.ShiftPressed &&
|
||||||
!e.SpecialKeyState.AltPressed &&
|
!e.SpecialKeyState.AltPressed &&
|
||||||
!e.SpecialKeyState.WinPressed
|
!e.SpecialKeyState.WinPressed
|
||||||
);
|
);
|
||||||
|
|
||||||
if (elevated && CanRunElevated)
|
if (elevated && CanRunElevated)
|
||||||
{
|
{
|
||||||
|
|
@ -358,14 +401,12 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
new Result
|
new Result
|
||||||
{
|
{
|
||||||
Title = api.GetTranslation("flowlauncher_plugin_program_open_containing_folder"),
|
Title = api.GetTranslation("flowlauncher_plugin_program_open_containing_folder"),
|
||||||
|
|
||||||
Action = _ =>
|
Action = _ =>
|
||||||
{
|
{
|
||||||
Main.Context.API.OpenDirectory(Package.Location);
|
Main.Context.API.OpenDirectory(Package.Location);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
IcoPath = "Images/folder.png"
|
IcoPath = "Images/folder.png"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -414,8 +455,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
var info = new ProcessStartInfo(command)
|
var info = new ProcessStartInfo(command)
|
||||||
{
|
{
|
||||||
UseShellExecute = true,
|
UseShellExecute = true, Verb = "runas",
|
||||||
Verb = "runas",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Main.StartProcess(Process.Start, info);
|
Main.StartProcess(Process.Start, info);
|
||||||
|
|
@ -492,7 +532,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramLogger.LogException($"|UWP|ResourceFromPri|{Package.Location}|Can't load null or empty result "
|
ProgramLogger.LogException($"|UWP|ResourceFromPri|{Package.Location}|Can't load null or empty result "
|
||||||
+ $"pri {source} in uwp location {Package.Location}", new NullReferenceException());
|
+ $"pri {source} in uwp location {Package.Location}", new NullReferenceException());
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -532,9 +572,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
var logoKeyFromVersion = new Dictionary<PackageVersion, string>
|
var logoKeyFromVersion = new Dictionary<PackageVersion, string>
|
||||||
{
|
{
|
||||||
{ PackageVersion.Windows10, "Square44x44Logo" },
|
{
|
||||||
{ PackageVersion.Windows81, "Square30x30Logo" },
|
PackageVersion.Windows10, "Square44x44Logo"
|
||||||
{ PackageVersion.Windows8, "SmallLogo" },
|
},
|
||||||
|
{
|
||||||
|
PackageVersion.Windows81, "Square30x30Logo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PackageVersion.Windows8, "SmallLogo"
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if (logoKeyFromVersion.ContainsKey(Package.Version))
|
if (logoKeyFromVersion.ContainsKey(Package.Version))
|
||||||
{
|
{
|
||||||
|
|
@ -571,14 +617,40 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
var end = path.Length - extension.Length;
|
var end = path.Length - extension.Length;
|
||||||
var prefix = path.Substring(0, end);
|
var prefix = path.Substring(0, end);
|
||||||
var paths = new List<string> { path };
|
var paths = new List<string>
|
||||||
|
{
|
||||||
|
path
|
||||||
|
};
|
||||||
|
|
||||||
var scaleFactors = new Dictionary<PackageVersion, List<int>>
|
var scaleFactors = new Dictionary<PackageVersion, List<int>>
|
||||||
{
|
{
|
||||||
// scale factors on win10: https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets#asset-size-tables,
|
// scale factors on win10: https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets#asset-size-tables,
|
||||||
{ PackageVersion.Windows10, new List<int> { 100, 125, 150, 200, 400 } },
|
{
|
||||||
{ PackageVersion.Windows81, new List<int> { 100, 120, 140, 160, 180 } },
|
PackageVersion.Windows10, new List<int>
|
||||||
{ PackageVersion.Windows8, new List<int> { 100 } }
|
{
|
||||||
|
100,
|
||||||
|
125,
|
||||||
|
150,
|
||||||
|
200,
|
||||||
|
400
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PackageVersion.Windows81, new List<int>
|
||||||
|
{
|
||||||
|
100,
|
||||||
|
120,
|
||||||
|
140,
|
||||||
|
160,
|
||||||
|
180
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PackageVersion.Windows8, new List<int>
|
||||||
|
{
|
||||||
|
100
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (scaleFactors.ContainsKey(Package.Version))
|
if (scaleFactors.ContainsKey(Package.Version))
|
||||||
|
|
@ -597,15 +669,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
|
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
|
||||||
$"|{UserModelId} can't find logo uri for {uri} in package location: {Package.Location}", new FileNotFoundException());
|
$"|{UserModelId} can't find logo uri for {uri} in package location: {Package.Location}", new FileNotFoundException());
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
|
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
|
||||||
$"|Unable to find extension from {uri} for {UserModelId} " +
|
$"|Unable to find extension from {uri} for {UserModelId} " +
|
||||||
$"in package location {Package.Location}", new FileNotFoundException());
|
$"in package location {Package.Location}", new FileNotFoundException());
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -632,8 +704,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramLogger.LogException($"|UWP|ImageFromPath|{(string.IsNullOrEmpty(path) ? "Not Avaliable" : path)}" +
|
ProgramLogger.LogException($"|UWP|ImageFromPath|{(string.IsNullOrEmpty(path) ? "Not Avaliable" : path)}" +
|
||||||
$"|Unable to get logo for {UserModelId} from {path} and" +
|
$"|Unable to get logo for {UserModelId} from {path} and" +
|
||||||
$" located in {Package.Location}", new FileNotFoundException());
|
$" located in {Package.Location}", new FileNotFoundException());
|
||||||
return new BitmapImage(new Uri(Constant.MissingImgIcon));
|
return new BitmapImage(new Uri(Constant.MissingImgIcon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -681,8 +753,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramLogger.LogException($"|UWP|PlatedImage|{Package.Location}" +
|
ProgramLogger.LogException($"|UWP|PlatedImage|{Package.Location}" +
|
||||||
$"|Unable to convert background string {BackgroundColor} " +
|
$"|Unable to convert background string {BackgroundColor} " +
|
||||||
$"to color for {Package.Location}", new InvalidOperationException());
|
$"to color for {Package.Location}", new InvalidOperationException());
|
||||||
|
|
||||||
return new BitmapImage(new Uri(Constant.MissingImgIcon));
|
return new BitmapImage(new Uri(Constant.MissingImgIcon));
|
||||||
}
|
}
|
||||||
|
|
@ -727,5 +799,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||||
private static extern Hresult SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf,
|
private static extern Hresult SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf,
|
||||||
IntPtr ppvReserved);
|
IntPtr ppvReserved);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,11 @@ using Flow.Launcher.Plugin.Program.Logger;
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Programs
|
namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
|
|
@ -109,7 +111,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
c.SpecialKeyState.ShiftPressed &&
|
c.SpecialKeyState.ShiftPressed &&
|
||||||
!c.SpecialKeyState.AltPressed &&
|
!c.SpecialKeyState.AltPressed &&
|
||||||
!c.SpecialKeyState.WinPressed
|
!c.SpecialKeyState.WinPressed
|
||||||
);
|
);
|
||||||
|
|
||||||
var info = new ProcessStartInfo
|
var info = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
|
|
@ -194,6 +196,9 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<FileSystemWatcher> Watchers = new List<FileSystemWatcher>();
|
||||||
|
|
||||||
|
|
||||||
private static Win32 Win32Program(string path)
|
private static Win32 Win32Program(string path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -216,7 +221,10 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
|
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
|
||||||
$"|Permission denied when trying to load the program from {path}", e);
|
$"|Permission denied when trying to load the program from {path}", e);
|
||||||
|
|
||||||
return new Win32() { Valid = false, Enabled = false };
|
return new Win32()
|
||||||
|
{
|
||||||
|
Valid = false, Enabled = false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,7 +302,10 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
|
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
|
||||||
$"|Permission denied when trying to load the program from {path}", e);
|
$"|Permission denied when trying to load the program from {path}", e);
|
||||||
|
|
||||||
return new Win32() { Valid = false, Enabled = false };
|
return new Win32()
|
||||||
|
{
|
||||||
|
Valid = false, Enabled = false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,8 +316,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
|
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
|
||||||
{
|
{
|
||||||
IgnoreInaccessible = true,
|
IgnoreInaccessible = true, RecurseSubdirectories = true
|
||||||
RecurseSubdirectories = true
|
|
||||||
}).Where(x => suffixes.Contains(Extension(x)));
|
}).Where(x => suffixes.Contains(Extension(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -545,5 +555,70 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
return UniqueIdentifier == other.UniqueIdentifier;
|
return UniqueIdentifier == other.UniqueIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<string> GetStartMenuPaths()
|
||||||
|
{
|
||||||
|
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
||||||
|
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
directory1, directory2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WatchProgramUpdate(Settings settings)
|
||||||
|
{
|
||||||
|
var paths = new List<string>();
|
||||||
|
if (settings.EnableStartMenuSource)
|
||||||
|
paths.AddRange(GetStartMenuPaths());
|
||||||
|
|
||||||
|
paths.AddRange(from source in settings.ProgramSources where source.Enabled select source.Location);
|
||||||
|
|
||||||
|
foreach (var directory in from path in paths where Directory.Exists(path) select path)
|
||||||
|
{
|
||||||
|
WatchDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = Task.Run(MonitorDirectoryChangeAsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Channel<byte> indexQueue = Channel.CreateBounded<byte>(1);
|
||||||
|
|
||||||
|
public static async Task MonitorDirectoryChangeAsync()
|
||||||
|
{
|
||||||
|
var reader = indexQueue.Reader;
|
||||||
|
while (await reader.WaitToReadAsync())
|
||||||
|
{
|
||||||
|
await Task.Delay(500);
|
||||||
|
while (reader.TryRead(out _))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
await Task.Run(Main.IndexWin32Programs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WatchDirectory(string directory)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Path Not Exist");
|
||||||
|
}
|
||||||
|
var watcher = new FileSystemWatcher(directory);
|
||||||
|
|
||||||
|
watcher.Created += static (_, _) => indexQueue.Writer.TryWrite(default);
|
||||||
|
watcher.Deleted += static (_, _) => indexQueue.Writer.TryWrite(default);
|
||||||
|
watcher.EnableRaisingEvents = true;
|
||||||
|
watcher.IncludeSubdirectories = true;
|
||||||
|
|
||||||
|
Watchers.Add(watcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var fileSystemWatcher in Watchers)
|
||||||
|
{
|
||||||
|
fileSystemWatcher.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"Name": "Program",
|
"Name": "Program",
|
||||||
"Description": "Search programs in Flow.Launcher",
|
"Description": "Search programs in Flow.Launcher",
|
||||||
"Author": "qianlifeng",
|
"Author": "qianlifeng",
|
||||||
"Version": "1.8.2",
|
"Version": "1.9.0",
|
||||||
"Language": "csharp",
|
"Language": "csharp",
|
||||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||||
"ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",
|
"ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue