diff --git a/README.md b/README.md index b0683ba..a28817d 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ You can disable specific platforms via settings menu. ### Custom shortcuts If you have retail games (or on an unsupported platform) you can add your own shortcuts files (.lnk / .uri) to the plugin games list. -To do this, go to Settings -> Plugins -> GamesLauncher -> Open Custom Shortcuts Directory +To do this, go to `Settings -> Plugins -> GamesLauncher -> Open Custom Shortcuts Directory` Place your shortcut in the opened directory and... That's it! You can now `Reload Plugin Data` to update your library. @@ -51,3 +51,10 @@ Place your shortcut in the opened directory and... That's it! You can now `Reloa If you have (un)installed a game, you can update the plugin without restarting Flow Launcher by using the `Reload Plugin Data` command. ![Reload](docs/reload.png) + +### Hide an item +You can hide a specific game from the plugin list by accessing the context menu (`right arrow`) and using the `Hide` command. + +![Hide Game](docs/hide.png) + +The game can be unhidden later from the settings menu. \ No newline at end of file diff --git a/docs/hide.png b/docs/hide.png new file mode 100644 index 0000000..b299e86 Binary files /dev/null and b/docs/hide.png differ diff --git a/docs/settings.png b/docs/settings.png index d82fc90..e78dd6f 100644 Binary files a/docs/settings.png and b/docs/settings.png differ diff --git a/src/GamesLauncher.Common/Settings/HiddenGames.cs b/src/GamesLauncher.Common/Settings/HiddenGames.cs new file mode 100644 index 0000000..4f77059 --- /dev/null +++ b/src/GamesLauncher.Common/Settings/HiddenGames.cs @@ -0,0 +1,46 @@ +namespace GamesLauncher.Common.Settings +{ + public class HiddenGames + { + public List Items { get; set; } = new List() //This property and class needs to be public to be retrieved by FL Settings + { + new HiddenGame + { + InternalGameId = "Steam_Steamworks Common Redistributables", + Platform = "Steam", + Title = "Steamworks Common Redistributables" + } + }; + + public void Hide(string title, string platform, string internalGameId) + { + if (!Items.Any(x => x.InternalGameId == internalGameId)) + { + Items.Add(new HiddenGame + { + InternalGameId = internalGameId, + Platform = platform, + Title = title + }); + } + } + + public void Unhide(HiddenGame hiddenGame) + { + Items.Remove(hiddenGame); + } + + public bool IsHidden(string internalGameId) + { + return Items.Any(x => x.InternalGameId == internalGameId); + } + } + + public class HiddenGame + { + public string Title { get; set; } = string.Empty; + public string Platform { get; set; } = string.Empty; + public string InternalGameId { get; set; } = string.Empty; + } + +} diff --git a/src/GamesLauncher.Platforms/PlatformsManager.cs b/src/GamesLauncher.Platforms/PlatformsManager.cs index 46098ad..021411c 100644 --- a/src/GamesLauncher.Platforms/PlatformsManager.cs +++ b/src/GamesLauncher.Platforms/PlatformsManager.cs @@ -30,6 +30,11 @@ public IEnumerable GetSynchronizedGames() return Games; } + public Game? GetGame(string title, string platform) + { + return Games.FirstOrDefault(x=> x.Title == title && x.Platform == platform); + } + private IEnumerable InitializeEngines(MainSettings settings) { var engines = new List(); diff --git a/src/GamesLauncher.Platforms/SyncEngines/Steam/SteamGamesConsts.cs b/src/GamesLauncher.Platforms/SyncEngines/Steam/SteamGamesConsts.cs deleted file mode 100644 index d8e8445..0000000 --- a/src/GamesLauncher.Platforms/SyncEngines/Steam/SteamGamesConsts.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Immutable; - -namespace GamesLauncher.Platforms.SyncEngines.Steam -{ - internal static class SteamGamesConsts - { - //TODO: When hiding games from list feature will be implemented this will be no longer needed - internal static readonly IImmutableList AppIdsToIgnore = new List() - { - 228980 //Steamworks Common Redistributables - } - .ToImmutableList(); - } -} diff --git a/src/GamesLauncher.Platforms/SyncEngines/Steam/SteamSyncEngine.cs b/src/GamesLauncher.Platforms/SyncEngines/Steam/SteamSyncEngine.cs index b5cb34e..5ef5231 100644 --- a/src/GamesLauncher.Platforms/SyncEngines/Steam/SteamSyncEngine.cs +++ b/src/GamesLauncher.Platforms/SyncEngines/Steam/SteamSyncEngine.cs @@ -21,8 +21,7 @@ public SteamSyncEngine(IPublicAPI publicApi) public async IAsyncEnumerable GetGames() { var result = handler.FindAllGames(); - var games = result.Where(x => x.IsGame()).Select(x => x.AsGame()) - .Where(x => SteamGamesConsts.AppIdsToIgnore.Contains(x.AppId.Value) == false); + var games = result.Where(x => x.IsGame()).Select(x => x.AsGame()); foreach (var game in games) { diff --git a/src/GamesLauncher.Platforms/SyncEngines/XboxSyncEngine.cs b/src/GamesLauncher.Platforms/SyncEngines/XboxSyncEngine.cs index f207f5b..d4343cd 100644 --- a/src/GamesLauncher.Platforms/SyncEngines/XboxSyncEngine.cs +++ b/src/GamesLauncher.Platforms/SyncEngines/XboxSyncEngine.cs @@ -70,7 +70,7 @@ private Func> GetGameRunTask(string cmd) if (bitmapSource == null || bitmapSource.CanFreeze == false) return null; - bitmapSource.Freeze(); + bitmapSource.Freeze(); //This is needed. Otherwise FL throws exception for some users. return delegate () { diff --git a/src/GamesLauncher/GamesLauncher.csproj b/src/GamesLauncher/GamesLauncher.csproj index 6e602df..4578118 100644 --- a/src/GamesLauncher/GamesLauncher.csproj +++ b/src/GamesLauncher/GamesLauncher.csproj @@ -45,6 +45,13 @@ Always + + Always + + + + + diff --git a/src/GamesLauncher/Images/excludeindexpath.png b/src/GamesLauncher/Images/excludeindexpath.png new file mode 100644 index 0000000..19b7025 Binary files /dev/null and b/src/GamesLauncher/Images/excludeindexpath.png differ diff --git a/src/GamesLauncher/Main.cs b/src/GamesLauncher/Main.cs index 21c7281..0132236 100644 --- a/src/GamesLauncher/Main.cs +++ b/src/GamesLauncher/Main.cs @@ -11,13 +11,14 @@ namespace GamesLauncher { - public class Main : IAsyncPlugin, ISettingProvider, IAsyncReloadable + public class Main : IAsyncPlugin, ISettingProvider, IAsyncReloadable, IContextMenu { #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - private IPublicAPI _publicApi; private MainSettings _settings; private LastPlayedGames _lastPlayedGames; + private HiddenGames _hiddenGames; + private IPublicAPI _publicApi; private PlatformsManager _platformsManager; #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. @@ -28,6 +29,7 @@ public async Task InitAsync(PluginInitContext context) _publicApi = context.API; _settings = _publicApi.LoadSettingJsonStorage(); _lastPlayedGames = _publicApi.LoadSettingJsonStorage(); + _hiddenGames = _publicApi.LoadSettingJsonStorage(); _platformsManager = new PlatformsManager(context.API); @@ -45,16 +47,47 @@ public Task> QueryAsync(Query query, CancellationToken token) var search = query.Search.Trim(); - return Task.FromResult(gamesQuery.Select(x => CreateResultFromGame(x, search)).ToList()); + return Task.FromResult( + gamesQuery.Select(x => + CreateQueryResultFromGame(x, search)) + .Where(x => x != null).Select(x => x!).ToList()); + } + + public List LoadContextMenus(Result selectedResult) + { + var results = new List(); + + var game = _platformsManager.GetGame(selectedResult.Title, selectedResult.SubTitle); + + if (game is null) + return results; + + results.Add(new Result + { + Title = "Hide", + SubTitle = "The game can be unhidden in settings panel", + IcoPath = @"Images\excludeindexpath.png", + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ued1a"), + AsyncAction = (context) => + { + _hiddenGames.Hide(game.Title, game.Platform, game.InternalGameId); + return ValueTask.FromResult(false); + } + }); + + return results; } public Control CreateSettingPanel() { - return new SettingsView(_settings, _publicApi); + return new SettingsView(_settings, _hiddenGames, _publicApi); } - private Result CreateResultFromGame(Game game, string search) + private Result? CreateQueryResultFromGame(Game game, string search) { + if (_hiddenGames.IsHidden(game.InternalGameId)) + return null; + var result = new Result { Title = game.Title, @@ -84,6 +117,5 @@ private Result CreateResultFromGame(Game game, string search) return result; } - } } \ No newline at end of file diff --git a/src/GamesLauncher/Views/SettingsView.xaml b/src/GamesLauncher/Views/SettingsView.xaml index 8afd320..37dd32a 100644 --- a/src/GamesLauncher/Views/SettingsView.xaml +++ b/src/GamesLauncher/Views/SettingsView.xaml @@ -7,6 +7,7 @@ d:DesignHeight="300" d:DesignWidth="300" Loaded="SettingsView_OnLoaded" + DataContext="{Binding RelativeSource={RelativeSource Self}}" mc:Ignorable="d"> @@ -16,6 +17,8 @@ + + Place shortcuts (.lnk/.url) in this directory. They will be available in the games list. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/GamesLauncher/Views/SettingsView.xaml.cs b/src/GamesLauncher/Views/SettingsView.xaml.cs index 824f990..a5f09c2 100644 --- a/src/GamesLauncher/Views/SettingsView.xaml.cs +++ b/src/GamesLauncher/Views/SettingsView.xaml.cs @@ -1,6 +1,8 @@ using Flow.Launcher.Plugin; using GamesLauncher.Common; using GamesLauncher.Common.Settings; +using System; +using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; @@ -9,13 +11,18 @@ namespace GamesLauncher.Views public partial class SettingsView : UserControl { private readonly MainSettings _settings; + private readonly HiddenGames _hiddenGames; + private readonly IPublicAPI _publicAPI; - public SettingsView(MainSettings settings, IPublicAPI publicAPI) + public SettingsView(MainSettings settings, HiddenGames hiddenGames, IPublicAPI publicAPI) { InitializeComponent(); _settings = settings; + _hiddenGames = hiddenGames; _publicAPI = publicAPI; + + HiddenGames.ItemsSource = new ObservableCollection(_hiddenGames.Items); } private void SettingsView_OnLoaded(object sender, RoutedEventArgs re) @@ -66,5 +73,19 @@ private void BtnOpenCustomShortcutsDirectory_Click(object sender, RoutedEventArg { _publicAPI.ShellRun(Paths.CustomShortcutsDirectory, "explorer.exe"); } + + private void BtnShowHiddenGames_Click(object sender, RoutedEventArgs e) + { + HiddenGamesStackPanel.Visibility = HiddenGamesStackPanel.Visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed; + } + + private void BtnUnhideGame_Click(object sender, EventArgs e) + { + if ((sender as Button)?.CommandParameter is not HiddenGame gameToUnhide) + return; + + _hiddenGames.Unhide(gameToUnhide); + HiddenGames.ItemsSource = new ObservableCollection(_hiddenGames.Items); + } } } diff --git a/src/GamesLauncher/plugin.json b/src/GamesLauncher/plugin.json index e44a049..a2f9ab0 100644 --- a/src/GamesLauncher/plugin.json +++ b/src/GamesLauncher/plugin.json @@ -4,7 +4,7 @@ "Name": "GamesLauncher", "Description": "Search and launch games from multiple platforms like Steam, Epic Games, Xbox etc.", "Author": "KrystianLesniak", - "Version": "1.4.5", + "Version": "1.5.0", "Language": "csharp", "Website": "https://github.com/KrystianLesniak/Flow.Launcher.Plugin.GamesLauncher", "IcoPath": "icon.png",