mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Add local favicon load
This commit is contained in:
parent
e28a69ca91
commit
5481a6aa43
21 changed files with 338 additions and 53 deletions
|
|
@ -57,6 +57,7 @@
|
|||
<PackageReference Include="FSharp.Core" Version="9.0.201" />
|
||||
<PackageReference Include="Meziantou.Framework.Win32.Jobs" Version="3.4.0" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" />
|
||||
<PackageReference Include="StreamJsonRpc" Version="2.21.10" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="NLog" Version="4.7.10" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<!--ToolGood.Words.Pinyin v3.0.2.6 results in high memory usage when search with pinyin is enabled-->
|
||||
<!--Bumping to it or higher needs to test and ensure this is no longer a problem-->
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@
|
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -104,6 +104,7 @@
|
|||
<PackageReference Include="NHotkey.Wpf" Version="3.0.0" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
||||
<PackageReference Include="SemanticVersioning" Version="3.0.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.12.1" />
|
||||
<PackageReference Include="VirtualizingWrapPanel" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,24 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using System;
|
||||
using System.Data.SQLite;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
||||
{
|
||||
private readonly string _faviconCacheDir;
|
||||
|
||||
protected ChromiumBookmarkLoader()
|
||||
{
|
||||
_faviconCacheDir = Path.Combine(
|
||||
Path.GetDirectoryName(typeof(ChromiumBookmarkLoader).Assembly.Location),
|
||||
"FaviconCache");
|
||||
Directory.CreateDirectory(_faviconCacheDir);
|
||||
}
|
||||
|
||||
public abstract List<Bookmark> GetBookmarks();
|
||||
|
||||
protected List<Bookmark> LoadBookmarks(string browserDataPath, string name)
|
||||
|
|
@ -22,10 +35,30 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
|||
if (!File.Exists(bookmarkPath))
|
||||
continue;
|
||||
|
||||
Main.RegisterBookmarkFile(bookmarkPath);
|
||||
// Register bookmark file monitoring (direct call to Main.RegisterBookmarkFile)
|
||||
try
|
||||
{
|
||||
if (File.Exists(bookmarkPath))
|
||||
{
|
||||
//Main.RegisterBookmarkFile(bookmarkPath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to register bookmark file monitoring: {bookmarkPath}", ex);
|
||||
}
|
||||
|
||||
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
||||
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
||||
var profileBookmarks = LoadBookmarksFromFile(bookmarkPath, source);
|
||||
|
||||
// Load favicons after loading bookmarks
|
||||
var faviconDbPath = Path.Combine(profile, "Favicons");
|
||||
if (File.Exists(faviconDbPath))
|
||||
{
|
||||
LoadFaviconsFromDb(faviconDbPath, profileBookmarks);
|
||||
}
|
||||
|
||||
bookmarks.AddRange(profileBookmarks);
|
||||
}
|
||||
|
||||
return bookmarks;
|
||||
|
|
@ -52,8 +85,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
|||
if (folder.Value.ValueKind != JsonValueKind.Object)
|
||||
continue;
|
||||
|
||||
// Fix for Opera. It stores bookmarks slightly different than chrome. See PR and bug report for this change for details.
|
||||
// If various exceptions start to build up here consider splitting this Loader into multiple separate ones.
|
||||
// Fix for Opera. It stores bookmarks slightly different than chrome.
|
||||
if (folder.Name == "custom_root")
|
||||
EnumerateRoot(folder.Value, bookmarks, source);
|
||||
else
|
||||
|
|
@ -91,4 +123,108 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadFaviconsFromDb(string dbPath, List<Bookmark> bookmarks)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use a copy to avoid lock issues with the original file
|
||||
var tempDbPath = Path.Combine(_faviconCacheDir, $"tempfavicons_{Guid.NewGuid()}.db");
|
||||
|
||||
try
|
||||
{
|
||||
File.Copy(dbPath, tempDbPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to copy favicon DB: {dbPath}", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var connection = new SQLiteConnection($"Data Source={tempDbPath};Version=3;Read Only=True;");
|
||||
connection.Open();
|
||||
|
||||
foreach (var bookmark in bookmarks)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = bookmark.Url;
|
||||
if (string.IsNullOrEmpty(url)) continue;
|
||||
|
||||
// Extract domain from URL
|
||||
if (!Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
|
||||
continue;
|
||||
|
||||
var domain = uri.Host;
|
||||
|
||||
using var cmd = connection.CreateCommand();
|
||||
cmd.CommandText = @"
|
||||
SELECT f.id, b.image_data
|
||||
FROM favicons f
|
||||
JOIN favicon_bitmaps b ON f.id = b.icon_id
|
||||
JOIN icon_mapping m ON f.id = m.icon_id
|
||||
WHERE m.page_url LIKE @url
|
||||
ORDER BY b.width DESC
|
||||
LIMIT 1";
|
||||
|
||||
cmd.Parameters.AddWithValue("@url", $"%{domain}%");
|
||||
|
||||
using var reader = cmd.ExecuteReader();
|
||||
if (reader.Read() && !reader.IsDBNull(1))
|
||||
{
|
||||
var iconId = reader.GetInt64(0).ToString();
|
||||
var imageData = (byte[])reader["image_data"];
|
||||
|
||||
if (imageData != null && imageData.Length > 0)
|
||||
{
|
||||
var faviconPath = Path.Combine(_faviconCacheDir, $"{domain}_{iconId}.png");
|
||||
if (!File.Exists(faviconPath))
|
||||
{
|
||||
SaveBitmapData(imageData, faviconPath);
|
||||
}
|
||||
bookmark.FaviconPath = faviconPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to extract bookmark favicon: {bookmark.Url}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to connect to SQLite: {tempDbPath}", ex);
|
||||
}
|
||||
|
||||
// Delete temporary file
|
||||
try { File.Delete(tempDbPath); } catch { /* Ignore */ }
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to load favicon DB: {dbPath}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveBitmapData(byte[] imageData, string outputPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var ms = new MemoryStream(imageData);
|
||||
using var bitmap = SKBitmap.Decode(ms);
|
||||
if (bitmap != null)
|
||||
{
|
||||
using var image = SKImage.FromBitmap(bitmap);
|
||||
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
|
||||
using var fs = File.OpenWrite(outputPath);
|
||||
data.SaveTo(fs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to save image: {outputPath}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,26 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader
|
||||
{
|
||||
private readonly string _faviconCacheDir;
|
||||
|
||||
protected FirefoxBookmarkLoaderBase()
|
||||
{
|
||||
_faviconCacheDir = Path.Combine(
|
||||
Path.GetDirectoryName(typeof(FirefoxBookmarkLoaderBase).Assembly.Location),
|
||||
"FaviconCache");
|
||||
Directory.CreateDirectory(_faviconCacheDir);
|
||||
}
|
||||
|
||||
public abstract List<Bookmark> GetBookmarks();
|
||||
|
||||
// Updated query - removed favicon_id column
|
||||
private const string QueryAllBookmarks = """
|
||||
SELECT moz_places.url, moz_bookmarks.title
|
||||
FROM moz_places
|
||||
|
|
@ -20,36 +33,161 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader
|
|||
ORDER BY moz_places.visit_count DESC
|
||||
""";
|
||||
|
||||
private const string DbPathFormat = "Data Source ={0}";
|
||||
private const string DbPathFormat = "Data Source={0}";
|
||||
|
||||
protected static List<Bookmark> GetBookmarksFromPath(string placesPath)
|
||||
protected List<Bookmark> GetBookmarksFromPath(string placesPath)
|
||||
{
|
||||
// Return empty list if the places.sqlite file cannot be found
|
||||
// Variable to store bookmark list
|
||||
var bookmarks = new List<Bookmark>();
|
||||
|
||||
// Return empty list if places.sqlite file doesn't exist
|
||||
if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath))
|
||||
return new List<Bookmark>();
|
||||
return bookmarks;
|
||||
|
||||
Main.RegisterBookmarkFile(placesPath);
|
||||
try
|
||||
{
|
||||
// Try to register file monitoring
|
||||
try
|
||||
{
|
||||
Main.RegisterBookmarkFile(placesPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to register Firefox bookmark file monitoring: {placesPath}", ex);
|
||||
}
|
||||
|
||||
// create the connection string and init the connection
|
||||
string dbPath = string.Format(DbPathFormat, placesPath);
|
||||
using var dbConnection = new SqliteConnection(dbPath);
|
||||
// Open connection to the database file and execute the query
|
||||
dbConnection.Open();
|
||||
var reader = new SqliteCommand(QueryAllBookmarks, dbConnection).ExecuteReader();
|
||||
// Use a copy to avoid lock issues with the original file
|
||||
var tempDbPath = Path.Combine(_faviconCacheDir, $"tempplaces_{Guid.NewGuid()}.sqlite");
|
||||
File.Copy(placesPath, tempDbPath, true);
|
||||
|
||||
// return results in List<Bookmark> format
|
||||
return reader
|
||||
.Select(
|
||||
x => new Bookmark(
|
||||
x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||
x["url"].ToString()
|
||||
// Connect to database and execute query
|
||||
string dbPath = string.Format(DbPathFormat, tempDbPath);
|
||||
using var dbConnection = new SqliteConnection(dbPath);
|
||||
dbConnection.Open();
|
||||
var reader = new SqliteCommand(QueryAllBookmarks, dbConnection).ExecuteReader();
|
||||
|
||||
// Create bookmark list
|
||||
bookmarks = reader
|
||||
.Select(
|
||||
x => new Bookmark(
|
||||
x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||
x["url"].ToString(),
|
||||
"Firefox"
|
||||
)
|
||||
)
|
||||
)
|
||||
.ToList();
|
||||
.ToList();
|
||||
|
||||
// Path to favicon database
|
||||
var faviconDbPath = Path.Combine(Path.GetDirectoryName(placesPath), "favicons.sqlite");
|
||||
if (File.Exists(faviconDbPath))
|
||||
{
|
||||
LoadFaviconsFromDb(faviconDbPath, bookmarks);
|
||||
}
|
||||
|
||||
// Delete temporary file
|
||||
try { File.Delete(tempDbPath); } catch { /* Ignore */ }
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to load Firefox bookmarks: {placesPath}", ex);
|
||||
}
|
||||
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
private void LoadFaviconsFromDb(string faviconDbPath, List<Bookmark> bookmarks)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use a copy to avoid lock issues with the original file
|
||||
var tempDbPath = Path.Combine(_faviconCacheDir, $"tempfavicons_{Guid.NewGuid()}.sqlite");
|
||||
File.Copy(faviconDbPath, tempDbPath, true);
|
||||
|
||||
string dbPath = string.Format(DbPathFormat, tempDbPath);
|
||||
using var connection = new SqliteConnection(dbPath);
|
||||
connection.Open();
|
||||
|
||||
// Get favicons based on bookmark URLs
|
||||
foreach (var bookmark in bookmarks)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(bookmark.Url))
|
||||
continue;
|
||||
|
||||
// Extract domain from URL
|
||||
if (!Uri.TryCreate(bookmark.Url, UriKind.Absolute, out Uri uri))
|
||||
continue;
|
||||
|
||||
var domain = uri.Host;
|
||||
|
||||
// Query for latest Firefox version favicon structure
|
||||
using var cmd = connection.CreateCommand();
|
||||
cmd.CommandText = @"
|
||||
SELECT i.data
|
||||
FROM moz_icons i
|
||||
JOIN moz_icons_to_pages ip ON i.id = ip.icon_id
|
||||
JOIN moz_pages_w_icons p ON ip.page_id = p.id
|
||||
WHERE p.page_url LIKE @url
|
||||
AND i.data IS NOT NULL
|
||||
ORDER BY i.width DESC -- Select largest icon available
|
||||
LIMIT 1";
|
||||
|
||||
cmd.Parameters.AddWithValue("@url", $"%{domain}%");
|
||||
|
||||
using var reader = cmd.ExecuteReader();
|
||||
if (reader.Read() && !reader.IsDBNull(0))
|
||||
{
|
||||
var imageData = (byte[])reader["data"];
|
||||
|
||||
if (imageData != null && imageData.Length > 0)
|
||||
{
|
||||
var faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}.png");
|
||||
|
||||
if (!File.Exists(faviconPath))
|
||||
{
|
||||
SaveBitmapData(imageData, faviconPath);
|
||||
}
|
||||
bookmark.FaviconPath = faviconPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to extract Firefox favicon: {bookmark.Url}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete temporary file
|
||||
try { File.Delete(tempDbPath); } catch { /* Ignore */ }
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to load Firefox favicon DB: {faviconDbPath}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveBitmapData(byte[] imageData, string outputPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var ms = new MemoryStream(imageData);
|
||||
using var bitmap = SKBitmap.Decode(ms);
|
||||
if (bitmap != null)
|
||||
{
|
||||
using var image = SKImage.FromBitmap(bitmap);
|
||||
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
|
||||
using var fs = File.OpenWrite(outputPath);
|
||||
data.SaveTo(fs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Failed to save image: {outputPath}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -77,33 +215,6 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
|||
using var sReader = new StreamReader(profileIni);
|
||||
var ini = sReader.ReadToEnd();
|
||||
|
||||
/*
|
||||
Current profiles.ini structure example as of Firefox version 69.0.1
|
||||
|
||||
[Install736426B0AF4A39CB]
|
||||
Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile
|
||||
Locked=1
|
||||
|
||||
[Profile2]
|
||||
Name=newblahprofile
|
||||
IsRelative=0
|
||||
Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code.
|
||||
|
||||
[Profile1]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=Profiles/cydum7q4.default
|
||||
Default=1
|
||||
|
||||
[Profile0]
|
||||
Name=default-release
|
||||
IsRelative=1
|
||||
Path=Profiles/7789f565.default-release
|
||||
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
Version=2
|
||||
*/
|
||||
var lines = ini.Split("\r\n").ToList();
|
||||
|
||||
var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty;
|
||||
|
|
|
|||
|
|
@ -96,6 +96,9 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.3" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex
|
|||
{
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
IcoPath = !string.IsNullOrEmpty(c.FaviconPath) && File.Exists(c.FaviconPath)
|
||||
? c.FaviconPath
|
||||
: @"Images\bookmark.png",
|
||||
Score = BookmarkLoader.MatchProgram(c, param).Score,
|
||||
Action = _ =>
|
||||
{
|
||||
|
|
@ -90,7 +92,9 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex
|
|||
{
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
IcoPath = !string.IsNullOrEmpty(c.FaviconPath) && File.Exists(c.FaviconPath)
|
||||
? c.FaviconPath
|
||||
: @"Images\bookmark.png",
|
||||
Score = 5,
|
||||
Action = _ =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,4 +18,5 @@ public record Bookmark(string Name, string Url, string Source = "")
|
|||
}
|
||||
|
||||
public List<CustomBrowser> CustomBrowsers { get; set; } = new();
|
||||
public string FaviconPath { get; set; } = string.Empty;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mages" Version="3.0.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<!-- Do not upgrade System.Data.OleDb since we are .Net7.0 -->
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
<PackageReference Include="System.Data.OleDb" Version="8.0.1" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="tlbimp-Microsoft.Search.Interop" Version="1.0.0" />
|
||||
|
|
|
|||
|
|
@ -56,5 +56,9 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -37,4 +37,8 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -60,6 +60,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="InputSimulator" Version="1.0.4" NoWarn="NU1701" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -64,5 +64,6 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -56,4 +56,8 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -56,4 +56,8 @@
|
|||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -68,5 +68,8 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Reference in a new issue