diff --git a/Flow.Launcher.Core/Plugin/PluginConfig.cs b/Flow.Launcher.Core/Plugin/PluginConfig.cs index ea2119e60..dd6517a7f 100644 --- a/Flow.Launcher.Core/Plugin/PluginConfig.cs +++ b/Flow.Launcher.Core/Plugin/PluginConfig.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.IO; @@ -45,8 +45,56 @@ namespace Flow.Launcher.Core.Plugin } } } - - return allPluginMetadata; + + (List uniqueList, List duplicateList) = GetUniqueLatestPluginMetadata(allPluginMetadata); + + duplicateList + .ForEach( + x => Log.Warn("PluginConfig", + string.Format("Duplicate plugin name: {0}, id: {1}, version: {2} " + + "not loaded due to version not the highest of the duplicates", + x.Name, x.ID, x.Version), + "GetUniqueLatestPluginMetadata")); + + return uniqueList; + } + + internal static (List, List) GetUniqueLatestPluginMetadata(List allPluginMetadata) + { + var duplicate_list = new List(); + var unique_list = new List(); + + var duplicateGroups = allPluginMetadata.GroupBy(x => x.ID).Where(g => g.Count() > 1).Select(y => y).ToList(); + + foreach (var metadata in allPluginMetadata) + { + var duplicatesExist = false; + foreach (var group in duplicateGroups) + { + if (metadata.ID == group.Key) + { + duplicatesExist = true; + + // If metadata's version greater than each duplicate's version, CompareTo > 0 + var count = group.Where(x => metadata.Version.CompareTo(x.Version) > 0).Count(); + + // Only add if the meatadata's version is the highest of all duplicates in the group + if (count == group.Count() - 1) + { + unique_list.Add(metadata); + } + else + { + duplicate_list.Add(metadata); + } + } + } + + if (!duplicatesExist) + unique_list.Add(metadata); + } + + return (unique_list, duplicate_list); } private static PluginMetadata GetPluginMetadata(string pluginDirectory) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 5711ed6aa..855e5c901 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.IO; using System.Threading; @@ -28,6 +28,11 @@ namespace Flow.Launcher.Core.Plugin var path = Path.Combine(Constant.ProgramDirectory, JsonRPC); _startInfo.EnvironmentVariables["PYTHONPATH"] = path; + _startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; + _startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; + _startInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory; + + //Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable _startInfo.ArgumentList.Add("-B"); } @@ -57,4 +62,4 @@ namespace Flow.Launcher.Core.Plugin return Task.CompletedTask; } } -} \ No newline at end of file +} diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index 78e8c5cbf..374f7c71f 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -10,6 +10,7 @@ using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using System.Globalization; +using System.Threading.Tasks; namespace Flow.Launcher.Core.Resource { @@ -95,10 +96,13 @@ namespace Flow.Launcher.Core.Resource { LoadLanguage(language); } - UpdatePluginMetadataTranslations(); Settings.Language = language.LanguageCode; CultureInfo.CurrentCulture = new CultureInfo(language.LanguageCode); CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture; + Task.Run(() => + { + UpdatePluginMetadataTranslations(); + }); } public bool PromptShouldUsePinyin(string languageCodeToSet) diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs index 564e03638..cd49217a4 100644 --- a/Flow.Launcher.Infrastructure/Constant.cs +++ b/Flow.Launcher.Infrastructure/Constant.cs @@ -35,8 +35,16 @@ namespace Flow.Launcher.Infrastructure public const string DefaultTheme = "Win11Light"; + public const string Light = "Light"; + public const string Dark = "Dark"; + public const string System = "System"; + public const string Themes = "Themes"; + public const string Settings = "Settings"; + public const string Logs = "Logs"; public const string Website = "https://flow-launcher.github.io"; + public const string GitHub = "https://github.com/Flow-Launcher/Flow.Launcher"; + public const string Docs = "https://flow-launcher.github.io/docs"; } } diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 74b502657..1ed632e51 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -15,6 +15,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings private string language = "en"; public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}"; public string OpenResultModifiers { get; set; } = KeyConstant.Alt; + public string ColorScheme { get; set; } = "System"; public bool ShowOpenResultHotkey { get; set; } = true; public double WindowSize { get; set; } = 580; @@ -151,7 +152,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings public bool DontPromptUpdateMsg { get; set; } public bool EnableUpdateLog { get; set; } - public bool StartFlowLauncherOnSystemStartup { get; set; } = true; + public bool StartFlowLauncherOnSystemStartup { get; set; } = false; public bool HideOnStartup { get; set; } bool _hideNotifyIcon { get; set; } public bool HideNotifyIcon @@ -184,4 +185,11 @@ namespace Flow.Launcher.Infrastructure.UserSettings Empty, Preserved } + + public enum ColorSchemes + { + System, + Light, + Dark + } } \ No newline at end of file diff --git a/Flow.Launcher.Plugin/Interfaces/IPluginI18n.cs b/Flow.Launcher.Plugin/Interfaces/IPluginI18n.cs index e332d450e..61662b671 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPluginI18n.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPluginI18n.cs @@ -1,4 +1,6 @@ -namespace Flow.Launcher.Plugin +using System.Globalization; + +namespace Flow.Launcher.Plugin { /// /// Represent plugins that support internationalization @@ -8,5 +10,13 @@ string GetTranslatedPluginTitle(); string GetTranslatedPluginDescription(); + + /// + /// The method will be invoked when language of flow changed + /// + void OnCultureInfoChanged(CultureInfo newCulture) + { + + } } } \ No newline at end of file diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index 3abdaf01f..0b59371f8 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -29,6 +29,21 @@ namespace Flow.Launcher.Plugin /// void RestartApp(); + /// + /// Run a shell command + /// + /// The command or program to run + /// the shell type to run, e.g. powershell.exe + /// Thrown when unable to find the file specified in the command + /// Thrown when error occurs during the execution of the command + void ShellRun(string cmd, string filename = "cmd.exe"); + + /// + /// Copy Text to clipboard + /// + /// Text to save on clipboard + public void CopyToClipboard(string text); + /// /// Save everything, all of Flow Launcher and plugins' data and settings /// diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 171b30c26..833ada9cd 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -50,7 +50,7 @@ namespace Flow.Launcher.Plugin /// /// Delegate to Get Image Source /// - public IconDelegate Icon { get; set; } + public IconDelegate Icon; /// /// Information for Glyph Icon diff --git a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs index c5d43a3d9..a2eea19a7 100644 --- a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs +++ b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -60,17 +60,39 @@ namespace Flow.Launcher.Plugin.SharedCommands return sb.ToString(); } - public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "") + public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "", bool createNoWindow = false) { var info = new ProcessStartInfo { FileName = fileName, WorkingDirectory = workingDirectory, Arguments = arguments, - Verb = verb + Verb = verb, + CreateNoWindow = createNoWindow }; return info; } + + /// + /// Runs a windows command using the provided ProcessStartInfo + /// + /// Thrown when unable to find the file specified in the command + /// Thrown when error occurs during the execution of the command + public static void Execute(ProcessStartInfo info) + { + Execute(Process.Start, info); + } + + /// + /// Runs a windows command using the provided ProcessStartInfo using a custom execute command function + /// + /// allows you to pass in a custom command execution function + /// Thrown when unable to find the file specified in the command + /// Thrown when error occurs during the execution of the command + public static void Execute(Func startProcess, ProcessStartInfo info) + { + startProcess(info); + } } } diff --git a/Flow.Launcher.Test/PluginLoadTest.cs b/Flow.Launcher.Test/PluginLoadTest.cs new file mode 100644 index 000000000..d6ba48f19 --- /dev/null +++ b/Flow.Launcher.Test/PluginLoadTest.cs @@ -0,0 +1,92 @@ +using NUnit.Framework; +using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Plugin; +using System.Collections.Generic; +using System.Linq; + +namespace Flow.Launcher.Test +{ + [TestFixture] + class PluginLoadTest + { + [Test] + public void GivenDuplicatePluginMetadatasWhenLoadedThenShouldReturnOnlyUniqueList() + { + // Given + var duplicateList = new List + { + new PluginMetadata + { + ID = "CEA0TYUC6D3B4085823D60DC76F28855", + Version = "1.0.0" + }, + new PluginMetadata + { + ID = "CEA0TYUC6D3B4085823D60DC76F28855", + Version = "1.0.1" + }, + new PluginMetadata + { + ID = "CEA0TYUC6D3B4085823D60DC76F28855", + Version = "1.0.2" + }, + new PluginMetadata + { + ID = "CEA0TYUC6D3B4085823D60DC76F28855", + Version = "1.0.0" + }, + new PluginMetadata + { + ID = "CEA0TYUC6D3B4085823D60DC76F28855", + Version = "1.0.0" + }, + new PluginMetadata + { + ID = "ABC0TYUC6D3B7855823D60DC76F28855", + Version = "1.0.0" + }, + new PluginMetadata + { + ID = "ABC0TYUC6D3B7855823D60DC76F28855", + Version = "1.0.0" + } + }; + + // When + (var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList); + + // Then + Assert.True(unique.FirstOrDefault().ID == "CEA0TYUC6D3B4085823D60DC76F28855" && unique.FirstOrDefault().Version == "1.0.2"); + Assert.True(unique.Count() == 1); + + Assert.False(duplicates.Any(x => x.Version == "1.0.2" && x.ID == "CEA0TYUC6D3B4085823D60DC76F28855")); + Assert.True(duplicates.Count() == 6); + } + + [Test] + public void GivenDuplicatePluginMetadatasWithNoUniquePluginWhenLoadedThenShouldReturnEmptyList() + { + // Given + var duplicateList = new List + { + new PluginMetadata + { + ID = "CEA0TYUC6D3B7855823D60DC76F28855", + Version = "1.0.0" + }, + new PluginMetadata + { + ID = "CEA0TYUC6D3B7855823D60DC76F28855", + Version = "1.0.0" + } + }; + + // When + (var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList); + + // Then + Assert.True(unique.Count() == 0); + Assert.True(duplicates.Count() == 2); + } + } +} diff --git a/Flow.Launcher.Test/Plugins/PluginInitTest.cs b/Flow.Launcher.Test/Plugins/PluginInitTest.cs deleted file mode 100644 index 299a837ee..000000000 --- a/Flow.Launcher.Test/Plugins/PluginInitTest.cs +++ /dev/null @@ -1,17 +0,0 @@ -using NUnit.Framework; -using Flow.Launcher.Core.Plugin; -using Flow.Launcher.Infrastructure.Exception; - -namespace Flow.Launcher.Test.Plugins -{ - - [TestFixture] - public class PluginInitTest - { - [Test] - public void PublicAPIIsNullTest() - { - //Assert.Throws(typeof(Flow.LauncherFatalException), () => PluginManager.Initialize(null)); - } - } -} diff --git a/Flow.Launcher.sln b/Flow.Launcher.sln index 21c3b47dc..b8deae553 100644 --- a/Flow.Launcher.sln +++ b/Flow.Launcher.sln @@ -13,7 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{3A73 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launcher\Flow.Launcher.csproj", "{DB90F671-D861-46BB-93A3-F1304F5BA1C5}" ProjectSection(ProjectDependencies) = postProject - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} = {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} {4792A74A-0CEA-4173-A8B2-30E6764C6217} = {4792A74A-0CEA-4173-A8B2-30E6764C6217} {FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4} @@ -23,6 +22,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launc {9B130CC5-14FB-41FF-B310-0A95B6894C37} = {9B130CC5-14FB-41FF-B310-0A95B6894C37} {FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {FDED22C8-B637-42E8-824A-63B5B6E05A3A} {A3DCCBCA-ACC1-421D-B16E-210896234C26} = {A3DCCBCA-ACC1-421D-B16E-210896234C26} + {5043CECE-E6A7-4867-9CBE-02D27D83747A} = {5043CECE-E6A7-4867-9CBE-02D27D83747A} {403B57F2-1856-4FC7-8A24-36AB346B763E} = {403B57F2-1856-4FC7-8A24-36AB346B763E} {588088F4-3262-4F9F-9663-A05DE12534C3} = {588088F4-3262-4F9F-9663-A05DE12534C3} EndProjectSection @@ -35,8 +35,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Progra EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.WebSearch", "Plugins\Flow.Launcher.Plugin.WebSearch\Flow.Launcher.Plugin.WebSearch.csproj", "{403B57F2-1856-4FC7-8A24-36AB346B763E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.ControlPanel", "Plugins\Flow.Launcher.Plugin.ControlPanel\Flow.Launcher.Plugin.ControlPanel.csproj", "{1EE20B48-82FB-48A2-8086-675D6DDAB4F0}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.PluginIndicator", "Plugins\Flow.Launcher.Plugin.PluginIndicator\Flow.Launcher.Plugin.PluginIndicator.csproj", "{FDED22C8-B637-42E8-824A-63B5B6E05A3A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Sys", "Plugins\Flow.Launcher.Plugin.Sys\Flow.Launcher.Plugin.Sys.csproj", "{0B9DE348-9361-4940-ADB6-F5953BFFCCEC}" @@ -68,6 +66,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Proces EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.PluginsManager", "Plugins\Flow.Launcher.Plugin.PluginsManager\Flow.Launcher.Plugin.PluginsManager.csproj", "{4792A74A-0CEA-4173-A8B2-30E6764C6217}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.WindowsSettings", "Plugins\Flow.Launcher.Plugin.WindowsSettings\Flow.Launcher.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -162,18 +162,6 @@ Global {403B57F2-1856-4FC7-8A24-36AB346B763E}.Release|x64.Build.0 = Release|Any CPU {403B57F2-1856-4FC7-8A24-36AB346B763E}.Release|x86.ActiveCfg = Release|Any CPU {403B57F2-1856-4FC7-8A24-36AB346B763E}.Release|x86.Build.0 = Release|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Debug|x64.ActiveCfg = Debug|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Debug|x64.Build.0 = Debug|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Debug|x86.Build.0 = Debug|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Release|Any CPU.Build.0 = Release|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Release|x64.ActiveCfg = Release|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Release|x64.Build.0 = Release|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Release|x86.ActiveCfg = Release|Any CPU - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}.Release|x86.Build.0 = Release|Any CPU {FDED22C8-B637-42E8-824A-63B5B6E05A3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FDED22C8-B637-42E8-824A-63B5B6E05A3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {FDED22C8-B637-42E8-824A-63B5B6E05A3A}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -283,6 +271,18 @@ Global {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x64.Build.0 = Release|Any CPU {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x86.ActiveCfg = Release|Any CPU {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x86.Build.0 = Release|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.ActiveCfg = Debug|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.Build.0 = Debug|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x86.ActiveCfg = Debug|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x86.Build.0 = Debug|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|Any CPU.Build.0 = Release|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.ActiveCfg = Release|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.Build.0 = Release|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.ActiveCfg = Release|Any CPU + {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -290,7 +290,6 @@ Global GlobalSection(NestedProjects) = preSolution {FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {403B57F2-1856-4FC7-8A24-36AB346B763E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} - {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {A3DCCBCA-ACC1-421D-B16E-210896234C26} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} @@ -300,6 +299,7 @@ Global {F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {588088F4-3262-4F9F-9663-A05DE12534C3} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {4792A74A-0CEA-4173-A8B2-30E6764C6217} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} + {5043CECE-E6A7-4867-9CBE-02D27D83747A} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED} diff --git a/Flow.Launcher/ActionKeywords.xaml b/Flow.Launcher/ActionKeywords.xaml index 32892768d..e94aac9f6 100644 --- a/Flow.Launcher/ActionKeywords.xaml +++ b/Flow.Launcher/ActionKeywords.xaml @@ -1,85 +1,137 @@ - + + + + - + - - + + - - + + + + + + + + + + + + + + - + - - - + + + - - - - - + + + - + + + + + + - - - - \ No newline at end of file diff --git a/Flow.Launcher/App.xaml b/Flow.Launcher/App.xaml index c5214d7ab..b8e2a1cfe 100644 --- a/Flow.Launcher/App.xaml +++ b/Flow.Launcher/App.xaml @@ -1,16 +1,30 @@ - + - + + + + + + + + + + + + + + - + diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 8c869e941..9ee486b3b 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -100,8 +100,6 @@ namespace Flow.Launcher AutoUpdates(); API.SaveAppAllSettings(); - - _mainVM.MainWindowVisibility = _settings.HideOnStartup ? Visibility.Hidden : Visibility.Visible; Log.Info("|App.OnStartup|End Flow Launcher startup ---------------------------------------------------- "); }); } @@ -178,7 +176,7 @@ namespace Flow.Launcher public void OnSecondAppStarted() { - Current.MainWindow.Visibility = Visibility.Visible; + Current.MainWindow.Show(); } } } \ No newline at end of file diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml b/Flow.Launcher/CustomQueryHotkeySetting.xaml index 23bd89906..4ba55b110 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml @@ -1,59 +1,160 @@ - + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - + + + + + - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index 0109474e1..ab4047cec 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -1,8 +1,6 @@ using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; -using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.UserSettings; -using System; using System.Collections.ObjectModel; using System.Linq; using System.Windows; @@ -91,9 +89,9 @@ namespace Flow.Launcher private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbAction.Text); - Application.Current.MainWindow.Visibility = Visibility.Visible; + Application.Current.MainWindow.Show(); + Application.Current.MainWindow.Opacity = 1; Application.Current.MainWindow.Focus(); - } private void cmdEsc_OnPress(object sender, ExecutedRoutedEventArgs e) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index fd2f5f1d9..f431504c2 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -104,6 +104,12 @@ + + + Always + + + diff --git a/Flow.Launcher/Helper/HotKeyMapper.cs b/Flow.Launcher/Helper/HotKeyMapper.cs index fe25ecf18..98327d8da 100644 --- a/Flow.Launcher/Helper/HotKeyMapper.cs +++ b/Flow.Launcher/Helper/HotKeyMapper.cs @@ -6,8 +6,6 @@ using NHotkey.Wpf; using Flow.Launcher.Core.Resource; using System.Windows; using Flow.Launcher.ViewModel; -using System.Threading.Tasks; -using System.Threading; namespace Flow.Launcher.Helper { @@ -27,7 +25,8 @@ namespace Flow.Launcher.Helper internal static void OnToggleHotkey(object sender, HotkeyEventArgs args) { - mainViewModel.ToggleFlowLauncher(); + if (!mainViewModel.GameModeStatus) + mainViewModel.ToggleFlowLauncher(); } private static void SetHotkey(string hotkeyStr, EventHandler action) @@ -75,10 +74,10 @@ namespace Flow.Launcher.Helper { SetHotkey(hotkey.Hotkey, (s, e) => { - if (mainViewModel.ShouldIgnoreHotkeys()) + if (mainViewModel.ShouldIgnoreHotkeys() || mainViewModel.GameModeStatus) return; - mainViewModel.MainWindowVisibility = Visibility.Visible; + mainViewModel.Show(); mainViewModel.ChangeQueryText(hotkey.ActionKeyword, true); }); } diff --git a/Flow.Launcher/Helper/SingletonWindowOpener.cs b/Flow.Launcher/Helper/SingletonWindowOpener.cs index fdfaaa4fc..8efc9be99 100644 --- a/Flow.Launcher/Helper/SingletonWindowOpener.cs +++ b/Flow.Launcher/Helper/SingletonWindowOpener.cs @@ -10,7 +10,6 @@ namespace Flow.Launcher.Helper { var window = Application.Current.Windows.OfType().FirstOrDefault(x => x.GetType() == typeof(T)) ?? (T)Activator.CreateInstance(typeof(T), args); - Application.Current.MainWindow.Hide(); // Fix UI bug // Add `window.WindowState = WindowState.Normal` diff --git a/Flow.Launcher/HotkeyControl.xaml b/Flow.Launcher/HotkeyControl.xaml index 285a282ef..94cdc6703 100644 --- a/Flow.Launcher/HotkeyControl.xaml +++ b/Flow.Launcher/HotkeyControl.xaml @@ -1,26 +1,55 @@ - + - + - - - - press key + + + + Press key - - - + + \ No newline at end of file diff --git a/Flow.Launcher/Images/gamemode.ico b/Flow.Launcher/Images/gamemode.ico new file mode 100644 index 000000000..27a46a904 Binary files /dev/null and b/Flow.Launcher/Images/gamemode.ico differ diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 4cc4e4d17..273723bd8 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -15,6 +15,8 @@ About Exit Close + Game Mode + Suspend the use of Hotkeys. Flow Launcher Settings @@ -56,15 +58,17 @@ Off Action keyword Setting Action keyword - Current action keyword: - New action keyword: - Current Priority: - New Priority: + Current action keyword + New action keyword + Current Priority + New Priority Priority Plugin Directory Author: Init time: Query time: + | Version + Website @@ -85,6 +89,14 @@ Fail to load theme {0}, fallback to default theme Theme Folder Open Theme Folder + Color Scheme + System Default + Light + Dark + Sound Effect + Play a small sound when the search window opens + Animation + Use Animation in UI Hotkey @@ -126,6 +138,8 @@ About Website + Github + Docs Version You have activated Flow Launcher {0} times Check for Updates @@ -136,7 +150,10 @@ or go to https://github.com/Flow-Launcher/Flow.Launcher/releases to download updates manually. Release Notes - Usage Tips: + Usage Tips + DevTools + Setting Folder + Log Folder Select File Manager @@ -173,7 +190,7 @@ This new Action Keyword is already assigned to another plugin, please choose a different one Success Completed successfully - Enter the action keyword you need to start the plug-in. Use * if you don't want to specify an action keyword. In the case, The plug-in works without keywords. + Enter the action keyword you like to use to start the plugin. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords. Custom Query Hotkey diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml index 649895cea..237d632ae 100644 --- a/Flow.Launcher/Languages/ko.xaml +++ b/Flow.Launcher/Languages/ko.xaml @@ -1,7 +1,8 @@ - - + + 핫키 등록 실패: {0} {0}을 실행할 수 없습니다. Flow Launcher 플러그인 파일 형식이 유효하지 않습니다. @@ -14,8 +15,10 @@ 정보 종료 닫기 + 게임 모드 + 핫키 사용을 일시중단합니다. - + Flow Launcher 설정 일반 포터블 모드 @@ -33,41 +36,48 @@ 표시할 결과 수 전체화면 모드에서는 핫키 무시 게이머라면 켜는 것을 추천합니다. + 기본 파일관리자 + 폴더를 열 때 사용할 파일관리자를 선택하세요. Python 디렉토리 자동 업데이트 선택 시작 시 Flow Launcher 숨김 트레이 아이콘 숨기기 - 쿼리 검색 정확도 - 검색 결과가 좀 더 정확해집니다. + 쿼리 검색 정밀도 + 검색 결과에 필요한 최소 매치 점수를 변경합니다. 항상 Pinyin 사용 Pinyin을 사용하여 검색할 수 있습니다. Pinyin(병음)은 로마자 중국어 입력 방식입니다. 반투명 흐림 효과를 사용하는 경우, 그림자 효과를 쓸 수 없습니다. - + 플러그인 플러그인 더 찾아보기 - On - Off + + 액션 키워드 + 현재 액션 키워드 + 새 액션 키워드 현재 중요도: 새 중요도: 중요도 - 플러그인 디렉토리 - 저자 + 플러그인 폴더 + 제작자 초기화 시간: 쿼리 시간: - - - + | 버전 + 웹사이트 + + + 플러그인 스토어 새로고침 설치 - + 테마 - 테마 더 찾아보기 + 테마 갤러리 + 테마 제작 안내 Hi There 쿼리 상자 글꼴 결과 항목 글꼴 @@ -77,8 +87,16 @@ {0} 테마 로드에 실패했습니다. 기본 테마로 변경합니다. 테마 폴더 테마 폴더 열기 + 앱 색상 + 시스템 기본 + 밝게 + 어둡게 + 소리 효과 + 검색창을 열 때 작은 소리를 재생합니다. + 애니메이션 + 일부 UI에 애니메이션을 사용합니다. - + 핫키 Flow Launcher 핫키 Flow Launcher를 열 때 사용할 단축키를 입력합니다. @@ -87,7 +105,7 @@ 단축키 표시 결과창에서 결과 선택 단축키를 표시합니다. 사용자지정 쿼리 핫키 - Query + 쿼리 삭제 편집 추가 @@ -95,10 +113,11 @@ {0} 플러그인 핫키를 삭제하시겠습니까? 그림자 효과 그림자 효과는 GPU를 사용합니다. 컴퓨터 퍼포먼스가 제한적인 경우 사용을 추천하지 않습니다. + 창 넓이 플루언트 아이콘 사용 결과 및 일부 메뉴에서 플루언트 아이콘을 사용합니다. - + HTTP 프록시 HTTP 프록시 켜기 HTTP 서버 @@ -114,26 +133,41 @@ 프록시 설정 정상 프록시 연결 실패 - + 정보 웹사이트 + Github + 문서 버전 Flow Launcher를 {0}번 실행했습니다. 업데이트 확인 새 버전({0})이 있습니다. Flow Launcher를 재시작하세요. 업데이트 확인을 실패했습니다. api.github.com로의 연결 또는 프록시 설정을 확인해주세요. - 업데이트 다운로드에 실패했습니다. github-cloud.s3.amazonaws.com의 연결 또는 프록시 설정을 확인해주세요. + 업데이트 다운로드에 실패했습니다. github-cloud.s3.amazonaws.com의 연결 또는 프록시 설정을 확인해주세요. 수동 다운로드를 하려면 https://github.com/Flow-Launcher/Flow.Launcher/releases 으로 방문하세요. - 릴리즈 노트: - 사용 팁: + 릴리즈 노트 + 사용 팁 + 개발자도구 + 설정 폴더 + 로그 폴더 - + + 파일관리자 선택 + 사용하려는 파일관리자를 선택하고 필요한 경우 인수를 추가하세요. 기본 인수는 "%d" 이며 해당 위치에 경로가 입력됩니다. 예를들어 "totalcmd.exe /A c:\windows"와 같은 명령이 필요한 경우, 인수는 /A "%d" 입니다. + "%f"는 특정 파일의 경로를 나타냅니다. 파일관리자에서 선택한 파일/폴더의 위치를 강조하는 기능에서 사용됩니다. 이 인수는 "파일경로 인수" 항목에서만 사용할 수 있습니다. 파일관리자에 해당 기능이 없거나 잘 모를 경우 "%d" 인수를 사용할 수 있습니다. + 파일관리자 + 프로필 이름 + 파일관리자 경로 + 폴더경로 인수 + 파일경로 인수 + + 중요도 변경 - 높은 수를 넣을수록 상위 결과에 표시됩니다. 5를 시도해보세요. 다른 플러그인 보다 결과를 낮추고 싶다면, 그보다 낮은 수를 입력하세요. + 높은 수를 넣을수록 상위 결과에 표시됩니다. 5를 시도해보세요. 다른 플러그인 보다 결과를 낮춰 표시하고 싶다면, 그보다 낮은 수를 입력하세요. 중요도에 올바른 정수를 입력하세요. - + 예전 액션 키워드 새 액션 키워드 취소 @@ -143,19 +177,20 @@ 새 액션 키워드가 할당된 플러그인이 이미 있습니다. 다른 액션 키워드를 입력하세요. 성공 성공적으로 완료했습니다. - 액션 키워드를 지정하지 않으려면 *를 사용하세요. + 플러그인을 시작하는데 필요한 액션 키워드를 입력하세요. 액션 키워드를 지정하지 않으려면 *를 사용하세요. 이 경우 키워드를 입력하지 않아도 동작합니다. - + 커스텀 플러그인 핫키 + 단축키를 지정하여 특정 쿼리를 자동으로 입력할 수 있습니다. 사용하고 싶은 단축키를 눌러 지정한 후, 사용할 쿼리를 입력하세요. 미리보기 핫키를 사용할 수 없습니다. 다른 핫키를 입력하세요. 플러그인 핫키가 유효하지 않습니다. 업데이트 - + 핫키를 사용할 수 없습니다. - + 버전 시간 수정을 위해 애플리케이션이 어떻게 충돌했는지 알려주세요. @@ -170,17 +205,19 @@ 보고서를 정상적으로 보냈습니다. 보고서를 보내지 못했습니다. Flow Launcher에 문제가 발생했습니다. - - + + 잠시 기다려주세요... - + 새 업데이트 확인 중 새 Flow Launcher 버전({0})을 사용할 수 있습니다. 이미 가장 최신 버전의 Flow Launcher를 사용중입니다. 업데이트 발견 업데이트 중... - Flow Launcher가 유저 정보 데이터를 새버전으로 옮길 수 없습니다. - 프로필 데이터 폴더를 수동으로 {0} 에서 {1}로 옮겨주세요. + + Flow Launcher가 유저 정보 데이터를 새버전으로 옮길 수 없습니다. + 프로필 데이터 폴더를 수동으로 {0} 에서 {1}로 옮겨주세요. + 새 업데이트 소프트웨어 업데이트를 설치하는 중에 오류가 발생했습니다. 업데이트 diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index daea406db..dd8979650 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -1,105 +1,200 @@ - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - + + - + - - - - - - + + + + + + - + @@ -121,49 +216,69 @@ - + - - + - - - + + + - + - - - + + + - - - + + + - + - - - + + + - - - - + + + + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 16e4be8a0..ba0b63a52 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Threading.Tasks; using System.Windows; @@ -11,16 +11,12 @@ using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.ViewModel; -using Microsoft.AspNetCore.Authorization; -using Application = System.Windows.Application; using Screen = System.Windows.Forms.Screen; using ContextMenuStrip = System.Windows.Forms.ContextMenuStrip; -using DataFormats = System.Windows.DataFormats; using DragEventArgs = System.Windows.DragEventArgs; using KeyEventArgs = System.Windows.Input.KeyEventArgs; -using MessageBox = System.Windows.MessageBox; using NotifyIcon = System.Windows.Forms.NotifyIcon; -using System.Windows.Interop; +using Flow.Launcher.Infrastructure; namespace Flow.Launcher { @@ -34,6 +30,7 @@ namespace Flow.Launcher private NotifyIcon _notifyIcon; private ContextMenu contextMenu; private MainViewModel _viewModel; + private bool _animating; #endregion @@ -43,6 +40,7 @@ namespace Flow.Launcher _viewModel = mainVM; _settings = settings; InitializeComponent(); + InitializePosition(); } public MainWindow() @@ -52,6 +50,8 @@ namespace Flow.Launcher private async void OnClosing(object sender, CancelEventArgs e) { + _settings.WindowTop = Top; + _settings.WindowLeft = Left; _notifyIcon.Visible = false; _viewModel.Save(); e.Cancel = true; @@ -65,12 +65,12 @@ namespace Flow.Launcher private void OnLoaded(object sender, RoutedEventArgs _) { + HideStartup(); // show notify icon when flowlauncher is hidden InitializeNotifyIcon(); - + InitializeColorScheme(); WindowsInteropHelper.DisableControlBox(this); InitProgressbarAnimation(); - InitializePosition(); // since the default main window visibility is visible // so we need set focus during startup QueryTextBox.Focus(); @@ -79,13 +79,13 @@ namespace Flow.Launcher { switch (e.PropertyName) { - case nameof(MainViewModel.MainWindowVisibility): + case nameof(MainViewModel.MainWindowVisibilityStatus): { - if (_viewModel.MainWindowVisibility == Visibility.Visible) + if (_viewModel.MainWindowVisibilityStatus) { + UpdatePosition(); Activate(); QueryTextBox.Focus(); - UpdatePosition(); _settings.ActivateTimes++; if (!_viewModel.LastQuerySelected) { @@ -117,7 +117,7 @@ namespace Flow.Launcher _progressBarStoryboard.Stop(ProgressBar); isProgressBarStoryboardPaused = true; } - else if (_viewModel.MainWindowVisibility == Visibility.Visible && + else if (_viewModel.MainWindowVisibilityStatus && isProgressBarStoryboardPaused) { _progressBarStoryboard.Begin(ProgressBar, true); @@ -148,24 +148,29 @@ namespace Flow.Launcher break; } }; - - InitializePosition(); } private void InitializePosition() { - Top = WindowTop(); - Left = WindowLeft(); - _settings.WindowTop = Top; - _settings.WindowLeft = Left; + if (_settings.RememberLastLaunchLocation) + { + Top = _settings.WindowTop; + Left = _settings.WindowLeft; + } + else + { + Left = WindowLeft(); + Top = WindowTop(); + } } private void UpdateNotifyIconText() { var menu = contextMenu; ((MenuItem)menu.Items[1]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen"); - ((MenuItem)menu.Items[2]).Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"); - ((MenuItem)menu.Items[3]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"); + ((MenuItem)menu.Items[2]).Header = InternationalizationManager.Instance.GetTranslation("GameMode"); + ((MenuItem)menu.Items[3]).Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"); + ((MenuItem)menu.Items[4]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"); } private void InitializeNotifyIcon() @@ -180,13 +185,17 @@ namespace Flow.Launcher var header = new MenuItem { - Header = "Flow Launcher", + Header = "Flow Launcher", IsEnabled = false }; var open = new MenuItem { Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") }; + var gamemode = new MenuItem + { + Header = InternationalizationManager.Instance.GetTranslation("GameMode") + }; var settings = new MenuItem { Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings") @@ -196,11 +205,14 @@ namespace Flow.Launcher Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit") }; - open.Click += (o, e) => Visibility = Visibility.Visible; + open.Click += (o, e) => _viewModel.ToggleFlowLauncher(); + gamemode.Click += (o, e) => ToggleGameMode(); settings.Click += (o, e) => App.API.OpenSettingDialog(); exit.Click += (o, e) => Close(); contextMenu.Items.Add(header); contextMenu.Items.Add(open); + gamemode.ToolTip = InternationalizationManager.Instance.GetTranslation("GameModeToolTip"); + contextMenu.Items.Add(gamemode); contextMenu.Items.Add(settings); contextMenu.Items.Add(exit); @@ -220,6 +232,19 @@ namespace Flow.Launcher }; } + private void ToggleGameMode() + { + if (_viewModel.GameModeStatus) + { + _notifyIcon.Icon = Properties.Resources.app; + _viewModel.GameModeStatus = false; + } + else + { + _notifyIcon.Icon = Properties.Resources.gamemode; + _viewModel.GameModeStatus = true; + } + } private void InitProgressbarAnimation() { var da = new DoubleAnimation(ProgressBar.X2, ActualWidth + 150, @@ -235,6 +260,54 @@ namespace Flow.Launcher isProgressBarStoryboardPaused = true; } + public void WindowAnimator() + { + if (_animating) + return; + + _animating = true; + UpdatePosition(); + Storyboard sb = new Storyboard(); + Storyboard iconsb = new Storyboard(); + CircleEase easing = new CircleEase(); // or whatever easing class you want + easing.EasingMode = EasingMode.EaseInOut; + var da = new DoubleAnimation + { + From = 0, + To = 1, + Duration = TimeSpan.FromSeconds(0.25), + FillBehavior = FillBehavior.Stop + }; + + var da2 = new DoubleAnimation + { + From = Top + 10, + To = Top, + Duration = TimeSpan.FromSeconds(0.25), + FillBehavior = FillBehavior.Stop + }; + var da3 = new DoubleAnimation + { + From = 12, + To = 0, + EasingFunction = easing, + Duration = TimeSpan.FromSeconds(0.36), + FillBehavior = FillBehavior.Stop + }; + Storyboard.SetTarget(da, this); + Storyboard.SetTargetProperty(da, new PropertyPath(Window.OpacityProperty)); + Storyboard.SetTargetProperty(da2, new PropertyPath(Window.TopProperty)); + Storyboard.SetTargetProperty(da3, new PropertyPath(TopProperty)); + sb.Children.Add(da); + sb.Children.Add(da2); + iconsb.Children.Add(da3); + sb.Completed += (_, _) => _animating = false; + _settings.WindowLeft = Left; + _settings.WindowTop = Top; + iconsb.Begin(SearchIcon); + sb.Begin(FlowMainWindow); + } + private void OnMouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) DragMove(); @@ -267,22 +340,41 @@ namespace Flow.Launcher e.Handled = true; } - private void OnContextMenusForSettingsClick(object sender, RoutedEventArgs e) + private async void OnContextMenusForSettingsClick(object sender, RoutedEventArgs e) { + _viewModel.Hide(); + + if(_settings.UseAnimation) + await Task.Delay(100); + App.API.OpenSettingDialog(); } - private void OnDeactivated(object sender, EventArgs e) + private async void OnDeactivated(object sender, EventArgs e) { - if (_settings.HideWhenDeactive) + //This condition stops extra hide call when animator is on, + // which causes the toggling to occasional hide instead of show. + if (_viewModel.MainWindowVisibilityStatus) { - _viewModel.Hide(); + // Need time to initialize the main query window animation. + // This also stops the mainwindow from flickering occasionally after Settings window is opened + // and always after Settings window is closed. + if (_settings.UseAnimation) + await Task.Delay(100); + + if (_settings.HideWhenDeactive) + { + _viewModel.Hide(); + } } } private void UpdatePosition() { + if (_animating) + return; + if (_settings.RememberLastLaunchLocation) { Left = _settings.WindowLeft; @@ -297,6 +389,8 @@ namespace Flow.Launcher private void OnLocationChanged(object sender, EventArgs e) { + if (_animating) + return; if (_settings.RememberLastLaunchLocation) { _settings.WindowLeft = Left; @@ -304,7 +398,20 @@ namespace Flow.Launcher } } - private double WindowLeft() + public void HideStartup() + { + UpdatePosition(); + if (_settings.HideOnStartup) + { + _viewModel.Hide(); + } + else + { + _viewModel.Show(); + } + } + + public double WindowLeft() { var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0); @@ -313,7 +420,7 @@ namespace Flow.Launcher return left; } - private double WindowTop() + public double WindowTop() { var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y); @@ -372,5 +479,17 @@ namespace Flow.Launcher { QueryTextBox.CaretIndex = QueryTextBox.Text.Length; } + + public void InitializeColorScheme() + { + if (_settings.ColorScheme == Constant.Light) + { + ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Light; + } + else if (_settings.ColorScheme == Constant.Dark) + { + ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Dark; + } + } } } \ No newline at end of file diff --git a/Flow.Launcher/PriorityChangeWindow.xaml b/Flow.Launcher/PriorityChangeWindow.xaml index bbe601010..8fb27c470 100644 --- a/Flow.Launcher/PriorityChangeWindow.xaml +++ b/Flow.Launcher/PriorityChangeWindow.xaml @@ -7,84 +7,118 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.modernwpf.com/2019" Title="{DynamicResource changePriorityWindow}" - Background="#F3F3F3" - BorderBrush="#cecece" + Width="350" + Background="{DynamicResource PopuBGColor}" + Foreground="{DynamicResource PopupTextColor}" Loaded="PriorityChangeWindow_Loaded" MouseDown="window_MouseDown" ResizeMode="NoResize" - SizeToContent="WidthAndHeight" + SizeToContent="Height" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + diff --git a/Flow.Launcher/Properties/Resources.Designer.cs b/Flow.Launcher/Properties/Resources.Designer.cs index a19716073..43927cb98 100644 --- a/Flow.Launcher/Properties/Resources.Designer.cs +++ b/Flow.Launcher/Properties/Resources.Designer.cs @@ -69,5 +69,13 @@ namespace Flow.Launcher.Properties { return ((System.Drawing.Icon)(obj)); } } + internal static System.Drawing.Icon gamemode + { + get + { + object obj = ResourceManager.GetObject("gamemode", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } } } diff --git a/Flow.Launcher/Properties/Resources.resx b/Flow.Launcher/Properties/Resources.resx index 3ae43d89b..2126cb185 100644 --- a/Flow.Launcher/Properties/Resources.resx +++ b/Flow.Launcher/Properties/Resources.resx @@ -112,13 +112,16 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + ..\Resources\app.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\gamemode.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index e90a53fc3..eb62733b7 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -14,6 +14,7 @@ using Flow.Launcher.Infrastructure.Image; using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; using Flow.Launcher.Plugin.SharedModels; +using Flow.Launcher.Plugin.SharedCommands; using System.Threading; using System.IO; using Flow.Launcher.Infrastructure.Http; @@ -55,7 +56,7 @@ namespace Flow.Launcher public void RestartApp() { - _mainVM.MainWindowVisibility = Visibility.Hidden; + _mainVM.Hide(); // we must manually save // UpdateManager.RestartApp() will call Environment.Exit(0) @@ -70,7 +71,7 @@ namespace Flow.Launcher public void RestarApp() => RestartApp(); - public void ShowMainWindow() => _mainVM.MainWindowVisibility = Visibility.Visible; + public void ShowMainWindow() => _mainVM.Show(); public void CheckForNewUpdate() => _settingsVM.UpdateApp(); @@ -106,6 +107,19 @@ namespace Flow.Launcher }); } + public void ShellRun(string cmd, string filename = "cmd.exe") + { + var args = filename == "cmd.exe" ? $"/C {cmd}" : $"{cmd}"; + + var startInfo = ShellCommand.SetProcessStartInfo(filename, arguments: args, createNoWindow: true); + ShellCommand.Execute(startInfo); + } + + public void CopyToClipboard(string text) + { + Clipboard.SetDataObject(text); + } + public void StartLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Visible; public void StopLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Collapsed; @@ -213,4 +227,4 @@ namespace Flow.Launcher #endregion } -} \ No newline at end of file +} diff --git a/Flow.Launcher/Resources/CustomControlTemplate.xaml b/Flow.Launcher/Resources/CustomControlTemplate.xaml index 877a97645..dd9dba391 100644 --- a/Flow.Launcher/Resources/CustomControlTemplate.xaml +++ b/Flow.Launcher/Resources/CustomControlTemplate.xaml @@ -4,532 +4,130 @@ xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:ui="http://schemas.modernwpf.com/2019"> - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + - + @@ -86,7 +115,7 @@ + Fill="{StaticResource Color03B}" /> - + + + + + + + - - - diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 4b1689b4f..8c7b34e9c 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -1,29 +1,34 @@ - + + + + @@ -57,8 +62,8 @@ + + - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - -  - - - - - - - - - - - - - - - - -  + + + + + + + + + + + + + + + + + + + + + + +  - - + + + - - - - - - - -  - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  - - - - - - - - - - - - -  - - - - - - - - - - - -  - - - - - - - - - - - - -  - - - - - - - + - - + - - - - - - - - - - - - - - - - - - - -  + + +  - - - - - - - - - - + + + + + + + + + + + + + + +  + + + + + - - - - + + - - - - - - - - - -  - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +