From 1b31e9c9685abd0d1d556d260425fac4b5aff165 Mon Sep 17 00:00:00 2001 From: Odotocodot <48138990+Odotocodot@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:37:05 +0000 Subject: [PATCH 001/259] Create Flow Launcher Theme Selector plugin --- ...w.Launcher.Plugin.FlowThemeSelector.csproj | 37 +++++++ .../Main.cs | 91 ++++++++++++++++++ .../icon.png | Bin 0 -> 6625 bytes .../plugin.json | 12 +++ 4 files changed, 140 insertions(+) create mode 100644 Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj create mode 100644 Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Main.cs create mode 100644 Plugins/Flow.Launcher.Plugin.FlowThemeSelector/icon.png create mode 100644 Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj new file mode 100644 index 000000000..ba0ddd6ab --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj @@ -0,0 +1,37 @@ + + + + + Library + net7.0-windows + true + false + + + + ..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.FlowThemeSelector + + + + ..\..\Output\Release\Plugins\Flow.Launcher.Plugin.FlowThemeSelector + + + + + + + + + + + PreserveNewest + + + + + + PreserveNewest + + + + diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Main.cs b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Main.cs new file mode 100644 index 000000000..6fd6472db --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Main.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Flow.Launcher.Core.Resource; + +namespace Flow.Launcher.Plugin.FlowThemeSelector +{ + public class FlowThemeSelector : IPlugin, IReloadable, IDisposable + { + private PluginInitContext context; + private IEnumerable themes; + + public void Init(PluginInitContext context) + { + this.context = context; + context.API.VisibilityChanged += OnVisibilityChanged; + } + + public List Query(Query query) + { + if (query.IsReQuery) + { + LoadThemes(); + } + + if (string.IsNullOrWhiteSpace(query.Search)) + { + return themes.Select(CreateThemeResult) + .OrderBy(x => x.Title) + .ToList(); + } + + return themes.Select(theme => (theme, matchResult: context.API.FuzzySearch(query.Search, theme))) + .Where(x => x.matchResult.IsSearchPrecisionScoreMet()) + .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData)) + .OrderBy(x => x.Title) + .ToList(); + } + + private void OnVisibilityChanged(object sender, VisibilityChangedEventArgs args) + { + if (args.IsVisible && !context.CurrentPluginMetadata.Disabled) + { + LoadThemes(); + } + } + + public void LoadThemes() => themes = ThemeManager.Instance.LoadAvailableThemes().Select(Path.GetFileNameWithoutExtension); + + public static Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); + + public static Result CreateThemeResult(string theme, int score, IList highlightData) + { + string title; + if (theme == ThemeManager.Instance.Settings.Theme) + { + title = $"{theme} ★"; + score = 2000; + } + else + { + title = theme; + } + + return new Result + { + Title = title, + TitleHighlightData = highlightData, + Glyph = new GlyphInfo("/Resources/#Segoe Fluent Icons", "\ue790"), + Score = score, + Action = c => + { + ThemeManager.Instance.ChangeTheme(theme); + return true; + } + }; + } + + public void ReloadData() => LoadThemes(); + + public void Dispose() + { + if (context != null && context.API != null) + { + context.API.VisibilityChanged -= OnVisibilityChanged; + } + } + + } +} diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/icon.png b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..704e9474eb29ffa1fcaeff9e24c60ee35155afd5 GIT binary patch literal 6625 zcmV<786M_|P)?L~#_W&dT5+Df~tR%E=9kt)zb>9h)AYqsw`j&HD=X&5T zo_x;9xxe?h&+}kl&}CiLWnI=~UDjn?)@5DRWnK1+nBx`2yKb4XkC_>=6)stFZLT1&5Y;r?b&_2|)x3Z7H-nk27~+~O4{^jFQ6z?V_@jHd8Y)Ztgd zAyMTCRj|KUDX@>PUTc*idEMZjU{-l}$t_2|z%@sHoj|YmPJvGYPzAgAO4!Cpg|=~( zvkidf4E|TmHCH~yHAlgAV>N=;8~pSZ;3sQ`UmpOwI1+?P*v3lIY~n?I4E~qQ?ULNw zEvGJug70wnwavnJY!iGbb?az}+$Kgk!{Avr$18Zzja9eDm8E#l;qdDN&>Z}v7U0L% z!&e5tCPwAa5?Duz_dK&D$u;Z0rtYk|EH_pi9v8l6t`J_Of!JC7CBBv~#whgirZXG4yg=vvTth_=(NKS1&!y!Y3XnCP6rBumjH< zJoN@V@0P3h#XYwU?Sh}J8GvbdsW|e$3ju#E!;$+-;r-_#?5&&M5P+59iC82Yi`iu( zF@zP}Dtw1F!j0o8{&s@M9l^Z(R>RQUyPpxCoY^qE8K; zMjMhMdEK3*h|?85GgF3n>=W3nn1>&JUx0moETpC9JHY_6V; zbKXJ(eqW=4zeG3=^UFuk>>pn|6vNqrF*xr-IK+#!YJI1WDhxjQCx#rqPp|Gi zaxj0Yg!67;V*u9PhQ*4ju<|R?4*x<0EQp5)S9dmhgQ-Dy!HrcHqA&PNqU}?pSSp-> zRpLolEtyQq4Y`s<*Gn`Wi-lt`pFavSN{3@o$%h!l@x+IBJm7w7C>-KN6ns!ztik@-CqO74-zt z2VqdYE1a)Rhkcv~4i}}Gax+c}hhr6R*(U|_=W4kAQUm7CRdCrSq1o^7RVi$@7GdCq z0$6^217=Gv;r)e~=>PQ%ScO&8*L_%qs>2sjHwzMM?==4Ith&_{ewzazZ+(|b0+1}l zh-*HyzRxQsK8ix0Q#JxKONV1BZx|+&e2CE;CH%n!Zg9EHfL;0zu#c;NJqduC+_a4q z!{LW=IDIFC^Ij1cdqr^GBZAX+0yyj{gWZ?KH2dqzPyfX%^qrrMK1(xTbwSVopJsnZ z1uW{}2h#w^tb#hBgUY-tW4N;v_gaEKI=2MJZ)`;2EnC#xcoTJ3-bMk-3CFTFV`NrI z^8v`Hr2%kBW@A$ESWMv#qrk~^GWR12eoWB^7{MNb4+}joINue_+YH!W8wA_feAvfU zz@8`_^<8dM1?+Z|&^k|m*Sq}=9_+Ri!-l|Lmj}yL*Ol4-Nf!FdNkOmKiLg9h-Yk4` zC486#3efLd`NAg(-y=izANSlkUQ6(|T|0r_xo_ZM(erp%@B;q2^)LK&^(8#WeHjn3 zUV$vN8#bk#YPQG2NU4N#f*5WYAsAis0mc-0(o!>uGlVX-9~BOQXMsCB@|a-UV!-}} z6KoRB!7fSwyI7H?)+hQtN(k%CcjzKZN{!Mv^mprx1vK*sd~>hM=(i{vedndYbVeeK zr^Uk}xD1vdLM8l=Ch&s<=uZQ{Pk*8TaAVa)wgi9ce zqxY;Nm`sU>@qz?c1eL+!yg)1b{^$7Ucc%RB_k+s&JsJ3y>gKdqcCw35m;V+X7QUc# zlKr>;g}<)9hzFNn!h@Wb@gU%+zJpEFE!aht!!}w7yBHBIKN`E-7%>fiD6NSRhsqvm$1<9(<~MIWb~RE52Fdu=)E}`<}?8OM)<)^;1fT~N8dB0t2!J$ zGh6nKd#*yFb-~S+coZFE(a>_A9ub{wnS#{~Px%zJ_}-ufs2H3z=rn zY%Ql$!-;IFE{fq0Cxm@;Iqaj#U>C`QT?Fw`*hZAm%x{D*eYCG1BY|~<00RPf=%EvOx4 zRxJuI+2OBiFVc*sPJX`f5*}Q7xiR}wU&Z~z*KjZHb=-@31GgfXwCp@`sFGX_rvwQc zFN)wm7S~t->|>N}7cEfMd{TDQ;m2zps*wJUb%YQDLd#&`ork^)(rKnsl`}7mF1DoP z^qQUklgY6#8Xtw8W5Up9_hp!$<-#nmtX25$pDst=)8(}tx-)jqQFyrLDE@9qYBJNS zpY`(8g4pR~<;Xu9#WRn#yqFSG* z9kSq(n%_`%wDk3@BP%d4jE?~!r7-*H7EI?P(?ym*C*{VNfG1f$HUd4zN1)HQmtc0L z1ZHP>Fb^u%gdf-hKFNL(fKz2KJ;k%@umHHR>QYFB~YE8?BDzv3s35Nut^DEol*N+loV3+^{E|kM6mP9P5Mgx$a z>WKSkuPW<&y%X?c(M@UsKm1MH4S5Te(DZ+qIJ_ejGgJm!e zmgkCLd6ol2C}ox2y_qVOvNjqzb@K3#0dH=sQ;Jk3oqw0fvQ`#J(xhLqD?F4<@it#3}D z6EBCk3Vc)e{Z#PZZw7wv6Q$_&YiYLL1K^gUNNj6^jg%lpvKSlVkK=Ci8%p5h8uf+} zeE6HV8>%cjcZ1%-f6x5~Yr_NJ7%!sVfVRTdHb&C0=xV@kp|5|T0+t~HJ4P zY!k(Es;sf}sNkCt|CO7sSNJYD^8Ri)^1s{K-E_&Q0V7okMv@pCV~(Rbyr(kTX~wI- z2fu|s1K&pFITNf6I}XRV3gw0?sZysIo_536?CZC>(Q1^NP2krD;8z|@j`Pa&8UR<8 z!n<9qWztTd-vS93i6RV(y9wWjjktN9iJG9Es1EFjn}M!46tW3Jqi-sAxfjK7Ops8y z*=G3hEx>PBbekNex7gQjEBtb;@J$1F=oP@N*6%4-jzZS%zCPK}rYcL3bD{`N@d7x- z@!=F#4#(Jf=fg3+g2E@Y-zm9DPXkn~!`Ir^4;H}g6d&{Ulwj-n0_^_mI=)_f32Rs8 zV)D)#unOR*DV`?qezm%=Hz zQmyQC&LAG~ufPVB}v?q?Z7= z=g3F41b;+=2;RG6knyQEIOBJsaO`#@&-)4cc7RJf6SLCAGH;wBQ}Hk@fRrmXajDK+>8~zSseo3Ru{S1 z+= ze6$3HM@o|Q6aYnbbMV*t=Rz=kCxtH+N9)8+~hiqVZ30v2|WDRXL>8)H_*px6e+*wpsB?_|qb=e#!-`nHYps z<43Xew?+)NpM{yH3Gqqb7$#7XAY!>=ztMIWvM z`-3$o9I_e(gI3|&Z9&RKSC0=%42+h94UCWuv56PGMtne|$kQrZ9PtQzEn2@}qjk0n z@1Npg`I2M``pa1fD!)j7-#RlEo2N%Nz+XEl2%k?lgB4?c!^~NMF!mz>D560i@C^?a z!{~6yXq^M#mZ@0WT#F%f?vJ$At9w2Cl3@gXWA@(}{5kRmtwi*cui>Q8VyJ1m)^Bd3 z6(#vX+kIPxi?_6<^)*_{BmgJ57`Hi#)^`GX^NeVE-84Olg5Nkb4C^O{(7I3Ik2?vk zF##C5Iu=HLg)lx+1fwI30qEg-r?<`laLrPD|40DRs!%XyD}~J+u5t=~BZ}4FlkC4U zjDm&7iy19~dnOYwg}GLn|U%n&Hvt>ywu9ZzZtw%g34-;n*-Wi~`>< zg?K0hzjjhER!=;KRpXVJPvCzt{y6&laves#g)kynuYzyrTcps-V@%9!d6fzJUGk6v9Jys&meK~SHS1a2M+D67Nwtb^T%1&$dZXPE3 zK&#?uoZ)Hc>-Rm$MV|l;+`eI9&Ez0jW=OWLnHWeHTLOONxKmg@_5{2}AIFkWN8zwF z1xAPRVd%$hgzs03o`*QmI>T25;D*LVD}(fQDv>aAFN%h)qrj;Ttp~prY)=CJb0z#i zO8B?jmLYP&PGz$#u~KKPZ`FqJKl8B4H(G+|WF68Y8`0*;-Bz!Rx04Tpqec1zioi3VzPuRamqyo(@krs7A&0*w^2p z75;g_Hk}St0=O_eRtyvWBA6UuD>qtXq4gus$(5}vJ5Avq;-H&1+g5J@aLJTcKhoKx zqk_tBf%C-*c!m_>n~kRsF>xny2d$(YHhw$4TK^k7g6_aRny(xaC)rQtciN-%qg&qP zT833b4hR!{K-L7}W+9@XH1nI&`mK$TXzA;l_?N)MzgW4^I#R5m^&8;R0C3RVhjU49 z@KpgQYqqUSTFRt{pD3n>Dh{!HI7FAjA-WXyQN+odX1Q{7upWMbD*HR|P{l&qM(c6m zAJc5Gslzu^!B=KK2R#mQ(ER{=iCzQ1%#`J6?dzwKv2iI40-0nWXS!r?)*)8u%9{T; z@TD!nZ&Pboi`LgR!=r>>+79@|8t~sc$U%<-oVs`RbM*U+7&BAGYVkchq^n7e5fdeF zB-0GU8|F5}4K@FX_Vt5W(E8fotFpi8p-KaMwH}YU+-!hPvfrohJH5hJ2B7w0n_q%N zjuexslp8J5TF`lbN}?zD&Cl>O51-c#_(cuyd-xQ}jepF0NACe(WXO(o+)I$8YVak0 z4~&wWCi>nswDxVs2;sl2BZLkEBE;Vf2p7paYKBJxen1oW{!QRFqj;3?*+lt#rFZx= z0O_(V9r+R@8=~`LBm$cliHEj(u#OVjuBI86I``+;+g{pu0D_=B=N3Z+A!l zm>D%=JMtw+)-e*ceORSoYxiLlA?#&&p+eCy15|2@ZhPS$V56H)p_f5NnOkP1VY9D& z)W=JZqNT;QkyS=*y%)<1!d)#Ms&tUtY^wDe;M3AmnBC#;3}U3!6l;6u=HtEuiIg3y z2w|`G+=pebz`nDzesl12>_zIP$ZU`O5) zdb=+0oO5b*kzQtaqNI;~P+<`yaBU5~wudG3qxI|Ivn&6zujt9XXWBWXda1EMqbhAlw5uDv9*4*^rS9op??V9)+|VH_i-PV z&{^wK_-wrEeP^3NXPHxKt-V8H^?%zYH#J%e2X%qpFQ}rMS+JnEGqpbPclQ_i8g#Zf zBvwtdPpG=zCaoVW`P({LvQwA8XB8xQy?>D4a@*x*^AAgCQ#^)k(E2L)Ay3Ua;T#jI z7dQ1X*TeTxQAIF|Bv=O7~KI{ z|E$5`D>^6AGil~Q{Led6>v!MJ)=4-#^VUB|kfc@dXninRclg~76yELb&0cKqPq%*O z_}nM1^}X4`?)y2+&i?FAh4nwn|F14uzrFCg9Vm?G{!2-Z&i>p_jrBWMF6l6>uLi&S z0d`F{pTfDF{du1{>vx8Ku0yrH5Bu-#KJ1`(4;S?8?9cjCTK_YAm-kPX{jDGPk7#{X zPjB|1&i;%~z4bX=ept_1pVjkV;bWae{3ESj4Cm$Er^=#qg6~^&|Gh&+XL|UsT{`>o zJewAT7y6vw?d*Mm_eWc`eow!mKYRKXNA&PzFEBpZ0mD-NL^J-i+^AOocZ11sZgQ^x z9^d#F_nz@FuFU9YNr{nv@g>6}C8rIK6s>*Fk3G1XPu@S{|37wFmvvc}by=5nS(kNL fmvx!JvuOVh5a5F)ThAaT00000NkvXXu0mjfwnX-y literal 0 HcmV?d00001 diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json new file mode 100644 index 000000000..f275d129c --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json @@ -0,0 +1,12 @@ +{ + "ID": "4DFA743E1086414BAB0AA3071D561D75", + "ActionKeyword": "flowtheme", + "Name": "Flow Launcher Theme Selector", + "Description": "Quickly switch your Flow Launcher theme.", + "Author": "Odotocodot", + "Version": "1.0.0", + "Language": "csharp", + "Website": "https://github.com/Flow-Launcher/Flow.Launcher", + "IcoPath": "icon.png", + "ExecuteFileName": "Flow.Launcher.Plugin.FlowThemeSelector.dll" +} \ No newline at end of file From 49a71d7d53a3c66a3feac30f743f625f47059f83 Mon Sep 17 00:00:00 2001 From: Odotocodot <48138990+Odotocodot@users.noreply.github.com> Date: Sat, 15 Jun 2024 12:16:36 +0100 Subject: [PATCH 002/259] Move Theme Selector into Sys plugin --- ...w.Launcher.Plugin.FlowThemeSelector.csproj | 37 ------------------ .../plugin.json | 12 ------ .../Flow.Launcher.Plugin.Sys.csproj | 1 + .../Images/theme_selector.png} | Bin .../Languages/en.xaml | 4 +- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 29 +++++++++++++- .../ThemeSelector.cs} | 24 +++++++----- 7 files changed, 45 insertions(+), 62 deletions(-) delete mode 100644 Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj delete mode 100644 Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json rename Plugins/{Flow.Launcher.Plugin.FlowThemeSelector/icon.png => Flow.Launcher.Plugin.Sys/Images/theme_selector.png} (100%) rename Plugins/{Flow.Launcher.Plugin.FlowThemeSelector/Main.cs => Flow.Launcher.Plugin.Sys/ThemeSelector.cs} (72%) diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj deleted file mode 100644 index ba0ddd6ab..000000000 --- a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Flow.Launcher.Plugin.FlowThemeSelector.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Library - net7.0-windows - true - false - - - - ..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.FlowThemeSelector - - - - ..\..\Output\Release\Plugins\Flow.Launcher.Plugin.FlowThemeSelector - - - - - - - - - - - PreserveNewest - - - - - - PreserveNewest - - - - diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json b/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json deleted file mode 100644 index f275d129c..000000000 --- a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "ID": "4DFA743E1086414BAB0AA3071D561D75", - "ActionKeyword": "flowtheme", - "Name": "Flow Launcher Theme Selector", - "Description": "Quickly switch your Flow Launcher theme.", - "Author": "Odotocodot", - "Version": "1.0.0", - "Language": "csharp", - "Website": "https://github.com/Flow-Launcher/Flow.Launcher", - "IcoPath": "icon.png", - "ExecuteFileName": "Flow.Launcher.Plugin.FlowThemeSelector.dll" -} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index c7a722189..bba466384 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -38,6 +38,7 @@ + diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/icon.png b/Plugins/Flow.Launcher.Plugin.Sys/Images/theme_selector.png similarity index 100% rename from Plugins/Flow.Launcher.Plugin.FlowThemeSelector/icon.png rename to Plugins/Flow.Launcher.Plugin.Sys/Images/theme_selector.png diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml index 91f32a844..2a266f8f6 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml @@ -27,6 +27,7 @@ Flow Launcher Tips Flow Launcher UserData Folder Toggle Game Mode + Set the Flow Launcher Theme Shutdown Computer @@ -49,8 +50,9 @@ Visit Flow Launcher's documentation for more help and how to use tips Open the location where Flow Launcher's settings are stored Toggle Game Mode + Quickly change the Flow Launcher theme - + Success All Flow Launcher settings saved Reloaded all applicable plugin data diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 1ec07915d..0dbb46be9 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -18,9 +18,10 @@ using MessageBox = System.Windows.MessageBox; namespace Flow.Launcher.Plugin.Sys { - public class Main : IPlugin, ISettingProvider, IPluginI18n + public class Main : IPlugin, ISettingProvider, IPluginI18n, IDisposable { private PluginInitContext context; + private ThemeSelector themeSelector; private Dictionary KeywordTitleMappings = new Dictionary(); #region DllImport @@ -58,6 +59,11 @@ namespace Flow.Launcher.Plugin.Sys public List Query(Query query) { + if(query.Search.StartsWith(ThemeSelector.Keyword)) + { + return themeSelector.Query(query); + } + var commands = Commands(); var results = new List(); foreach (var c in commands) @@ -106,6 +112,7 @@ namespace Flow.Launcher.Plugin.Sys public void Init(PluginInitContext context) { this.context = context; + themeSelector = new ThemeSelector(context); KeywordTitleMappings = new Dictionary{ {"Shutdown", "flowlauncher_plugin_sys_shutdown_computer_cmd"}, {"Restart", "flowlauncher_plugin_sys_restart_computer_cmd"}, @@ -126,7 +133,8 @@ namespace Flow.Launcher.Plugin.Sys {"Open Log Location", "flowlauncher_plugin_sys_open_log_location_cmd"}, {"Flow Launcher Tips", "flowlauncher_plugin_sys_open_docs_tips_cmd"}, {"Flow Launcher UserData Folder", "flowlauncher_plugin_sys_open_userdata_location_cmd"}, - {"Toggle Game Mode", "flowlauncher_plugin_sys_toggle_game_mode_cmd"} + {"Toggle Game Mode", "flowlauncher_plugin_sys_toggle_game_mode_cmd"}, + {"Set Flow Launcher Theme", "flowlauncher_plugin_sys_theme_selector_cmd"} }; } @@ -426,6 +434,18 @@ namespace Flow.Launcher.Plugin.Sys context.API.ToggleGameMode(); return true; } + }, + new Result + { + Title = "Set Flow Launcher Theme", + SubTitle = context.API.GetTranslation("flowlauncher_plugin_sys_theme_selector"), + IcoPath = "Images\\theme_selector.png", + Glyph = new GlyphInfo("/Resources/#Segoe Fluent Icons", "\ue790"), + Action = c => + { + context.API.ChangeQuery($"{ThemeSelector.Keyword} "); + return false; + } } }); @@ -441,5 +461,10 @@ namespace Flow.Launcher.Plugin.Sys { return context.API.GetTranslation("flowlauncher_plugin_sys_plugin_description"); } + + public void Dispose() + { + themeSelector.Dispose(); + } } } diff --git a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs similarity index 72% rename from Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Main.cs rename to Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 6fd6472db..24d17486e 100644 --- a/Plugins/Flow.Launcher.Plugin.FlowThemeSelector/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -4,14 +4,16 @@ using System.IO; using System.Linq; using Flow.Launcher.Core.Resource; -namespace Flow.Launcher.Plugin.FlowThemeSelector +namespace Flow.Launcher.Plugin.Sys { - public class FlowThemeSelector : IPlugin, IReloadable, IDisposable + public class ThemeSelector : IReloadable, IDisposable { - private PluginInitContext context; + public const string Keyword = "fltheme"; + + private readonly PluginInitContext context; private IEnumerable themes; - public void Init(PluginInitContext context) + public ThemeSelector(PluginInitContext context) { this.context = context; context.API.VisibilityChanged += OnVisibilityChanged; @@ -24,14 +26,16 @@ namespace Flow.Launcher.Plugin.FlowThemeSelector LoadThemes(); } - if (string.IsNullOrWhiteSpace(query.Search)) + string search = query.Search[(query.Search.IndexOf(Keyword, StringComparison.Ordinal) + Keyword.Length + 1)..]; + + if (string.IsNullOrWhiteSpace(search)) { return themes.Select(CreateThemeResult) .OrderBy(x => x.Title) .ToList(); } - return themes.Select(theme => (theme, matchResult: context.API.FuzzySearch(query.Search, theme))) + return themes.Select(theme => (theme, matchResult: context.API.FuzzySearch(search, theme))) .Where(x => x.matchResult.IsSearchPrecisionScoreMet()) .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData)) .OrderBy(x => x.Title) @@ -46,11 +50,12 @@ namespace Flow.Launcher.Plugin.FlowThemeSelector } } - public void LoadThemes() => themes = ThemeManager.Instance.LoadAvailableThemes().Select(Path.GetFileNameWithoutExtension); + private void LoadThemes() + => themes = ThemeManager.Instance.LoadAvailableThemes().Select(Path.GetFileNameWithoutExtension); - public static Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); + private static Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); - public static Result CreateThemeResult(string theme, int score, IList highlightData) + private static Result CreateThemeResult(string theme, int score, IList highlightData) { string title; if (theme == ThemeManager.Instance.Settings.Theme) @@ -86,6 +91,5 @@ namespace Flow.Launcher.Plugin.FlowThemeSelector context.API.VisibilityChanged -= OnVisibilityChanged; } } - } } From 7a0be2c6103939312eeead86c3a1e01a3d618a3f Mon Sep 17 00:00:00 2001 From: Odotocodot <48138990+Odotocodot@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:50:00 +0100 Subject: [PATCH 003/259] Remove Reloadable from theme selector --- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 24d17486e..758250421 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -6,7 +6,7 @@ using Flow.Launcher.Core.Resource; namespace Flow.Launcher.Plugin.Sys { - public class ThemeSelector : IReloadable, IDisposable + public class ThemeSelector : IDisposable { public const string Keyword = "fltheme"; @@ -82,8 +82,6 @@ namespace Flow.Launcher.Plugin.Sys }; } - public void ReloadData() => LoadThemes(); - public void Dispose() { if (context != null && context.API != null) From 5a80adcbfec1309b537721ab9e98f9d07187c135 Mon Sep 17 00:00:00 2001 From: Kevin Zhang <45326534+taooceros@users.noreply.github.com> Date: Sun, 17 Nov 2024 23:59:43 -0600 Subject: [PATCH 004/259] Send a reload request with ctx when reloading --- Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs index 5a6633525..ae4fd639d 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs @@ -133,10 +133,16 @@ namespace Flow.Launcher.Core.Plugin RPC.StartListening(); } - public virtual Task ReloadDataAsync() + public virtual async Task ReloadDataAsync() { SetupJsonRPC(); - return Task.CompletedTask; + try + { + await RPC.InvokeAsync("reload", context); + } + catch (RemoteMethodNotFoundException e) + { + } } public virtual async ValueTask DisposeAsync() From fa8cd548f6c11d71cf9dbd91a5c6c1495837222b Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Thu, 5 Dec 2024 14:18:13 +0600 Subject: [PATCH 005/259] Add `.`, `./lib`, `./plugin` directories to path for Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 52 ++++++++++++++++++--- Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 31 +++++++++++- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 536e69b3d..36160b920 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.IO; using System.Text.Json; using System.Threading; @@ -29,10 +30,6 @@ namespace Flow.Launcher.Core.Plugin _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"); } protected override Task RequestAsync(JsonRPCRequestModel request, CancellationToken token = default) @@ -50,10 +47,51 @@ namespace Flow.Launcher.Core.Plugin // TODO: Async Action return Execute(_startInfo); } + public override async Task InitAsync(PluginInitContext context) { - _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); - _startInfo.ArgumentList.Add(""); + // Run .py files via `-c ` + if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase)) + { + var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; + var libDirectory = Path.Combine(rootDirectory, "lib"); + var pluginDirectory = Path.Combine(rootDirectory, "plugin"); + + // This makes it easier for plugin authors to import their own modules. + // They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually. + // Instead of running the .py file directly, we pass the code we want to run as a CLI argument. + // This code sets sys.path for the plugin author and then runs the .py file via runpy. + _startInfo.ArgumentList.Add("-c"); + _startInfo.ArgumentList.Add( + $""" + import sys + sys.path.append(r'{rootDirectory}') + sys.path.append(r'{libDirectory}') + sys.path.append(r'{pluginDirectory}') + + import runpy + runpy.run_path(r'{context.CurrentPluginMetadata.ExecuteFilePath}', None, '__main__') + """ + ); + // Plugins always expect the JSON data to be in the third argument + // (we're always setting it as _startInfo.ArgumentList[2] = ...). + _startInfo.ArgumentList.Add(""); + // Because plugins always expect the JSON data to be in the third argument, and specifying -c + // takes up two arguments, we have to move `-B` to the end. + _startInfo.ArgumentList.Add("-B"); + } + // Run .pyz files as is + else + { + // -B flag is needed to tell python not to write .py[co] files. + // Because .pyc contains location infos which will prevent python portable + _startInfo.ArgumentList.Add("-B"); + _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + // Plugins always expect the JSON data to be in the third argument + // (we're always setting it as _startInfo.ArgumentList[2] = ...). + _startInfo.ArgumentList.Add(""); + } + await base.InitAsync(context); _startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory; } diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 5c36e0eea..224653ba1 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -33,7 +33,36 @@ namespace Flow.Launcher.Core.Plugin public override async Task InitAsync(PluginInitContext context) { - StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + // Run .py files via `-c ` + if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase)) + { + var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; + var libDirectory = Path.Combine(rootDirectory, "lib"); + var pluginDirectory = Path.Combine(rootDirectory, "plugin"); + var filePath = context.CurrentPluginMetadata.ExecuteFilePath; + + // This makes it easier for plugin authors to import their own modules. + // They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually. + // Instead of running the .py file directly, we pass the code we want to run as a CLI argument. + // This code sets sys.path for the plugin author and then runs the .py file via runpy. + StartInfo.ArgumentList.Add("-c"); + StartInfo.ArgumentList.Add( + $""" + import sys + sys.path.append(r'{rootDirectory}') + sys.path.append(r'{libDirectory}') + sys.path.append(r'{pluginDirectory}') + + import runpy + runpy.run_path(r'{filePath}', None, '__main__') + """ + ); + } + // Run .pyz files as is + else + { + StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + } await base.InitAsync(context); } From d5dd7b44a41322ebdd9e4e97a25e62e653775688 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Thu, 5 Dec 2024 17:37:54 +0600 Subject: [PATCH 006/259] Use PYTHONDONTWRITEBYTECODE instead of -B flag when running Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 11 ++++++----- Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 4 +--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 36160b920..7b670742a 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -26,6 +26,9 @@ namespace Flow.Launcher.Core.Plugin var path = Path.Combine(Constant.ProgramDirectory, JsonRPC); _startInfo.EnvironmentVariables["PYTHONPATH"] = path; + // Prevent Python from writing .py[co] files. + // Because .pyc contains location infos which will prevent python portable. + _startInfo.EnvironmentVariables["PYTHONDONTWRITEBYTECODE"] = "1"; _startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; _startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; @@ -76,15 +79,13 @@ namespace Flow.Launcher.Core.Plugin // Plugins always expect the JSON data to be in the third argument // (we're always setting it as _startInfo.ArgumentList[2] = ...). _startInfo.ArgumentList.Add(""); - // Because plugins always expect the JSON data to be in the third argument, and specifying -c - // takes up two arguments, we have to move `-B` to the end. - _startInfo.ArgumentList.Add("-B"); } // Run .pyz files as is else { - // -B flag is needed to tell python not to write .py[co] files. - // Because .pyc contains location infos which will prevent python portable + // No need for -B flag because we're using PYTHONDONTWRITEBYTECODE env variable now, + // but the plugins still expect data to be sent as the third argument, so we're keeping + // the flag here, even though it's not necessary anymore. _startInfo.ArgumentList.Add("-B"); _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); // Plugins always expect the JSON data to be in the third argument diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 224653ba1..03ac0e661 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -26,9 +26,7 @@ namespace Flow.Launcher.Core.Plugin var path = Path.Combine(Constant.ProgramDirectory, JsonRpc); StartInfo.EnvironmentVariables["PYTHONPATH"] = path; - - //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"); + StartInfo.EnvironmentVariables["PYTHONDONTWRITEBYTECODE"] = "1"; } public override async Task InitAsync(PluginInitContext context) From 41a345a70006e881709b1c6543e683926289b583 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 6 Dec 2024 23:55:20 -0600 Subject: [PATCH 007/259] Remove Result comparison and Change signature from IEnumerable to ICollection (due to the potential of multiple enumeration) --- Flow.Launcher.Plugin/Result.cs | 21 --------------------- Flow.Launcher/ViewModel/ResultsViewModel.cs | 6 +++--- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 9b42b1021..ac0b827c0 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -156,27 +156,6 @@ namespace Flow.Launcher.Plugin } } - /// - public override bool Equals(object obj) - { - var r = obj as Result; - - var equality = string.Equals(r?.Title, Title) && - string.Equals(r?.SubTitle, SubTitle) && - string.Equals(r?.AutoCompleteText, AutoCompleteText) && - string.Equals(r?.CopyText, CopyText) && - string.Equals(r?.IcoPath, IcoPath) && - TitleHighlightData == r.TitleHighlightData; - - return equality; - } - - /// - public override int GetHashCode() - { - return HashCode.Combine(Title, SubTitle, AutoCompleteText, CopyText, IcoPath); - } - /// public override string ToString() { diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 107372e01..c0e0b146d 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -182,7 +182,7 @@ namespace Flow.Launcher.ViewModel /// /// To avoid deadlock, this method should not called from main thread /// - public void AddResults(IEnumerable resultsForUpdates, CancellationToken token, bool reselect = true) + public void AddResults(ICollection resultsForUpdates, CancellationToken token, bool reselect = true) { var newResults = NewResults(resultsForUpdates); @@ -228,12 +228,12 @@ namespace Flow.Launcher.ViewModel .ToList(); } - private List NewResults(IEnumerable resultsForUpdates) + private List NewResults(ICollection resultsForUpdates) { if (!resultsForUpdates.Any()) return Results; - return Results.Where(r => r != null && !resultsForUpdates.Any(u => u.ID == r.Result.PluginID)) + return Results.Where(r => r != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) .Concat(resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings))) .OrderByDescending(rv => rv.Result.Score) .ToList(); From a395936a6c6b8fa0f3d7c34ccbb0b876d88d035b Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 11:56:32 +0800 Subject: [PATCH 008/259] Replace FormApplication & DllImport with CSWin32 --- .../Flow.Launcher.Plugin.Sys.csproj | 7 +++ Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 44 ++++--------------- .../NativeMethods.txt | 6 +++ 3 files changed, 21 insertions(+), 36 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index b797b3cf4..dbc36ad42 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -57,4 +57,11 @@ PreserveNewest + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 6e5558228..f80f3c9dd 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -2,17 +2,16 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; using System.Windows; -using System.Windows.Forms; -using System.Windows.Interop; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.SharedCommands; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.System.Shutdown; using Application = System.Windows.Application; using Control = System.Windows.Controls.Control; -using FormsApplication = System.Windows.Forms.Application; namespace Flow.Launcher.Plugin.Sys { @@ -21,33 +20,6 @@ namespace Flow.Launcher.Plugin.Sys private PluginInitContext context; private Dictionary KeywordTitleMappings = new Dictionary(); - #region DllImport - - internal const int EWX_LOGOFF = 0x00000000; - internal const int EWX_SHUTDOWN = 0x00000001; - internal const int EWX_REBOOT = 0x00000002; - internal const int EWX_FORCE = 0x00000004; - internal const int EWX_POWEROFF = 0x00000008; - internal const int EWX_FORCEIFHUNG = 0x00000010; - - [DllImport("user32")] - private static extern bool ExitWindowsEx(uint uFlags, uint dwReason); - - [DllImport("user32")] - private static extern void LockWorkStation(); - - [DllImport("Shell32.dll", CharSet = CharSet.Unicode)] - private static extern uint SHEmptyRecycleBin(IntPtr hWnd, uint dwFlags); - - // http://www.pinvoke.net/default.aspx/Enums/HRESULT.html - private enum HRESULT : uint - { - S_FALSE = 0x0001, - S_OK = 0x0000 - } - - #endregion - public Control CreateSettingPanel() { var results = Commands(); @@ -206,7 +178,7 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - ExitWindowsEx(EWX_LOGOFF, 0); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, 0); return true; } @@ -219,7 +191,7 @@ namespace Flow.Launcher.Plugin.Sys IcoPath = "Images\\lock.png", Action = c => { - LockWorkStation(); + PInvoke.LockWorkStation(); return true; } }, @@ -229,7 +201,7 @@ namespace Flow.Launcher.Plugin.Sys SubTitle = context.API.GetTranslation("flowlauncher_plugin_sys_sleep"), Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xec46"), IcoPath = "Images\\sleep.png", - Action = c => FormsApplication.SetSuspendState(PowerState.Suspend, false, false) + Action = c => PInvoke.SetSuspendState(false, false, false) }, new Result { @@ -274,8 +246,8 @@ namespace Flow.Launcher.Plugin.Sys // http://www.pinvoke.net/default.aspx/shell32/SHEmptyRecycleBin.html // FYI, couldn't find documentation for this but if the recycle bin is already empty, it will return -2147418113 (0x8000FFFF (E_UNEXPECTED)) // 0 for nothing - var result = SHEmptyRecycleBin(new WindowInteropHelper(Application.Current.MainWindow).Handle, 0); - if (result != (uint) HRESULT.S_OK && result != (uint) 0x8000FFFF) + var result = PInvoke.SHEmptyRecycleBin(new(), string.Empty, 0); + if (result != HRESULT.S_OK && result != HRESULT.E_UNEXPECTED) { context.API.ShowMsgBox($"Error emptying recycle bin, error code: {result}\n" + "please refer to https://msdn.microsoft.com/en-us/library/windows/desktop/aa378137", diff --git a/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt b/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt new file mode 100644 index 000000000..8fcb6cae9 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt @@ -0,0 +1,6 @@ +ExitWindowsEx +LockWorkStation +SHEmptyRecycleBin +S_OK +E_UNEXPECTED +SetSuspendState \ No newline at end of file From ca01b25a39b6c35d58b021fd153d796def9d7e05 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 13:29:21 +0800 Subject: [PATCH 009/259] Replace DllImport & flags with CSWin32 --- .../Flow.Launcher.Plugin.ProcessKiller.csproj | 7 +++ .../NativeMethods.txt | 2 + .../ProcessHelper.cs | 52 ++++++++----------- 3 files changed, 31 insertions(+), 30 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.ProcessKiller/NativeMethods.txt diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj index 876bac1e7..4e216b7b2 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj @@ -50,6 +50,13 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/NativeMethods.txt b/Plugins/Flow.Launcher.Plugin.ProcessKiller/NativeMethods.txt new file mode 100644 index 000000000..7fa794755 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/NativeMethods.txt @@ -0,0 +1,2 @@ +QueryFullProcessImageName +OpenProcess \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs index 0acc39fbb..d8e5f4fb7 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs @@ -1,11 +1,13 @@ -using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; +using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Runtime.InteropServices; -using System.Text; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.System.Threading; namespace Flow.Launcher.Plugin.ProcessKiller { @@ -84,43 +86,33 @@ namespace Flow.Launcher.Plugin.ProcessKiller } } - public string TryGetProcessFilename(Process p) + public unsafe string TryGetProcessFilename(Process p) { try { - int capacity = 2000; - StringBuilder builder = new StringBuilder(capacity); - IntPtr ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id); - if (!QueryFullProcessImageName(ptr, 0, builder, ref capacity)) + var handle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, (uint)p.Id); + if (handle.Value == IntPtr.Zero) { - return String.Empty; + return string.Empty; } - return builder.ToString(); + using var safeHandle = new SafeProcessHandle(handle.Value, true); + uint capacity = 2000; + char[] buffer = new char[capacity]; + fixed (char* pBuffer = buffer) + { + if (!PInvoke.QueryFullProcessImageName(safeHandle, PROCESS_NAME_FORMAT.PROCESS_NAME_WIN32, (PWSTR)pBuffer, ref capacity)) + { + return string.Empty; + } + } + + return new string(buffer, 0, (int)capacity); } catch { - return ""; + return string.Empty; } } - - [Flags] - private enum ProcessAccessFlags : uint - { - QueryLimitedInformation = 0x00001000 - } - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool QueryFullProcessImageName( - [In] IntPtr hProcess, - [In] int dwFlags, - [Out] StringBuilder lpExeName, - ref int lpdwSize); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern IntPtr OpenProcess( - ProcessAccessFlags processAccess, - bool bInheritHandle, - int processId); } } From 313f86b6485e6f32f1d23e58fcd09692ae322e8c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 15:09:06 +0800 Subject: [PATCH 010/259] Replace DllImport & flags with CSWin32 --- .../Flow.Launcher.Plugin.Program.csproj | 8 ++ .../NativeMethods.txt | 10 ++ .../Programs/ShellLinkHelper.cs | 130 +++++------------- .../Programs/ShellLocalization.cs | 67 +++++---- 4 files changed, 82 insertions(+), 133 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index c0ad63cfe..99c1a12e9 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -52,6 +52,10 @@ PreserveNewest + + + + @@ -61,6 +65,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt b/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt new file mode 100644 index 000000000..ecd547dff --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt @@ -0,0 +1,10 @@ +SHGetLocalizedName +LoadString +LoadLibraryEx +FreeLibrary +ExpandEnvironmentStrings +S_OK +SLGP_FLAGS +WIN32_FIND_DATAW +SLR_FLAGS +IShellLinkW \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index 78c66d604..fae9c84c9 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -1,97 +1,17 @@ using System; -using System.Text; using System.Runtime.InteropServices; -using Accessibility; using System.Runtime.InteropServices.ComTypes; using Flow.Launcher.Plugin.Program.Logger; +using Windows.Win32.Foundation; +using Windows.Win32.UI.Shell; +using Windows.Win32.Storage.FileSystem; namespace Flow.Launcher.Plugin.Program.Programs { class ShellLinkHelper { - [Flags()] - public enum SLGP_FLAGS - { - SLGP_SHORTPATH = 0x1, - SLGP_UNCPRIORITY = 0x2, - SLGP_RAWPATH = 0x4 - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct WIN32_FIND_DATAW - { - public uint dwFileAttributes; - public long ftCreationTime; - public long ftLastAccessTime; - public long ftLastWriteTime; - public uint nFileSizeHigh; - public uint nFileSizeLow; - public uint dwReserved0; - public uint dwReserved1; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string cFileName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public string cAlternateFileName; - } - - [Flags()] - public enum SLR_FLAGS - { - SLR_NO_UI = 0x1, - SLR_ANY_MATCH = 0x2, - SLR_UPDATE = 0x4, - SLR_NOUPDATE = 0x8, - SLR_NOSEARCH = 0x10, - SLR_NOTRACK = 0x20, - SLR_NOLINKINFO = 0x40, - SLR_INVOKE_MSI = 0x80 - } - - + // Reference : http://www.pinvoke.net/default.aspx/Interfaces.IShellLinkW - /// The IShellLink interface allows Shell links to be created, modified, and resolved - [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")] - interface IShellLinkW - { - /// Retrieves the path and file name of a Shell link object - void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, ref WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags); - /// Retrieves the list of item identifiers for a Shell link object - void GetIDList(out IntPtr ppidl); - /// Sets the pointer to an item identifier list (PIDL) for a Shell link object. - void SetIDList(IntPtr pidl); - /// Retrieves the description string for a Shell link object - void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); - /// Sets the description for a Shell link object. The description can be any application-defined string - void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); - /// Retrieves the name of the working directory for a Shell link object - void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); - /// Sets the name of the working directory for a Shell link object - void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); - /// Retrieves the command-line arguments associated with a Shell link object - void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); - /// Sets the command-line arguments for a Shell link object - void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - /// Retrieves the hot key for a Shell link object - void GetHotkey(out short pwHotkey); - /// Sets a hot key for a Shell link object - void SetHotkey(short wHotkey); - /// Retrieves the show command for a Shell link object - void GetShowCmd(out int piShowCmd); - /// Sets the show command for a Shell link object. The show command sets the initial show state of the window. - void SetShowCmd(int iShowCmd); - /// Retrieves the location (path and index) of the icon for a Shell link object - void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, - int cchIconPath, out int piIcon); - /// Sets the location (path and index) of the icon for a Shell link object - void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); - /// Sets the relative path to the Shell link object - void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); - /// Attempts to find the target of a Shell link, even if it has been moved or renamed - void Resolve(ref Accessibility._RemotableHandle hwnd, SLR_FLAGS fFlags); - /// Sets the path and file name of a Shell link object - void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); - } - [ComImport(), Guid("00021401-0000-0000-C000-000000000046")] public class ShellLink { @@ -102,29 +22,40 @@ namespace Flow.Launcher.Plugin.Program.Programs public string arguments = string.Empty; // Retrieve the target path using Shell Link - public string retrieveTargetPath(string path) + public unsafe string retrieveTargetPath(string path) { var link = new ShellLink(); const int STGM_READ = 0; ((IPersistFile)link).Load(path, STGM_READ); - var hwnd = new _RemotableHandle(); - ((IShellLinkW)link).Resolve(ref hwnd, 0); + var hwnd = new HWND(IntPtr.Zero); + ((IShellLinkW)link).Resolve(hwnd, 0); const int MAX_PATH = 260; - StringBuilder buffer = new StringBuilder(MAX_PATH); + char[] buffer = new char[MAX_PATH]; var data = new WIN32_FIND_DATAW(); - ((IShellLinkW)link).GetPath(buffer, buffer.Capacity, ref data, SLGP_FLAGS.SLGP_SHORTPATH); - var target = buffer.ToString(); + var target = string.Empty; + fixed (char* bufferChar = buffer) + { + ((IShellLinkW)link).GetPath((PWSTR)bufferChar, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); + int validLength = Array.IndexOf(buffer, '\0'); + if (validLength < 0) validLength = MAX_PATH; + target = new string(buffer, 0, validLength); + } // To set the app description - if (!String.IsNullOrEmpty(target)) + if (!string.IsNullOrEmpty(target)) { try { - buffer = new StringBuilder(MAX_PATH); - ((IShellLinkW)link).GetDescription(buffer, MAX_PATH); - description = buffer.ToString(); + char[] buffer1 = new char[MAX_PATH]; + fixed (char* buffer1Char = buffer1) + { + ((IShellLinkW)link).GetDescription((PWSTR)buffer1Char, MAX_PATH); + int validLength = Array.IndexOf(buffer1, '\0'); + if (validLength < 0) validLength = MAX_PATH; + description = new string(buffer1, 0, validLength); + } } catch (COMException e) { @@ -134,9 +65,14 @@ namespace Flow.Launcher.Plugin.Program.Programs e); } - buffer.Clear(); - ((IShellLinkW)link).GetArguments(buffer, MAX_PATH); - arguments = buffer.ToString(); + char[] buffer2 = new char[MAX_PATH]; + fixed (char* buffer2Char = buffer2) + { + ((IShellLinkW)link).GetArguments((PWSTR)buffer2Char, MAX_PATH); + int validLength = Array.IndexOf(buffer2, '\0'); + if (validLength < 0) validLength = MAX_PATH; + arguments = new string(buffer2, 0, validLength); + } } // To release unmanaged memory diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs index 4f344d89e..e36618b0d 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs @@ -1,8 +1,8 @@ using System; using System.IO; -using System.Runtime.InteropServices; -using System.Text; - +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.System.LibraryLoader; namespace Flow.Launcher.Plugin.Program.Programs { @@ -13,51 +13,46 @@ namespace Flow.Launcher.Plugin.Program.Programs /// public static class ShellLocalization { - internal const uint DONTRESOLVEDLLREFERENCES = 0x00000001; - internal const uint LOADLIBRARYASDATAFILE = 0x00000002; - - [DllImport("shell32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] - internal static extern int SHGetLocalizedName(string pszPath, StringBuilder pszResModule, ref int cch, out int pidsRes); - - [DllImport("user32.dll", EntryPoint = "LoadStringW", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] - internal static extern int LoadString(IntPtr hModule, int resourceID, StringBuilder resourceValue, int len); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadLibraryExW")] - internal static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); - - [DllImport("kernel32.dll", ExactSpelling = true)] - internal static extern int FreeLibrary(IntPtr hModule); - - [DllImport("kernel32.dll", EntryPoint = "ExpandEnvironmentStringsW", CharSet = CharSet.Unicode, ExactSpelling = true)] - internal static extern uint ExpandEnvironmentStrings(string lpSrc, StringBuilder lpDst, int nSize); - /// /// Returns the localized name of a shell item. /// /// Path to the shell item (e. g. shortcut 'File Explorer.lnk'). /// The localized name as string or . - public static string GetLocalizedName(string path) + public static unsafe string GetLocalizedName(string path) { - StringBuilder resourcePath = new StringBuilder(1024); - StringBuilder localizedName = new StringBuilder(1024); - int len, id; - len = resourcePath.Capacity; + int capacity = 1024; + char[] resourcePathBuffer = new char[capacity]; // If there is no resource to localize a file name the method returns a non zero value. - if (SHGetLocalizedName(path, resourcePath, ref len, out id) == 0) + fixed (char* resourcePath = resourcePathBuffer) { - _ = ExpandEnvironmentStrings(resourcePath.ToString(), resourcePath, resourcePath.Capacity); - IntPtr hMod = LoadLibraryEx(resourcePath.ToString(), IntPtr.Zero, DONTRESOLVEDLLREFERENCES | LOADLIBRARYASDATAFILE); - if (hMod != IntPtr.Zero) + var result = PInvoke.SHGetLocalizedName(path, (PWSTR)resourcePath, (uint)capacity, out var id); + if (result == HRESULT.S_OK) { - if (LoadString(hMod, id, localizedName, localizedName.Capacity) != 0) + int validLength = Array.IndexOf(resourcePathBuffer, '\0'); + if (validLength < 0) validLength = capacity; + var resourcePathStr = new string(resourcePathBuffer, 0, validLength); + _ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, resourcePath, (uint)capacity); + var handle = PInvoke.LoadLibraryEx(resourcePathStr, + LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE); + IntPtr safeHandle = handle.DangerousGetHandle(); + if (safeHandle != IntPtr.Zero) { - string lString = localizedName.ToString(); - _ = FreeLibrary(hMod); - return lString; - } + char[] localizedNameBuffer = new char[capacity]; + fixed (char* localizedName = localizedNameBuffer) + { + if (PInvoke.LoadString(handle, (uint)id, (PWSTR)localizedName, capacity) != 0) + { + validLength = Array.IndexOf(localizedNameBuffer, '\0'); + if (validLength < 0) validLength = capacity; + var lString = new string(localizedNameBuffer, 0, validLength); + PInvoke.FreeLibrary(new(safeHandle)); + return lString; + } + } - _ = FreeLibrary(hMod); + PInvoke.FreeLibrary(new(safeHandle)); + } } } From ccfc39e54a35fb552cc563f1fa8660e99ffe1037 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 15:12:35 +0800 Subject: [PATCH 011/259] Fix string length issue --- Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs index d8e5f4fb7..6df12fae9 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs @@ -105,9 +105,11 @@ namespace Flow.Launcher.Plugin.ProcessKiller { return string.Empty; } - } - return new string(buffer, 0, (int)capacity); + int validLength = Array.IndexOf(buffer, '\0'); + if (validLength < 0) validLength = (int)capacity; + return new string(buffer, 0, validLength); + } } catch { From 79f8f053d9288282c56579f41f284e96c19f2de5 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 15:24:19 +0800 Subject: [PATCH 012/259] Replace DllImport with CSWin32 --- .../Flow.Launcher.Plugin.csproj | 10 +++++- Flow.Launcher.Plugin/NativeMethods.txt | 3 ++ .../SharedCommands/ShellCommand.cs | 31 ++++++++++++------- 3 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 Flow.Launcher.Plugin/NativeMethods.txt diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 35b9af1c9..2feb21b12 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -57,7 +57,11 @@ - + + + + + @@ -68,6 +72,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Flow.Launcher.Plugin/NativeMethods.txt b/Flow.Launcher.Plugin/NativeMethods.txt new file mode 100644 index 000000000..e3e2b705e --- /dev/null +++ b/Flow.Launcher.Plugin/NativeMethods.txt @@ -0,0 +1,3 @@ +EnumThreadWindows +GetWindowText +GetWindowTextLength \ No newline at end of file diff --git a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs index 49f78b458..191a76309 100644 --- a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs +++ b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs @@ -2,18 +2,15 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; -using System.Text; using System.Threading; +using Windows.Win32; +using Windows.Win32.Foundation; namespace Flow.Launcher.Plugin.SharedCommands { public static class ShellCommand { public delegate bool EnumThreadDelegate(IntPtr hwnd, IntPtr lParam); - [DllImport("user32.dll")] static extern bool EnumThreadWindows(uint threadId, EnumThreadDelegate lpfn, IntPtr lParam); - [DllImport("user32.dll")] static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount); - [DllImport("user32.dll")] static extern int GetWindowTextLength(IntPtr hwnd); private static bool containsSecurityWindow; @@ -42,21 +39,33 @@ namespace Flow.Launcher.Plugin.SharedCommands { ProcessThreadCollection ptc = Process.GetCurrentProcess().Threads; for (int i = 0; i < ptc.Count; i++) - EnumThreadWindows((uint)ptc[i].Id, CheckSecurityThread, IntPtr.Zero); + PInvoke.EnumThreadWindows((uint)ptc[i].Id, CheckSecurityThread, IntPtr.Zero); } - private static bool CheckSecurityThread(IntPtr hwnd, IntPtr lParam) + private static BOOL CheckSecurityThread(HWND hwnd, LPARAM lParam) { if (GetWindowTitle(hwnd) == "Windows Security") containsSecurityWindow = true; return true; } - private static string GetWindowTitle(IntPtr hwnd) + private static unsafe string GetWindowTitle(HWND hwnd) { - StringBuilder sb = new StringBuilder(GetWindowTextLength(hwnd) + 1); - GetWindowText(hwnd, sb, sb.Capacity); - return sb.ToString(); + var capacity = PInvoke.GetWindowTextLength(hwnd) + 1; + char[] buffer = new char[capacity]; + fixed (char* pBuffer = buffer) + { + // If the window has no title bar or text, if the title bar is empty, + // or if the window or control handle is invalid, the return value is zero. + if (PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity) == 0) + { + return string.Empty; + } + + int validLength = Array.IndexOf(buffer, '\0'); + if (validLength < 0) validLength = capacity; + return new string(buffer, 0, validLength); + } } public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "", bool createNoWindow = false) From 22170ee43a9fc9b01838cef65f0f45594473d952 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 20:44:28 +0800 Subject: [PATCH 013/259] Replace DllImport & flags with CSWin32 --- .../FileExplorerHelper.cs | 10 +- .../Flow.Launcher.Infrastructure.csproj | 8 + .../Hotkey/GlobalHotkey.cs | 58 +++---- .../Hotkey/InterceptKeys.cs | 38 ----- .../Hotkey/KeyEvent.cs | 12 +- .../Image/ThumbnailReader.cs | 154 ++++++------------ .../NativeMethods.txt | 20 +++ 7 files changed, 116 insertions(+), 184 deletions(-) delete mode 100644 Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs create mode 100644 Flow.Launcher.Infrastructure/NativeMethods.txt diff --git a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs index 76695a4e3..b738b9c88 100644 --- a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs +++ b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Runtime.InteropServices; +using Windows.Win32; namespace Flow.Launcher.Infrastructure { @@ -54,10 +54,6 @@ namespace Flow.Launcher.Infrastructure return explorerWindows.Zip(zOrders).MinBy(x => x.Second).First; } - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); - private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); /// @@ -70,9 +66,9 @@ namespace Flow.Launcher.Infrastructure var index = 0; var numRemaining = hWnds.Count; - EnumWindows((wnd, _) => + PInvoke.EnumWindows((wnd, _) => { - var searchIndex = hWnds.FindIndex(x => x.HWND == wnd.ToInt32()); + var searchIndex = hWnds.FindIndex(x => x.HWND == wnd.Value); if (searchIndex != -1) { z[searchIndex] = index; diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index ec35ef9d6..1475252ca 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -35,6 +35,10 @@ false + + + + @@ -56,6 +60,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs index f847ab189..75af843b9 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs @@ -1,6 +1,11 @@ -using System; +using System; +using System.Diagnostics; using System.Runtime.InteropServices; using Flow.Launcher.Plugin; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.UI.Input.KeyboardAndMouse; +using Windows.Win32.UI.WindowsAndMessaging; namespace Flow.Launcher.Infrastructure.Hotkey { @@ -10,44 +15,41 @@ namespace Flow.Launcher.Infrastructure.Hotkey /// public unsafe class GlobalHotkey : IDisposable { - private static readonly IntPtr hookId; - - - - public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state); - internal static Func hookedKeyboardCallback; + private static readonly UnhookWindowsHookExSafeHandle hookId; - //Modifier key constants - private const int VK_SHIFT = 0x10; - private const int VK_CONTROL = 0x11; - private const int VK_ALT = 0x12; - private const int VK_WIN = 91; + public delegate bool KeyboardCallback(int keyEvent, int vkCode, SpecialKeyState state); + internal static Func hookedKeyboardCallback; static GlobalHotkey() { // Set the hook - hookId = InterceptKeys.SetHook(& LowLevelKeyboardProc); + using Process curProcess = Process.GetCurrentProcess(); + using ProcessModule curModule = curProcess.MainModule; + hookId = PInvoke.SetWindowsHookEx( + WINDOWS_HOOK_ID.WH_KEYBOARD_LL, + LowLevelKeyboardProc, + PInvoke.GetModuleHandle(curModule.ModuleName), 0); } public static SpecialKeyState CheckModifiers() { SpecialKeyState state = new SpecialKeyState(); - if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_SHIFT) & 0x8000) != 0) { //SHIFT is pressed state.ShiftPressed = true; } - if ((InterceptKeys.GetKeyState(VK_CONTROL) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_CONTROL) & 0x8000) != 0) { //CONTROL is pressed state.CtrlPressed = true; } - if ((InterceptKeys.GetKeyState(VK_ALT) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_MENU) & 0x8000) != 0) { //ALT is pressed state.AltPressed = true; } - if ((InterceptKeys.GetKeyState(VK_WIN) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0) { //WIN is pressed state.WinPressed = true; @@ -56,33 +58,33 @@ namespace Flow.Launcher.Infrastructure.Hotkey return state; } - [UnmanagedCallersOnly] - private static IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam) + private static LRESULT LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { bool continues = true; if (nCode >= 0) { - if (wParam.ToUInt32() == (int)KeyEvent.WM_KEYDOWN || - wParam.ToUInt32() == (int)KeyEvent.WM_KEYUP || - wParam.ToUInt32() == (int)KeyEvent.WM_SYSKEYDOWN || - wParam.ToUInt32() == (int)KeyEvent.WM_SYSKEYUP) + var wParamValue = (int)wParam.Value; + if (wParamValue == (int)KeyEvent.WM_KEYDOWN || + wParamValue == (int)KeyEvent.WM_KEYUP || + wParamValue == (int)KeyEvent.WM_SYSKEYDOWN || + wParamValue == (int)KeyEvent.WM_SYSKEYUP) { if (hookedKeyboardCallback != null) - continues = hookedKeyboardCallback((KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), CheckModifiers()); + continues = hookedKeyboardCallback((KeyEvent)wParamValue, Marshal.ReadInt32(lParam), CheckModifiers()); } } if (continues) { - return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam); + return PInvoke.CallNextHookEx(hookId, nCode, wParam, lParam); } - return (IntPtr)(-1); + return new LRESULT(-1); } public void Dispose() { - InterceptKeys.UnhookWindowsHookEx(hookId); + PInvoke.UnhookWindowsHookEx(new HHOOK(hookId.DangerousGetHandle())); } ~GlobalHotkey() @@ -90,4 +92,4 @@ namespace Flow.Launcher.Infrastructure.Hotkey Dispose(); } } -} \ No newline at end of file +} diff --git a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs b/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs deleted file mode 100644 index d33bac34c..000000000 --- a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Flow.Launcher.Infrastructure.Hotkey -{ - internal static unsafe class InterceptKeys - { - public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam); - - private const int WH_KEYBOARD_LL = 13; - - public static IntPtr SetHook(delegate* unmanaged proc) - { - using (Process curProcess = Process.GetCurrentProcess()) - using (ProcessModule curModule = curProcess.MainModule) - { - return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0); - } - } - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr SetWindowsHookEx(int idHook, delegate* unmanaged lpfn, IntPtr hMod, uint dwThreadId); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool UnhookWindowsHookEx(IntPtr hhk); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr GetModuleHandle(string lpModuleName); - - [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] - public static extern short GetKeyState(int keyCode); - } -} \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs b/Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs index 15e306883..95bb25837 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs @@ -1,3 +1,5 @@ +using Windows.Win32; + namespace Flow.Launcher.Infrastructure.Hotkey { public enum KeyEvent @@ -5,21 +7,21 @@ namespace Flow.Launcher.Infrastructure.Hotkey /// /// Key down /// - WM_KEYDOWN = 256, + WM_KEYDOWN = (int)PInvoke.WM_KEYDOWN, /// /// Key up /// - WM_KEYUP = 257, + WM_KEYUP = (int)PInvoke.WM_KEYUP, /// /// System key up /// - WM_SYSKEYUP = 261, + WM_SYSKEYUP = (int)PInvoke.WM_SYSKEYUP, /// /// System key down /// - WM_SYSKEYDOWN = 260 + WM_SYSKEYDOWN = (int)PInvoke.WM_SYSKEYDOWN } -} \ No newline at end of file +} diff --git a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs index 247238bb6..49d6da8c2 100644 --- a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs +++ b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs @@ -1,12 +1,19 @@ using System; using System.Runtime.InteropServices; using System.IO; +using System.Windows; using System.Windows.Interop; using System.Windows.Media.Imaging; -using System.Windows; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.UI.Shell; +using Windows.Win32.Graphics.Gdi; namespace Flow.Launcher.Infrastructure.Image { + /// + /// Subclass of + /// [Flags] public enum ThumbnailOptions { @@ -22,91 +29,13 @@ namespace Flow.Launcher.Infrastructure.Image { // Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows - private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93"; - - [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern int SHCreateItemFromParsingName( - [MarshalAs(UnmanagedType.LPWStr)] string path, - IntPtr pbc, - ref Guid riid, - [MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem); - - [DllImport("gdi32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeleteObject(IntPtr hObject); - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] - internal interface IShellItem - { - void BindToHandler(IntPtr pbc, - [MarshalAs(UnmanagedType.LPStruct)]Guid bhid, - [MarshalAs(UnmanagedType.LPStruct)]Guid riid, - out IntPtr ppv); - - void GetParent(out IShellItem ppsi); - void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName); - void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); - void Compare(IShellItem psi, uint hint, out int piOrder); - }; - - internal enum SIGDN : uint - { - NORMALDISPLAY = 0, - PARENTRELATIVEPARSING = 0x80018001, - PARENTRELATIVEFORADDRESSBAR = 0x8001c001, - DESKTOPABSOLUTEPARSING = 0x80028000, - PARENTRELATIVEEDITING = 0x80031001, - DESKTOPABSOLUTEEDITING = 0x8004c000, - FILESYSPATH = 0x80058000, - URL = 0x80068000 - } - - internal enum HResult - { - Ok = 0x0000, - False = 0x0001, - InvalidArguments = unchecked((int)0x80070057), - OutOfMemory = unchecked((int)0x8007000E), - NoInterface = unchecked((int)0x80004002), - Fail = unchecked((int)0x80004005), - ExtractionFailed = unchecked((int)0x8004B200), - ElementNotFound = unchecked((int)0x80070490), - TypeElementNotFound = unchecked((int)0x8002802B), - NoObject = unchecked((int)0x800401E5), - Win32ErrorCanceled = 1223, - Canceled = unchecked((int)0x800704C7), - ResourceInUse = unchecked((int)0x800700AA), - AccessDenied = unchecked((int)0x80030005) - } - - [ComImportAttribute()] - [GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")] - [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IShellItemImageFactory - { - [PreserveSig] - HResult GetImage( - [In, MarshalAs(UnmanagedType.Struct)] NativeSize size, - [In] ThumbnailOptions flags, - [Out] out IntPtr phbm); - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NativeSize - { - private int width; - private int height; - - public int Width { set { width = value; } } - public int Height { set { height = value; } } - }; + private static readonly Guid GUID_IShellItem = typeof(IShellItem).GUID; + private static readonly HRESULT S_ExtractionFailed = (HRESULT)0x8004B200; public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options) { - IntPtr hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options); + HBITMAP hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options); try { @@ -115,39 +44,52 @@ namespace Flow.Launcher.Infrastructure.Image finally { // delete HBitmap to avoid memory leaks - DeleteObject(hBitmap); + PInvoke.DeleteObject(hBitmap); } } - - private static IntPtr GetHBitmap(string fileName, int width, int height, ThumbnailOptions options) - { - IShellItem nativeShellItem; - Guid shellItem2Guid = new Guid(IShellItem2Guid); - int retCode = SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem); - if (retCode != 0) + private static unsafe HBITMAP GetHBitmap(string fileName, int width, int height, ThumbnailOptions options) + { + var retCode = PInvoke.SHCreateItemFromParsingName( + fileName, + null, + GUID_IShellItem, + out var nativeShellItem); + + if (retCode != HRESULT.S_OK) throw Marshal.GetExceptionForHR(retCode); - NativeSize nativeSize = new NativeSize + if (nativeShellItem is not IShellItemImageFactory imageFactory) { - Width = width, - Height = height - }; - - IntPtr hBitmap; - HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, options, out hBitmap); - - // if extracting image thumbnail and failed, extract shell icon - if (options == ThumbnailOptions.ThumbnailOnly && hr == HResult.ExtractionFailed) - { - hr = ((IShellItemImageFactory) nativeShellItem).GetImage(nativeSize, ThumbnailOptions.IconOnly, out hBitmap); + Marshal.ReleaseComObject(nativeShellItem); + throw new InvalidOperationException("Failed to get IShellItemImageFactory"); } - Marshal.ReleaseComObject(nativeShellItem); + SIZE size = new SIZE + { + cx = width, + cy = height + }; - if (hr == HResult.Ok) return hBitmap; + HBITMAP hBitmap = default; + try + { + try + { + imageFactory.GetImage(size, (SIIGBF)options, &hBitmap); + } + catch (COMException ex) when (ex.HResult == S_ExtractionFailed && options == ThumbnailOptions.ThumbnailOnly) + { + // Fallback to IconOnly if ThumbnailOnly fails + imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); + } + } + finally + { + Marshal.ReleaseComObject(nativeShellItem); + } - throw new COMException($"Error while extracting thumbnail for {fileName}", Marshal.GetExceptionForHR((int)hr)); + return hBitmap; } } -} \ No newline at end of file +} diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt new file mode 100644 index 000000000..a083f79aa --- /dev/null +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -0,0 +1,20 @@ +SHCreateItemFromParsingName +DeleteObject +IShellItem +IShellItemImageFactory +ExtractionFailed +S_OK + +SetWindowsHookEx +UnhookWindowsHookEx +CallNextHookEx +GetModuleHandle +GetKeyState +VIRTUAL_KEY + +WM_KEYDOWN +WM_KEYUP +WM_SYSKEYDOWN +WM_SYSKEYUP + +EnumWindows \ No newline at end of file From ce8b42bc6edb3e5759c7700dd11c71dfb4bff1d4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 22:01:55 +0800 Subject: [PATCH 014/259] Replace DllImport & flags with CSWin32 --- Flow.Launcher/Flow.Launcher.csproj | 4 + Flow.Launcher/Helper/DWMDropShadow.cs | 19 ++-- .../Helper/WallpaperPathRetrieval.cs | 17 ++-- Flow.Launcher/Helper/WindowsInteropHelper.cs | 89 +++++++------------ Flow.Launcher/MainWindow.xaml.cs | 9 +- Flow.Launcher/NativeMethods.txt | 14 +++ 6 files changed, 65 insertions(+), 87 deletions(-) create mode 100644 Flow.Launcher/NativeMethods.txt diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index afc3fbbaa..7bd59e8c1 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -90,6 +90,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Flow.Launcher/Helper/DWMDropShadow.cs b/Flow.Launcher/Helper/DWMDropShadow.cs index e448acd4c..7cb719d07 100644 --- a/Flow.Launcher/Helper/DWMDropShadow.cs +++ b/Flow.Launcher/Helper/DWMDropShadow.cs @@ -1,20 +1,15 @@ using System; -using System.Drawing.Printing; -using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; +using Windows.Win32; +using Windows.Win32.Graphics.Dwm; +using Windows.Win32.UI.Controls; namespace Flow.Launcher.Helper; public class DwmDropShadow { - [DllImport("dwmapi.dll", PreserveSig = true)] - private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); - - [DllImport("dwmapi.dll")] - private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMarInset); - /// /// Drops a standard shadow to a WPF Window, even if the window isborderless. Only works with DWM (Vista and Seven). /// This method is much more efficient than setting AllowsTransparency to true and using the DropShadow effect, @@ -43,18 +38,18 @@ public class DwmDropShadow /// /// Window to which the shadow will be applied /// True if the method succeeded, false if not - private static bool DropShadow(Window window) + private unsafe static bool DropShadow(Window window) { try { WindowInteropHelper helper = new WindowInteropHelper(window); int val = 2; - int ret1 = DwmSetWindowAttribute(helper.Handle, 2, ref val, 4); + int ret1 = PInvoke.DwmSetWindowAttribute(new(helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4); if (ret1 == 0) { - Margins m = new Margins { Bottom = 0, Left = 0, Right = 0, Top = 0 }; - int ret2 = DwmExtendFrameIntoClientArea(helper.Handle, ref m); + var m = new MARGINS { cyBottomHeight = 0, cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0 }; + int ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m); return ret2 == 0; } else diff --git a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs index e08e227cc..8ab06e78d 100644 --- a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs +++ b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs @@ -1,24 +1,21 @@ -using System; -using System.Linq; -using System.Runtime.InteropServices; +using System.Linq; using System.Text; using System.Windows.Media; using Microsoft.Win32; +using Windows.Win32; +using Windows.Win32.UI.WindowsAndMessaging; namespace Flow.Launcher.Helper; public static class WallpaperPathRetrieval { - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - private static extern Int32 SystemParametersInfo(UInt32 action, - Int32 uParam, StringBuilder vParam, UInt32 winIni); - private static readonly UInt32 SPI_GETDESKWALLPAPER = 0x73; - private static int MAX_PATH = 260; + + private static readonly int MAX_PATH = 260; - public static string GetWallpaperPath() + public static unsafe string GetWallpaperPath() { var wallpaper = new StringBuilder(MAX_PATH); - SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0); + PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH, &wallpaper, 0); var str = wallpaper.ToString(); if (string.IsNullOrEmpty(str)) diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index 89fbec967..ae48034e8 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -1,75 +1,50 @@ using System; using System.Drawing; -using System.Runtime.InteropServices; -using System.Text; using System.Windows; using System.Windows.Forms; using System.Windows.Interop; using System.Windows.Media; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.UI.WindowsAndMessaging; using Point = System.Windows.Point; namespace Flow.Launcher.Helper; public class WindowsInteropHelper { - private const int GWL_STYLE = -16; //WPF's Message code for Title Bar's Style - private const int WS_SYSMENU = 0x80000; //WPF's Message code for System Menu - private static IntPtr _hwnd_shell; - private static IntPtr _hwnd_desktop; + private static HWND _hwnd_shell; + private static HWND _hwnd_desktop; //Accessors for shell and desktop handlers //Will set the variables once and then will return them - private static IntPtr HWND_SHELL + private static HWND HWND_SHELL { get { - return _hwnd_shell != IntPtr.Zero ? _hwnd_shell : _hwnd_shell = GetShellWindow(); + return _hwnd_shell != HWND.Null ? _hwnd_shell : _hwnd_shell = PInvoke.GetShellWindow(); } } - private static IntPtr HWND_DESKTOP + + private static HWND HWND_DESKTOP { get { - return _hwnd_desktop != IntPtr.Zero ? _hwnd_desktop : _hwnd_desktop = GetDesktopWindow(); + return _hwnd_desktop != HWND.Null ? _hwnd_desktop : _hwnd_desktop = PInvoke.GetDesktopWindow(); } } - [DllImport("user32.dll", SetLastError = true)] - internal static extern int GetWindowLong(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll")] - internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("user32.dll")] - internal static extern IntPtr GetForegroundWindow(); - - [DllImport("user32.dll")] - internal static extern IntPtr GetDesktopWindow(); - - [DllImport("user32.dll")] - internal static extern IntPtr GetShellWindow(); - - [DllImport("user32.dll", SetLastError = true)] - internal static extern int GetWindowRect(IntPtr hwnd, out RECT rc); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); - - [DllImport("user32.DLL")] - public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); - - const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass"; const string WINDOW_CLASS_WINTAB = "Flip3D"; const string WINDOW_CLASS_PROGMAN = "Progman"; const string WINDOW_CLASS_WORKERW = "WorkerW"; - public static bool IsWindowFullscreen() + public unsafe static bool IsWindowFullscreen() { //get current active window - IntPtr hWnd = GetForegroundWindow(); + var hWnd = PInvoke.GetForegroundWindow(); - if (hWnd.Equals(IntPtr.Zero)) + if (hWnd.Equals(HWND.Null)) { return false; } @@ -80,9 +55,16 @@ public class WindowsInteropHelper return false; } - StringBuilder sb = new StringBuilder(256); - GetClassName(hWnd, sb, sb.Capacity); - string windowClass = sb.ToString(); + string windowClass; + int capacity = 256; + char[] buffer = new char[capacity]; + fixed (char* pBuffer = buffer) + { + PInvoke.GetClassName(hWnd, pBuffer, capacity); + int validLength = Array.IndexOf(buffer, '\0'); + if (validLength < 0) validLength = capacity; + windowClass = new string(buffer, 0, validLength); + } //for Win+Tab (Flip3D) if (windowClass == WINDOW_CLASS_WINTAB) @@ -90,20 +72,19 @@ public class WindowsInteropHelper return false; } - RECT appBounds; - GetWindowRect(hWnd, out appBounds); + PInvoke.GetWindowRect(hWnd, out var appBounds); //for console (ConsoleWindowClass), we have to check for negative dimensions if (windowClass == WINDOW_CLASS_CONSOLE) { - return appBounds.Top < 0 && appBounds.Bottom < 0; + return appBounds.top < 0 && appBounds.bottom < 0; } //for desktop (Progman or WorkerW, depends on the system), we have to check if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW) { - IntPtr hWndDesktop = FindWindowEx(hWnd, IntPtr.Zero, "SHELLDLL_DefView", null); - hWndDesktop = FindWindowEx(hWndDesktop, IntPtr.Zero, "SysListView32", "FolderView"); + var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null); + hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView"); if (!hWndDesktop.Equals(IntPtr.Zero)) { return false; @@ -111,7 +92,7 @@ public class WindowsInteropHelper } Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds; - return (appBounds.Bottom - appBounds.Top) == screenBounds.Height && (appBounds.Right - appBounds.Left) == screenBounds.Width; + return (appBounds.bottom - appBounds.top) == screenBounds.Height && (appBounds.right - appBounds.left) == screenBounds.Width; } /// @@ -120,8 +101,8 @@ public class WindowsInteropHelper /// public static void DisableControlBox(Window win) { - var hwnd = new WindowInteropHelper(win).Handle; - SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU); + var hwnd = new HWND(new WindowInteropHelper(win).Handle); + PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE) & ~(int)WINDOW_STYLE.WS_SYSMENU); } /// @@ -146,14 +127,4 @@ public class WindowsInteropHelper } return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY)); } - - - [StructLayout(LayoutKind.Sequential)] - public struct RECT - { - public int Left; - public int Top; - public int Right; - public int Bottom; - } } diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 0f8b8f6d7..b4f1fb031 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -26,7 +26,7 @@ using System.Media; using DataObject = System.Windows.DataObject; using System.Windows.Media; using System.Windows.Interop; -using System.Runtime.InteropServices; +using Windows.Win32; namespace Flow.Launcher { @@ -34,9 +34,6 @@ namespace Flow.Launcher { #region Private Fields - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr SetForegroundWindow(IntPtr hwnd); - private readonly Storyboard _progressBarStoryboard = new Storyboard(); private bool isProgressBarStoryboardPaused; private Settings _settings; @@ -424,7 +421,7 @@ namespace Flow.Launcher // Get context menu handle and bring it to the foreground if (PresentationSource.FromVisual(contextMenu) is HwndSource hwndSource) { - _ = SetForegroundWindow(hwndSource.Handle); + PInvoke.SetForegroundWindow(new(hwndSource.Handle)); } contextMenu.Focus(); @@ -692,7 +689,7 @@ namespace Flow.Launcher screen = Screen.PrimaryScreen; break; case SearchWindowScreens.Focus: - IntPtr foregroundWindowHandle = WindowsInteropHelper.GetForegroundWindow(); + var foregroundWindowHandle = PInvoke.GetForegroundWindow().Value; screen = Screen.FromHandle(foregroundWindowHandle); break; case SearchWindowScreens.Custom: diff --git a/Flow.Launcher/NativeMethods.txt b/Flow.Launcher/NativeMethods.txt new file mode 100644 index 000000000..bbf55502e --- /dev/null +++ b/Flow.Launcher/NativeMethods.txt @@ -0,0 +1,14 @@ +DwmSetWindowAttribute +DwmExtendFrameIntoClientArea +SystemParametersInfo +SetForegroundWindow + +GetWindowLong +SetWindowLong +GetForegroundWindow +GetDesktopWindow +GetShellWindow +GetWindowRect +GetClassName +FindWindowEx +WINDOW_STYLE \ No newline at end of file From dbe626d2384865b0a90af2939d8a2e75c4e223e1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 11 Dec 2024 09:57:13 +0800 Subject: [PATCH 015/259] Fix key event return result issue --- .../Hotkey/GlobalHotkey.cs | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs index 75af843b9..04694ed16 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs @@ -15,20 +15,23 @@ namespace Flow.Launcher.Infrastructure.Hotkey /// public unsafe class GlobalHotkey : IDisposable { + private static readonly HOOKPROC _procKeyboard = HookKeyboardCallback; private static readonly UnhookWindowsHookExSafeHandle hookId; - public delegate bool KeyboardCallback(int keyEvent, int vkCode, SpecialKeyState state); + public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state); internal static Func hookedKeyboardCallback; static GlobalHotkey() { // Set the hook - using Process curProcess = Process.GetCurrentProcess(); - using ProcessModule curModule = curProcess.MainModule; - hookId = PInvoke.SetWindowsHookEx( - WINDOWS_HOOK_ID.WH_KEYBOARD_LL, - LowLevelKeyboardProc, - PInvoke.GetModuleHandle(curModule.ModuleName), 0); + hookId = SetHook(_procKeyboard, WINDOWS_HOOK_ID.WH_KEYBOARD_LL); + } + + private static UnhookWindowsHookExSafeHandle SetHook(HOOKPROC proc, WINDOWS_HOOK_ID hookId) + { + using var curProcess = Process.GetCurrentProcess(); + using var curModule = curProcess.MainModule; + return PInvoke.SetWindowsHookEx(hookId, proc, PInvoke.GetModuleHandle(curModule.ModuleName), 0); } public static SpecialKeyState CheckModifiers() @@ -58,20 +61,19 @@ namespace Flow.Launcher.Infrastructure.Hotkey return state; } - private static LRESULT LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) + private static LRESULT HookKeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam) { bool continues = true; if (nCode >= 0) { - var wParamValue = (int)wParam.Value; - if (wParamValue == (int)KeyEvent.WM_KEYDOWN || - wParamValue == (int)KeyEvent.WM_KEYUP || - wParamValue == (int)KeyEvent.WM_SYSKEYDOWN || - wParamValue == (int)KeyEvent.WM_SYSKEYUP) + if (wParam.Value == (int)KeyEvent.WM_KEYDOWN || + wParam.Value == (int)KeyEvent.WM_KEYUP || + wParam.Value == (int)KeyEvent.WM_SYSKEYDOWN || + wParam.Value == (int)KeyEvent.WM_SYSKEYUP) { if (hookedKeyboardCallback != null) - continues = hookedKeyboardCallback((KeyEvent)wParamValue, Marshal.ReadInt32(lParam), CheckModifiers()); + continues = hookedKeyboardCallback((KeyEvent)wParam.Value, Marshal.ReadInt32(lParam), CheckModifiers()); } } @@ -79,7 +81,8 @@ namespace Flow.Launcher.Infrastructure.Hotkey { return PInvoke.CallNextHookEx(hookId, nCode, wParam, lParam); } - return new LRESULT(-1); + + return new LRESULT(1); } public void Dispose() From be72bb73aa8b1783c6ec9877f8067096e5a7ac84 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 11 Dec 2024 09:57:49 +0800 Subject: [PATCH 016/259] Fix VIRTUAL_KEY.VK_RWIN check issue --- Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs index 04694ed16..2bc7db9bf 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs @@ -52,7 +52,8 @@ namespace Flow.Launcher.Infrastructure.Hotkey //ALT is pressed state.AltPressed = true; } - if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0 || + (PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RWIN) & 0x8000) != 0) { //WIN is pressed state.WinPressed = true; From 49fc0b8fd07d5856eb265981e6dbccaad834d2a3 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 11 Dec 2024 10:04:03 +0800 Subject: [PATCH 017/259] Remove useless DllImport & flags --- Flow.Launcher/Helper/SingleInstance.cs | 226 ------------------------- 1 file changed, 226 deletions(-) diff --git a/Flow.Launcher/Helper/SingleInstance.cs b/Flow.Launcher/Helper/SingleInstance.cs index 739fed378..e0e3075f6 100644 --- a/Flow.Launcher/Helper/SingleInstance.cs +++ b/Flow.Launcher/Helper/SingleInstance.cs @@ -1,11 +1,5 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Runtime.InteropServices; using System.IO.Pipes; -using System.Security; -using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -14,172 +8,6 @@ using System.Windows; // modified to allow single instace restart namespace Flow.Launcher.Helper { - internal enum WM - { - NULL = 0x0000, - CREATE = 0x0001, - DESTROY = 0x0002, - MOVE = 0x0003, - SIZE = 0x0005, - ACTIVATE = 0x0006, - SETFOCUS = 0x0007, - KILLFOCUS = 0x0008, - ENABLE = 0x000A, - SETREDRAW = 0x000B, - SETTEXT = 0x000C, - GETTEXT = 0x000D, - GETTEXTLENGTH = 0x000E, - PAINT = 0x000F, - CLOSE = 0x0010, - QUERYENDSESSION = 0x0011, - QUIT = 0x0012, - QUERYOPEN = 0x0013, - ERASEBKGND = 0x0014, - SYSCOLORCHANGE = 0x0015, - SHOWWINDOW = 0x0018, - ACTIVATEAPP = 0x001C, - SETCURSOR = 0x0020, - MOUSEACTIVATE = 0x0021, - CHILDACTIVATE = 0x0022, - QUEUESYNC = 0x0023, - GETMINMAXINFO = 0x0024, - - WINDOWPOSCHANGING = 0x0046, - WINDOWPOSCHANGED = 0x0047, - - CONTEXTMENU = 0x007B, - STYLECHANGING = 0x007C, - STYLECHANGED = 0x007D, - DISPLAYCHANGE = 0x007E, - GETICON = 0x007F, - SETICON = 0x0080, - NCCREATE = 0x0081, - NCDESTROY = 0x0082, - NCCALCSIZE = 0x0083, - NCHITTEST = 0x0084, - NCPAINT = 0x0085, - NCACTIVATE = 0x0086, - GETDLGCODE = 0x0087, - SYNCPAINT = 0x0088, - NCMOUSEMOVE = 0x00A0, - NCLBUTTONDOWN = 0x00A1, - NCLBUTTONUP = 0x00A2, - NCLBUTTONDBLCLK = 0x00A3, - NCRBUTTONDOWN = 0x00A4, - NCRBUTTONUP = 0x00A5, - NCRBUTTONDBLCLK = 0x00A6, - NCMBUTTONDOWN = 0x00A7, - NCMBUTTONUP = 0x00A8, - NCMBUTTONDBLCLK = 0x00A9, - - SYSKEYDOWN = 0x0104, - SYSKEYUP = 0x0105, - SYSCHAR = 0x0106, - SYSDEADCHAR = 0x0107, - COMMAND = 0x0111, - SYSCOMMAND = 0x0112, - - MOUSEMOVE = 0x0200, - LBUTTONDOWN = 0x0201, - LBUTTONUP = 0x0202, - LBUTTONDBLCLK = 0x0203, - RBUTTONDOWN = 0x0204, - RBUTTONUP = 0x0205, - RBUTTONDBLCLK = 0x0206, - MBUTTONDOWN = 0x0207, - MBUTTONUP = 0x0208, - MBUTTONDBLCLK = 0x0209, - MOUSEWHEEL = 0x020A, - XBUTTONDOWN = 0x020B, - XBUTTONUP = 0x020C, - XBUTTONDBLCLK = 0x020D, - MOUSEHWHEEL = 0x020E, - - - CAPTURECHANGED = 0x0215, - - ENTERSIZEMOVE = 0x0231, - EXITSIZEMOVE = 0x0232, - - IME_SETCONTEXT = 0x0281, - IME_NOTIFY = 0x0282, - IME_CONTROL = 0x0283, - IME_COMPOSITIONFULL = 0x0284, - IME_SELECT = 0x0285, - IME_CHAR = 0x0286, - IME_REQUEST = 0x0288, - IME_KEYDOWN = 0x0290, - IME_KEYUP = 0x0291, - - NCMOUSELEAVE = 0x02A2, - - DWMCOMPOSITIONCHANGED = 0x031E, - DWMNCRENDERINGCHANGED = 0x031F, - DWMCOLORIZATIONCOLORCHANGED = 0x0320, - DWMWINDOWMAXIMIZEDCHANGE = 0x0321, - - #region Windows 7 - DWMSENDICONICTHUMBNAIL = 0x0323, - DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326, - #endregion - - USER = 0x0400, - - // This is the hard-coded message value used by WinForms for Shell_NotifyIcon. - // It's relatively safe to reuse. - TRAYMOUSEMESSAGE = 0x800, //WM_USER + 1024 - APP = 0x8000 - } - - [SuppressUnmanagedCodeSecurity] - internal static class NativeMethods - { - /// - /// Delegate declaration that matches WndProc signatures. - /// - public delegate IntPtr MessageHandler(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled); - - [DllImport("shell32.dll", EntryPoint = "CommandLineToArgvW", CharSet = CharSet.Unicode)] - private static extern IntPtr _CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string cmdLine, out int numArgs); - - - [DllImport("kernel32.dll", EntryPoint = "LocalFree", SetLastError = true)] - private static extern IntPtr _LocalFree(IntPtr hMem); - - - public static string[] CommandLineToArgvW(string cmdLine) - { - IntPtr argv = IntPtr.Zero; - try - { - int numArgs = 0; - - argv = _CommandLineToArgvW(cmdLine, out numArgs); - if (argv == IntPtr.Zero) - { - throw new Win32Exception(); - } - var result = new string[numArgs]; - - for (int i = 0; i < numArgs; i++) - { - IntPtr currArg = Marshal.ReadIntPtr(argv, i * Marshal.SizeOf(typeof(IntPtr))); - result[i] = Marshal.PtrToStringUni(currArg); - } - - return result; - } - finally - { - - IntPtr p = _LocalFree(argv); - // Otherwise LocalFree failed. - // Assert.AreEqual(IntPtr.Zero, p); - } - } - - } - public interface ISingleInstanceApp { void OnSecondAppStarted(); @@ -219,10 +47,6 @@ namespace Flow.Launcher.Helper #endregion - #region Public Properties - - #endregion - #region Public Methods /// @@ -264,56 +88,6 @@ namespace Flow.Launcher.Helper #region Private Methods - /// - /// Gets command line args - for ClickOnce deployed applications, command line args may not be passed directly, they have to be retrieved. - /// - /// List of command line arg strings. - private static IList GetCommandLineArgs( string uniqueApplicationName ) - { - string[] args = null; - - try - { - // The application was not clickonce deployed, get args from standard API's - args = Environment.GetCommandLineArgs(); - } - catch (NotSupportedException) - { - - // The application was clickonce deployed - // Clickonce deployed apps cannot recieve traditional commandline arguments - // As a workaround commandline arguments can be written to a shared location before - // the app is launched and the app can obtain its commandline arguments from the - // shared location - string appFolderPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), uniqueApplicationName); - - string cmdLinePath = Path.Combine(appFolderPath, "cmdline.txt"); - if (File.Exists(cmdLinePath)) - { - try - { - using (TextReader reader = new StreamReader(cmdLinePath, Encoding.Unicode)) - { - args = NativeMethods.CommandLineToArgvW(reader.ReadToEnd()); - } - - File.Delete(cmdLinePath); - } - catch (IOException) - { - } - } - } - - if (args == null) - { - args = new string[] { }; - } - - return new List(args); - } - /// /// Creates a remote server pipe for communication. /// Once receives signal from client, will activate first instance. From 8a05c606e4ce63ecdde6aacf8b3d6ae7b778f91d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 11 Dec 2024 11:08:57 +0800 Subject: [PATCH 018/259] Fix possible double release --- Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs index 49d6da8c2..2fb8cf363 100644 --- a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs +++ b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs @@ -62,6 +62,7 @@ namespace Flow.Launcher.Infrastructure.Image if (nativeShellItem is not IShellItemImageFactory imageFactory) { Marshal.ReleaseComObject(nativeShellItem); + nativeShellItem = null; throw new InvalidOperationException("Failed to get IShellItemImageFactory"); } @@ -86,7 +87,10 @@ namespace Flow.Launcher.Infrastructure.Image } finally { - Marshal.ReleaseComObject(nativeShellItem); + if (nativeShellItem != null) + { + Marshal.ReleaseComObject(nativeShellItem); + } } return hBitmap; From a088f91541ea18c637c368706443793739acdc46 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 14 Dec 2024 11:17:29 +0800 Subject: [PATCH 019/259] Add comments for string truncation --- Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs | 1 + Flow.Launcher/Helper/WindowsInteropHelper.cs | 2 ++ Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs | 1 + .../Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs | 2 ++ 4 files changed, 6 insertions(+) diff --git a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs index 191a76309..9639f1b1a 100644 --- a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs +++ b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs @@ -62,6 +62,7 @@ namespace Flow.Launcher.Plugin.SharedCommands return string.Empty; } + // Truncate the buffer to the actual length of the string int validLength = Array.IndexOf(buffer, '\0'); if (validLength < 0) validLength = capacity; return new string(buffer, 0, validLength); diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index ae48034e8..6656b0c5b 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -61,6 +61,8 @@ public class WindowsInteropHelper fixed (char* pBuffer = buffer) { PInvoke.GetClassName(hWnd, pBuffer, capacity); + + // Truncate the buffer to the actual length of the string int validLength = Array.IndexOf(buffer, '\0'); if (validLength < 0) validLength = capacity; windowClass = new string(buffer, 0, validLength); diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs index 6df12fae9..abc254d86 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs @@ -106,6 +106,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller return string.Empty; } + // Truncate the buffer to the actual length of the string int validLength = Array.IndexOf(buffer, '\0'); if (validLength < 0) validLength = (int)capacity; return new string(buffer, 0, validLength); diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index fae9c84c9..05cbfd2b1 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -38,6 +38,8 @@ namespace Flow.Launcher.Plugin.Program.Programs fixed (char* bufferChar = buffer) { ((IShellLinkW)link).GetPath((PWSTR)bufferChar, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); + + // Truncate the buffer to the actual length of the string int validLength = Array.IndexOf(buffer, '\0'); if (validLength < 0) validLength = MAX_PATH; target = new string(buffer, 0, validLength); From a899ff83e5a336505cdf0b64d2ef48f2d1fd417a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 14 Dec 2024 11:46:09 +0800 Subject: [PATCH 020/259] Improve code quality --- .../Programs/ShellLinkHelper.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index 05cbfd2b1..ad1f3ab56 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -38,11 +38,7 @@ namespace Flow.Launcher.Plugin.Program.Programs fixed (char* bufferChar = buffer) { ((IShellLinkW)link).GetPath((PWSTR)bufferChar, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); - - // Truncate the buffer to the actual length of the string - int validLength = Array.IndexOf(buffer, '\0'); - if (validLength < 0) validLength = MAX_PATH; - target = new string(buffer, 0, validLength); + target = GetStringFromBuffer(buffer, MAX_PATH); } // To set the app description @@ -54,9 +50,7 @@ namespace Flow.Launcher.Plugin.Program.Programs fixed (char* buffer1Char = buffer1) { ((IShellLinkW)link).GetDescription((PWSTR)buffer1Char, MAX_PATH); - int validLength = Array.IndexOf(buffer1, '\0'); - if (validLength < 0) validLength = MAX_PATH; - description = new string(buffer1, 0, validLength); + description = GetStringFromBuffer(buffer1, MAX_PATH); } } catch (COMException e) @@ -71,9 +65,7 @@ namespace Flow.Launcher.Plugin.Program.Programs fixed (char* buffer2Char = buffer2) { ((IShellLinkW)link).GetArguments((PWSTR)buffer2Char, MAX_PATH); - int validLength = Array.IndexOf(buffer2, '\0'); - if (validLength < 0) validLength = MAX_PATH; - arguments = new string(buffer2, 0, validLength); + arguments = GetStringFromBuffer(buffer2, MAX_PATH); } } @@ -82,5 +74,13 @@ namespace Flow.Launcher.Plugin.Program.Programs return target; } + + private static unsafe string GetStringFromBuffer(char[] buffer, int maxLength) + { + // Truncate the buffer to the actual length of the string + int validLength = Array.IndexOf(buffer, '\0'); + if (validLength < 0) validLength = maxLength; + return new string(buffer, 0, validLength); + } } } From b96c7b12d51ec89b3355c8bc7a241f8173935d10 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 14 Dec 2024 11:51:13 +0800 Subject: [PATCH 021/259] Remove useless PInvoke method import --- Flow.Launcher.Infrastructure/NativeMethods.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index a083f79aa..f117534a1 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -2,7 +2,6 @@ DeleteObject IShellItem IShellItemImageFactory -ExtractionFailed S_OK SetWindowsHookEx From 532b5dc4c90b03399136299cc514aecd65d59eb5 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 19 Dec 2024 14:08:46 +0800 Subject: [PATCH 022/259] Replace flags with CSWin32 --- Flow.Launcher/MainWindow.xaml.cs | 6 ++---- Flow.Launcher/NativeMethods.txt | 5 ++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index b4f1fb031..8ca153afc 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -78,21 +78,19 @@ namespace Flow.Launcher InitializeComponent(); } - private const int WM_ENTERSIZEMOVE = 0x0231; - private const int WM_EXITSIZEMOVE = 0x0232; private int _initialWidth; private int _initialHeight; private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { - if (msg == WM_ENTERSIZEMOVE) + if (msg == PInvoke.WM_ENTERSIZEMOVE) { _initialWidth = (int)Width; _initialHeight = (int)Height; handled = true; } - if (msg == WM_EXITSIZEMOVE) + if (msg == PInvoke.WM_EXITSIZEMOVE) { if (_initialHeight != (int)Height) { diff --git a/Flow.Launcher/NativeMethods.txt b/Flow.Launcher/NativeMethods.txt index bbf55502e..2b147c05f 100644 --- a/Flow.Launcher/NativeMethods.txt +++ b/Flow.Launcher/NativeMethods.txt @@ -11,4 +11,7 @@ GetShellWindow GetWindowRect GetClassName FindWindowEx -WINDOW_STYLE \ No newline at end of file +WINDOW_STYLE + +WM_ENTERSIZEMOVE +WM_EXITSIZEMOVE \ No newline at end of file From 3ab1fb15b639f13fa46ab5fcfceb581e20b3682a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 19 Dec 2024 16:34:32 +0800 Subject: [PATCH 023/259] Fix clipboard action under sta thread issue --- .../NativeMethods.txt | 5 +- .../UserSettings/Settings.cs | 2 +- Flow.Launcher.Infrastructure/Win32Helper.cs | 141 ++++++++++++++++++ Flow.Launcher/PublicAPIInstance.cs | 45 +++--- 4 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 Flow.Launcher.Infrastructure/Win32Helper.cs diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index f117534a1..d8777ff27 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -16,4 +16,7 @@ WM_KEYUP WM_SYSKEYDOWN WM_SYSKEYUP -EnumWindows \ No newline at end of file +EnumWindows + +OleInitialize +OleUninitialize \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 0c7de10fd..5493ad724 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -230,7 +230,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings [JsonIgnore] public ObservableCollection BuiltinShortcuts { get; set; } = new() { - new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText), + new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", () => Win32Helper.StartSTATaskAsync(Clipboard.GetText).Result), new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath) }; diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs new file mode 100644 index 000000000..76e9cfe5b --- /dev/null +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -0,0 +1,141 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Windows.Win32; + +namespace Flow.Launcher.Infrastructure +{ + /// + /// Provides static helper for Win32. + /// Codes are edited from: https://github.com/files-community/Files. + /// + public static class Win32Helper + { + public static Task StartSTATaskAsync(Action action) + { + var taskCompletionSource = new TaskCompletionSource(); + Thread thread = new(() => + { + PInvoke.OleInitialize(); + + try + { + action(); + taskCompletionSource.SetResult(); + } + catch (System.Exception) + { + taskCompletionSource.SetResult(); + } + finally + { + PInvoke.OleUninitialize(); + } + }) + { + IsBackground = true, + Priority = ThreadPriority.Normal + }; + + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + + return taskCompletionSource.Task; + } + + public static Task StartSTATaskAsync(Func func) + { + var taskCompletionSource = new TaskCompletionSource(); + Thread thread = new(async () => + { + PInvoke.OleInitialize(); + + try + { + await func(); + taskCompletionSource.SetResult(); + } + catch (System.Exception) + { + taskCompletionSource.SetResult(); + } + finally + { + PInvoke.OleUninitialize(); + } + }) + { + IsBackground = true, + Priority = ThreadPriority.Normal + }; + + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + + return taskCompletionSource.Task; + } + + public static Task StartSTATaskAsync(Func func) + { + var taskCompletionSource = new TaskCompletionSource(); + + Thread thread = new(() => + { + PInvoke.OleInitialize(); + + try + { + taskCompletionSource.SetResult(func()); + } + catch (System.Exception) + { + taskCompletionSource.SetResult(default); + } + finally + { + PInvoke.OleUninitialize(); + } + }) + { + IsBackground = true, + Priority = ThreadPriority.Normal + }; + + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + + return taskCompletionSource.Task; + } + + public static Task StartSTATaskAsync(Func> func) + { + var taskCompletionSource = new TaskCompletionSource(); + + Thread thread = new(async () => + { + PInvoke.OleInitialize(); + try + { + taskCompletionSource.SetResult(await func()); + } + catch (System.Exception) + { + taskCompletionSource.SetResult(default); + } + finally + { + PInvoke.OleUninitialize(); + } + }) + { + IsBackground = true, + Priority = ThreadPriority.Normal + }; + + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + + return taskCompletionSource.Task; + } + } +} diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index f4712770d..dcdb798ff 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; @@ -117,35 +117,38 @@ namespace Flow.Launcher ShellCommand.Execute(startInfo); } - public void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true) + public async void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true) { if (string.IsNullOrEmpty(stringToCopy)) return; - var isFile = File.Exists(stringToCopy); - if (directCopy && (isFile || Directory.Exists(stringToCopy))) + await Win32Helper.StartSTATaskAsync(() => { - var paths = new StringCollection + var isFile = File.Exists(stringToCopy); + if (directCopy && (isFile || Directory.Exists(stringToCopy))) { - stringToCopy - }; + var paths = new StringCollection + { + stringToCopy + }; - Clipboard.SetFileDropList(paths); + Clipboard.SetFileDropList(paths); - if (showDefaultNotification) - ShowMsg( - $"{GetTranslation("copy")} {(isFile ? GetTranslation("fileTitle") : GetTranslation("folderTitle"))}", - GetTranslation("completedSuccessfully")); - } - else - { - Clipboard.SetDataObject(stringToCopy); + if (showDefaultNotification) + ShowMsg( + $"{GetTranslation("copy")} {(isFile ? GetTranslation("fileTitle") : GetTranslation("folderTitle"))}", + GetTranslation("completedSuccessfully")); + } + else + { + Clipboard.SetDataObject(stringToCopy); - if (showDefaultNotification) - ShowMsg( - $"{GetTranslation("copy")} {GetTranslation("textTitle")}", - GetTranslation("completedSuccessfully")); - } + if (showDefaultNotification) + ShowMsg( + $"{GetTranslation("copy")} {GetTranslation("textTitle")}", + GetTranslation("completedSuccessfully")); + } + }); } public void StartLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Visible; From 1073821b655e3dd29062fd19cc4a6f2b976aa292 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 20 Dec 2024 18:55:57 +0800 Subject: [PATCH 024/259] Improve recyble bin clear issue noticification --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 8bcd5cd6b..5bfc68ea6 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -252,8 +252,10 @@ namespace Flow.Launcher.Plugin.Sys var result = PInvoke.SHEmptyRecycleBin(new(), string.Empty, 0); if (result != HRESULT.S_OK && result != HRESULT.E_UNEXPECTED) { - context.API.ShowMsgBox($"Error emptying recycle bin, error code: {result}\n" + - "please refer to https://msdn.microsoft.com/en-us/library/windows/desktop/aa378137", + context.API.ShowMsgBox("Failed to empty the recycle bin. This might happen if:\n" + + "- A file in the recycle bin is in use\n" + + "- You don't have permission to delete some items\n" + + "Please close any applications that might be using these files and try again.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } From 6f899092b59a344b3ceb3d2edd28700e585c7335 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 24 Dec 2024 11:59:04 +0800 Subject: [PATCH 025/259] Move dll import codes to win32 helper --- Flow.Launcher.Core/Resource/Theme.cs | 98 +----------------- Flow.Launcher.Infrastructure/Win32Helper.cs | 106 +++++++++++++++++++- 2 files changed, 104 insertions(+), 100 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 0d8c0d901..1d8409306 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -3,10 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml; -using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; -using System.Windows.Interop; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Effects; @@ -98,12 +96,12 @@ namespace Flow.Launcher.Core.Resource _oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath); } - BlurEnabled = IsBlurTheme(); + BlurEnabled = Win32Helper.IsBlurTheme(); if (Settings.UseDropShadowEffect && !BlurEnabled) AddDropShadowEffectToCurrentTheme(); - SetBlurForWindow(); + Win32Helper.SetBlurForWindow(Application.Current.MainWindow, BlurEnabled); } catch (DirectoryNotFoundException) { @@ -357,98 +355,6 @@ namespace Flow.Launcher.Core.Resource UpdateResourceDictionary(dict); } - #region Blur Handling - /* - Found on https://github.com/riverar/sample-win10-aeroglass - */ - private enum AccentState - { - ACCENT_DISABLED = 0, - ACCENT_ENABLE_GRADIENT = 1, - ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, - ACCENT_ENABLE_BLURBEHIND = 3, - ACCENT_INVALID_STATE = 4 - } - - [StructLayout(LayoutKind.Sequential)] - private struct AccentPolicy - { - public AccentState AccentState; - public int AccentFlags; - public int GradientColor; - public int AnimationId; - } - - [StructLayout(LayoutKind.Sequential)] - private struct WindowCompositionAttributeData - { - public WindowCompositionAttribute Attribute; - public IntPtr Data; - public int SizeOfData; - } - - private enum WindowCompositionAttribute - { - WCA_ACCENT_POLICY = 19 - } - [DllImport("user32.dll")] - private static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data); - - /// - /// Sets the blur for a window via SetWindowCompositionAttribute - /// - public void SetBlurForWindow() - { - if (BlurEnabled) - { - SetWindowAccent(Application.Current.MainWindow, AccentState.ACCENT_ENABLE_BLURBEHIND); - } - else - { - SetWindowAccent(Application.Current.MainWindow, AccentState.ACCENT_DISABLED); - } - } - - private bool IsBlurTheme() - { - if (Environment.OSVersion.Version >= new Version(6, 2)) - { - var resource = Application.Current.TryFindResource("ThemeBlurEnabled"); - - if (resource is bool) - return (bool)resource; - - return false; - } - - return false; - } - - private void SetWindowAccent(Window w, AccentState state) - { - var windowHelper = new WindowInteropHelper(w); - - windowHelper.EnsureHandle(); - - var accent = new AccentPolicy { AccentState = state }; - var accentStructSize = Marshal.SizeOf(accent); - - var accentPtr = Marshal.AllocHGlobal(accentStructSize); - Marshal.StructureToPtr(accent, accentPtr, false); - - var data = new WindowCompositionAttributeData - { - Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY, - SizeOfData = accentStructSize, - Data = accentPtr - }; - - SetWindowCompositionAttribute(windowHelper.Handle, ref data); - - Marshal.FreeHGlobal(accentPtr); - } - #endregion - public record ThemeData(string FileNameWithoutExtension, string Name, bool? IsDark = null, bool? HasBlur = null); } } diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 76e9cfe5b..6d6c72864 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -1,16 +1,21 @@ using System; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using System.Windows.Interop; +using System.Windows; using Windows.Win32; namespace Flow.Launcher.Infrastructure { - /// - /// Provides static helper for Win32. - /// Codes are edited from: https://github.com/files-community/Files. - /// public static class Win32Helper { + #region STA Thread + + /* + Found on https://github.com/files-community/Files + */ + public static Task StartSTATaskAsync(Action action) { var taskCompletionSource = new TaskCompletionSource(); @@ -137,5 +142,98 @@ namespace Flow.Launcher.Infrastructure return taskCompletionSource.Task; } + + #endregion + + #region Blur Handling + + /* + Found on https://github.com/riverar/sample-win10-aeroglass + */ + + private enum AccentState + { + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_INVALID_STATE = 4 + } + + [StructLayout(LayoutKind.Sequential)] + private struct AccentPolicy + { + public AccentState AccentState; + public int AccentFlags; + public int GradientColor; + public int AnimationId; + } + + [StructLayout(LayoutKind.Sequential)] + private struct WindowCompositionAttributeData + { + public WindowCompositionAttribute Attribute; + public IntPtr Data; + public int SizeOfData; + } + + private enum WindowCompositionAttribute + { + WCA_ACCENT_POLICY = 19 + } + + [DllImport("user32.dll")] + private static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data); + + /// + /// Checks if the blur theme is enabled + /// + public static bool IsBlurTheme() + { + if (Environment.OSVersion.Version >= new Version(6, 2)) + { + var resource = Application.Current.TryFindResource("ThemeBlurEnabled"); + + if (resource is bool b) + return b; + + return false; + } + + return false; + } + + /// + /// Sets the blur for a window via SetWindowCompositionAttribute + /// + public static void SetBlurForWindow(Window w, bool blur) + { + SetWindowAccent(w, blur ? AccentState.ACCENT_ENABLE_BLURBEHIND : AccentState.ACCENT_DISABLED); + } + + private static void SetWindowAccent(Window w, AccentState state) + { + var windowHelper = new WindowInteropHelper(w); + + windowHelper.EnsureHandle(); + + var accent = new AccentPolicy { AccentState = state }; + var accentStructSize = Marshal.SizeOf(accent); + + var accentPtr = Marshal.AllocHGlobal(accentStructSize); + Marshal.StructureToPtr(accent, accentPtr, false); + + var data = new WindowCompositionAttributeData + { + Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY, + SizeOfData = accentStructSize, + Data = accentPtr + }; + + SetWindowCompositionAttribute(windowHelper.Handle, ref data); + + Marshal.FreeHGlobal(accentPtr); + } + #endregion } } From 51a16cc40f8159f6e54d772df16e5ae0466be989 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 6 Dec 2024 23:55:20 -0600 Subject: [PATCH 026/259] Remove Result comparison and Change signature from IEnumerable to ICollection (due to the potential of multiple enumeration) --- Flow.Launcher.Plugin/Result.cs | 21 --------------------- Flow.Launcher/ViewModel/ResultsViewModel.cs | 6 +++--- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index f2050cc9f..c6ca81cf3 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -157,27 +157,6 @@ namespace Flow.Launcher.Plugin } } - /// - public override bool Equals(object obj) - { - var r = obj as Result; - - var equality = string.Equals(r?.Title, Title) && - string.Equals(r?.SubTitle, SubTitle) && - string.Equals(r?.AutoCompleteText, AutoCompleteText) && - string.Equals(r?.CopyText, CopyText) && - string.Equals(r?.IcoPath, IcoPath) && - TitleHighlightData == r.TitleHighlightData; - - return equality; - } - - /// - public override int GetHashCode() - { - return HashCode.Combine(Title, SubTitle, AutoCompleteText, CopyText, IcoPath); - } - /// public override string ToString() { diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 107372e01..c0e0b146d 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -182,7 +182,7 @@ namespace Flow.Launcher.ViewModel /// /// To avoid deadlock, this method should not called from main thread /// - public void AddResults(IEnumerable resultsForUpdates, CancellationToken token, bool reselect = true) + public void AddResults(ICollection resultsForUpdates, CancellationToken token, bool reselect = true) { var newResults = NewResults(resultsForUpdates); @@ -228,12 +228,12 @@ namespace Flow.Launcher.ViewModel .ToList(); } - private List NewResults(IEnumerable resultsForUpdates) + private List NewResults(ICollection resultsForUpdates) { if (!resultsForUpdates.Any()) return Results; - return Results.Where(r => r != null && !resultsForUpdates.Any(u => u.ID == r.Result.PluginID)) + return Results.Where(r => r != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) .Concat(resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings))) .OrderByDescending(rv => rv.Result.Score) .ToList(); From 5f6ac6a35e38c301ffb2b8b2fdc5af95869b3703 Mon Sep 17 00:00:00 2001 From: Kevin Zhang <45326534+taooceros@users.noreply.github.com> Date: Sat, 7 Dec 2024 12:48:15 -0600 Subject: [PATCH 027/259] Update Flow.Launcher/ViewModel/ResultsViewModel.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index c0e0b146d..7d2b5bc93 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -233,7 +233,7 @@ namespace Flow.Launcher.ViewModel if (!resultsForUpdates.Any()) return Results; - return Results.Where(r => r != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) + return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) .Concat(resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings))) .OrderByDescending(rv => rv.Result.Score) .ToList(); From 0153f71083b755ff2df85c16757e7341e4069d2e Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Wed, 25 Dec 2024 11:20:09 -0600 Subject: [PATCH 028/259] use stackalloc if possible and fix some incorrect use of safehandle --- .../Hotkey/GlobalHotkey.cs | 2 +- .../SharedCommands/ShellCommand.cs | 19 +++---- Flow.Launcher/Helper/DWMDropShadow.cs | 17 +++--- .../Helper/WallpaperPathRetrieval.cs | 24 +++++---- Flow.Launcher/Helper/WindowsInteropHelper.cs | 41 +++++++++++---- .../ProcessHelper.cs | 7 +-- .../Programs/ShellLinkHelper.cs | 30 ++++------- .../Programs/ShellLocalization.cs | 52 +++++++++---------- 8 files changed, 96 insertions(+), 96 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs index 2bc7db9bf..b2a140755 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs @@ -88,7 +88,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey public void Dispose() { - PInvoke.UnhookWindowsHookEx(new HHOOK(hookId.DangerousGetHandle())); + hookId.Dispose(); } ~GlobalHotkey() diff --git a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs index 9639f1b1a..9ea582118 100644 --- a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs +++ b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs @@ -25,6 +25,7 @@ namespace Flow.Launcher.Plugin.SharedCommands CheckSecurityWindow(); Thread.Sleep(25); } + while (containsSecurityWindow) // while this process contains a "Windows Security" dialog, stay open { containsSecurityWindow = false; @@ -52,24 +53,20 @@ namespace Flow.Launcher.Plugin.SharedCommands private static unsafe string GetWindowTitle(HWND hwnd) { var capacity = PInvoke.GetWindowTextLength(hwnd) + 1; - char[] buffer = new char[capacity]; + int length; + Span buffer = stackalloc char[capacity]; fixed (char* pBuffer = buffer) { // If the window has no title bar or text, if the title bar is empty, // or if the window or control handle is invalid, the return value is zero. - if (PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity) == 0) - { - return string.Empty; - } - - // Truncate the buffer to the actual length of the string - int validLength = Array.IndexOf(buffer, '\0'); - if (validLength < 0) validLength = capacity; - return new string(buffer, 0, validLength); + length = PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity); } + + return buffer[..length].ToString(); } - public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "", bool createNoWindow = false) + public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", + string arguments = "", string verb = "", bool createNoWindow = false) { var info = new ProcessStartInfo { diff --git a/Flow.Launcher/Helper/DWMDropShadow.cs b/Flow.Launcher/Helper/DWMDropShadow.cs index 7cb719d07..58817d70e 100644 --- a/Flow.Launcher/Helper/DWMDropShadow.cs +++ b/Flow.Launcher/Helper/DWMDropShadow.cs @@ -2,6 +2,7 @@ using System.Windows; using System.Windows.Interop; using Windows.Win32; +using Windows.Win32.Foundation; using Windows.Win32.Graphics.Dwm; using Windows.Win32.UI.Controls; @@ -38,24 +39,22 @@ public class DwmDropShadow /// /// Window to which the shadow will be applied /// True if the method succeeded, false if not - private unsafe static bool DropShadow(Window window) + private static unsafe bool DropShadow(Window window) { try { WindowInteropHelper helper = new WindowInteropHelper(window); int val = 2; - int ret1 = PInvoke.DwmSetWindowAttribute(new(helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4); + var ret1 = PInvoke.DwmSetWindowAttribute(new (helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4); - if (ret1 == 0) + if (ret1 == HRESULT.S_OK) { var m = new MARGINS { cyBottomHeight = 0, cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0 }; - int ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m); - return ret2 == 0; - } - else - { - return false; + var ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m); + return ret2 == HRESULT.S_OK; } + + return false; } catch (Exception) { diff --git a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs index 8ab06e78d..8a42d480f 100644 --- a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs +++ b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs @@ -1,5 +1,8 @@ -using System.Linq; +using System; +using System.Linq; +using System.Runtime.InteropServices; using System.Text; +using System.Windows.Documents; using System.Windows.Media; using Microsoft.Win32; using Windows.Win32; @@ -9,19 +12,17 @@ namespace Flow.Launcher.Helper; public static class WallpaperPathRetrieval { - private static readonly int MAX_PATH = 260; public static unsafe string GetWallpaperPath() { - var wallpaper = new StringBuilder(MAX_PATH); - PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH, &wallpaper, 0); - - var str = wallpaper.ToString(); - if (string.IsNullOrEmpty(str)) - return null; - - return str; + var wallpaperPtr = stackalloc char[MAX_PATH]; + PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH, + wallpaperPtr, + 0); + var wallpaper = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(wallpaperPtr); + + return wallpaper.ToString(); } public static Color GetWallpaperColor() @@ -32,13 +33,14 @@ public static class WallpaperPathRetrieval { try { - var parts = strResult.Trim().Split(new[] {' '}, 3).Select(byte.Parse).ToList(); + var parts = strResult.Trim().Split(new[] { ' ' }, 3).Select(byte.Parse).ToList(); return Color.FromRgb(parts[0], parts[1], parts[2]); } catch { } } + return Colors.Transparent; } } diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index 6656b0c5b..caf3f0a7f 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -1,5 +1,7 @@ using System; +using System.ComponentModel; using System.Drawing; +using System.Runtime.InteropServices; using System.Windows; using System.Windows.Forms; using System.Windows.Interop; @@ -56,18 +58,17 @@ public class WindowsInteropHelper } string windowClass; - int capacity = 256; - char[] buffer = new char[capacity]; + const int capacity = 256; + Span buffer = stackalloc char[capacity]; + int validLength; fixed (char* pBuffer = buffer) { - PInvoke.GetClassName(hWnd, pBuffer, capacity); - - // Truncate the buffer to the actual length of the string - int validLength = Array.IndexOf(buffer, '\0'); - if (validLength < 0) validLength = capacity; - windowClass = new string(buffer, 0, validLength); + validLength = PInvoke.GetClassName(hWnd, pBuffer, capacity); } + windowClass = buffer[..validLength].ToString(); + + //for Win+Tab (Flip3D) if (windowClass == WINDOW_CLASS_WINTAB) { @@ -87,14 +88,15 @@ public class WindowsInteropHelper { var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null); hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView"); - if (!hWndDesktop.Equals(IntPtr.Zero)) + if (hWndDesktop.Value != (IntPtr.Zero)) { return false; } } Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds; - return (appBounds.bottom - appBounds.top) == screenBounds.Height && (appBounds.right - appBounds.left) == screenBounds.Width; + return (appBounds.bottom - appBounds.top) == screenBounds.Height && + (appBounds.right - appBounds.left) == screenBounds.Width; } /// @@ -104,7 +106,23 @@ public class WindowsInteropHelper public static void DisableControlBox(Window win) { var hwnd = new HWND(new WindowInteropHelper(win).Handle); - PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE) & ~(int)WINDOW_STYLE.WS_SYSMENU); + + var style = PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE); + + if (style == 0) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } + + style &= ~(int)WINDOW_STYLE.WS_SYSMENU; + + var previousStyle = PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, + style); + + if (previousStyle == 0) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } } /// @@ -127,6 +145,7 @@ public class WindowsInteropHelper using var src = new HwndSource(new HwndSourceParameters()); matrix = src.CompositionTarget.TransformFromDevice; } + return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY)); } } diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs index abc254d86..519e8a792 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs @@ -98,7 +98,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller using var safeHandle = new SafeProcessHandle(handle.Value, true); uint capacity = 2000; - char[] buffer = new char[capacity]; + Span buffer = new char[capacity]; fixed (char* pBuffer = buffer) { if (!PInvoke.QueryFullProcessImageName(safeHandle, PROCESS_NAME_FORMAT.PROCESS_NAME_WIN32, (PWSTR)pBuffer, ref capacity)) @@ -106,10 +106,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller return string.Empty; } - // Truncate the buffer to the actual length of the string - int validLength = Array.IndexOf(buffer, '\0'); - if (validLength < 0) validLength = (int)capacity; - return new string(buffer, 0, validLength); + return buffer[..(int)capacity].ToString(); } } catch diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index ad1f3ab56..f194ae973 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -31,14 +31,14 @@ namespace Flow.Launcher.Plugin.Program.Programs ((IShellLinkW)link).Resolve(hwnd, 0); const int MAX_PATH = 260; - char[] buffer = new char[MAX_PATH]; + Span buffer = stackalloc char[MAX_PATH]; var data = new WIN32_FIND_DATAW(); var target = string.Empty; - fixed (char* bufferChar = buffer) + fixed (char* bufferPtr = buffer) { - ((IShellLinkW)link).GetPath((PWSTR)bufferChar, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); - target = GetStringFromBuffer(buffer, MAX_PATH); + ((IShellLinkW)link).GetPath((PWSTR)bufferPtr, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); + target = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); } // To set the app description @@ -46,11 +46,10 @@ namespace Flow.Launcher.Plugin.Program.Programs { try { - char[] buffer1 = new char[MAX_PATH]; - fixed (char* buffer1Char = buffer1) + fixed (char* bufferPtr = buffer) { - ((IShellLinkW)link).GetDescription((PWSTR)buffer1Char, MAX_PATH); - description = GetStringFromBuffer(buffer1, MAX_PATH); + ((IShellLinkW)link).GetDescription(bufferPtr, MAX_PATH); + description = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); } } catch (COMException e) @@ -61,11 +60,10 @@ namespace Flow.Launcher.Plugin.Program.Programs e); } - char[] buffer2 = new char[MAX_PATH]; - fixed (char* buffer2Char = buffer2) + fixed (char* bufferPtr = buffer) { - ((IShellLinkW)link).GetArguments((PWSTR)buffer2Char, MAX_PATH); - arguments = GetStringFromBuffer(buffer2, MAX_PATH); + ((IShellLinkW)link).GetArguments(bufferPtr, MAX_PATH); + arguments = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); } } @@ -74,13 +72,5 @@ namespace Flow.Launcher.Plugin.Program.Programs return target; } - - private static unsafe string GetStringFromBuffer(char[] buffer, int maxLength) - { - // Truncate the buffer to the actual length of the string - int validLength = Array.IndexOf(buffer, '\0'); - if (validLength < 0) validLength = maxLength; - return new string(buffer, 0, validLength); - } } } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs index e36618b0d..fac3ab181 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Runtime.InteropServices; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.LibraryLoader; @@ -20,39 +21,34 @@ namespace Flow.Launcher.Plugin.Program.Programs /// The localized name as string or . public static unsafe string GetLocalizedName(string path) { - int capacity = 1024; - char[] resourcePathBuffer = new char[capacity]; + const int capacity = 1024; + Span buffer = new char[capacity]; // If there is no resource to localize a file name the method returns a non zero value. - fixed (char* resourcePath = resourcePathBuffer) + fixed (char* bufferPtr = buffer) { - var result = PInvoke.SHGetLocalizedName(path, (PWSTR)resourcePath, (uint)capacity, out var id); - if (result == HRESULT.S_OK) + var result = PInvoke.SHGetLocalizedName(path, bufferPtr, capacity, out var id); + if (result != HRESULT.S_OK) { - int validLength = Array.IndexOf(resourcePathBuffer, '\0'); - if (validLength < 0) validLength = capacity; - var resourcePathStr = new string(resourcePathBuffer, 0, validLength); - _ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, resourcePath, (uint)capacity); - var handle = PInvoke.LoadLibraryEx(resourcePathStr, - LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE); - IntPtr safeHandle = handle.DangerousGetHandle(); - if (safeHandle != IntPtr.Zero) - { - char[] localizedNameBuffer = new char[capacity]; - fixed (char* localizedName = localizedNameBuffer) - { - if (PInvoke.LoadString(handle, (uint)id, (PWSTR)localizedName, capacity) != 0) - { - validLength = Array.IndexOf(localizedNameBuffer, '\0'); - if (validLength < 0) validLength = capacity; - var lString = new string(localizedNameBuffer, 0, validLength); - PInvoke.FreeLibrary(new(safeHandle)); - return lString; - } - } + return string.Empty; + } - PInvoke.FreeLibrary(new(safeHandle)); - } + var resourcePathStr = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); + _ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, bufferPtr, capacity); + using var handle = PInvoke.LoadLibraryEx(resourcePathStr, + LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE); + if (handle.IsInvalid) + { + return string.Empty; + } + + // not sure about the behavior of Pinvoke.LoadString, so we clear the buffer before using it (so it must be a null-terminated string) + buffer.Clear(); + + if (PInvoke.LoadString(handle, (uint)id, bufferPtr, capacity) != 0) + { + var lString = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); + return lString; } } From 02a45661c4f836e9c21aff68f9872795cf1ee04c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 26 Dec 2024 13:04:15 +0800 Subject: [PATCH 029/259] Add consistent error handling for GetArguments --- .../Programs/ShellLinkHelper.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index f194ae973..a77b2ace8 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -35,10 +35,18 @@ namespace Flow.Launcher.Plugin.Program.Programs var data = new WIN32_FIND_DATAW(); var target = string.Empty; - fixed (char* bufferPtr = buffer) + try { - ((IShellLinkW)link).GetPath((PWSTR)bufferPtr, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); - target = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); + fixed (char* bufferPtr = buffer) + { + ((IShellLinkW)link).GetPath((PWSTR)bufferPtr, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); + target = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); + } + } + catch (COMException e) + { + ProgramLogger.LogException($"|IShellLinkW|retrieveTargetPath|{path}" + + "|Error occurred while getting program arguments", e); } // To set the app description @@ -66,11 +74,11 @@ namespace Flow.Launcher.Plugin.Program.Programs arguments = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString(); } } - + // To release unmanaged memory Marshal.ReleaseComObject(link); return target; - } + } } } From 9350e82b7793414871dcc59ae95a5b84268aa365 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 27 Dec 2024 12:57:17 -0600 Subject: [PATCH 030/259] only stackalloc the getwindowtitle buffer when length is small. --- Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs index 9ea582118..a0440e30d 100644 --- a/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs +++ b/Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs @@ -54,12 +54,12 @@ namespace Flow.Launcher.Plugin.SharedCommands { var capacity = PInvoke.GetWindowTextLength(hwnd) + 1; int length; - Span buffer = stackalloc char[capacity]; + Span buffer = capacity < 1024 ? stackalloc char[capacity] : new char[capacity]; fixed (char* pBuffer = buffer) { // If the window has no title bar or text, if the title bar is empty, // or if the window or control handle is invalid, the return value is zero. - length = PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity); + length = PInvoke.GetWindowText(hwnd, pBuffer, capacity); } return buffer[..length].ToString(); From 4b9c23d49bcf823641258ab003225edd9face248 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 22:46:08 +0000 Subject: [PATCH 031/259] Bump nunit from 3.14.0 to 4.3.2 Bumps [nunit](https://github.com/nunit/nunit) from 3.14.0 to 4.3.2. - [Release notes](https://github.com/nunit/nunit/releases) - [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md) - [Commits](https://github.com/nunit/nunit/compare/v3.14.0...4.3.2) --- updated-dependencies: - dependency-name: nunit dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Flow.Launcher.Test/Flow.Launcher.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Test/Flow.Launcher.Test.csproj b/Flow.Launcher.Test/Flow.Launcher.Test.csproj index 8286e142e..0241a374e 100644 --- a/Flow.Launcher.Test/Flow.Launcher.Test.csproj +++ b/Flow.Launcher.Test/Flow.Launcher.Test.csproj @@ -49,7 +49,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 921d6a3beb6a3c05ca00e6ce70a41fbf9e98b21b Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 2 Jan 2025 18:47:25 +0800 Subject: [PATCH 032/259] Add support for system language item --- .../Resource/Internationalization.cs | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index 1505e84f8..aac6ecc1e 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -18,6 +18,8 @@ namespace Flow.Launcher.Core.Resource { public Settings Settings { get; set; } private const string Folder = "Languages"; + private const string SystemLanguageCode = "System"; + private const string DefaultLanguageCode = "en"; private const string DefaultFile = "en.xaml"; private const string Extension = ".xaml"; private readonly List _languageDirectories = new List(); @@ -68,8 +70,18 @@ namespace Flow.Launcher.Core.Resource public void ChangeLanguage(string languageCode) { languageCode = languageCode.NonNull(); - Language language = GetLanguageByLanguageCode(languageCode); - ChangeLanguage(language); + + // Get actual language if language code is system + var isSystem = false; + if (languageCode == SystemLanguageCode) + { + languageCode = GetSystemLanguageCode(); + isSystem = true; + } + + // Get language by language code and change language + var language = GetLanguageByLanguageCode(languageCode); + ChangeLanguage(language, isSystem); } private Language GetLanguageByLanguageCode(string languageCode) @@ -87,11 +99,10 @@ namespace Flow.Launcher.Core.Resource } } - public void ChangeLanguage(Language language) + private void ChangeLanguage(Language language, bool isSystem) { language = language.NonNull(); - RemoveOldLanguageFiles(); if (language != AvailableLanguages.English) { @@ -103,7 +114,7 @@ namespace Flow.Launcher.Core.Resource CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture; // Raise event after culture is set - Settings.Language = language.LanguageCode; + Settings.Language = isSystem ? SystemLanguageCode : language.LanguageCode; _ = Task.Run(() => { UpdatePluginMetadataTranslations(); @@ -167,7 +178,35 @@ namespace Flow.Launcher.Core.Resource public List LoadAvailableLanguages() { - return AvailableLanguages.GetAvailableLanguages(); + var list = AvailableLanguages.GetAvailableLanguages(); + list.Insert(0, new Language(SystemLanguageCode, "System")); + return list; + } + + private string GetSystemLanguageCode() + { + var availableLanguages = AvailableLanguages.GetAvailableLanguages(); + + // Retrieve the language identifiers for the current culture + var currentCulture = CultureInfo.CurrentCulture; + var twoLetterCode = currentCulture.TwoLetterISOLanguageName; + var threeLetterCode = currentCulture.ThreeLetterISOLanguageName; + var fullName = currentCulture.Name; + + // Try to find a match in the available languages list + foreach (var language in availableLanguages) + { + var languageCode = language.LanguageCode; + + if (string.Equals(languageCode, twoLetterCode, StringComparison.OrdinalIgnoreCase) || + string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) || + string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase)) + { + return languageCode; + } + } + + return DefaultLanguageCode; } public string GetTranslation(string key) From 0ae3cfcdd6f735b6f8e16ffa0e782c394fbd2e68 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 2 Jan 2025 18:50:02 +0800 Subject: [PATCH 033/259] Add display translation for system language item --- .../Resource/AvailableLanguages.cs | 34 ++++++++++++++++++- .../Resource/Internationalization.cs | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Resource/AvailableLanguages.cs b/Flow.Launcher.Core/Resource/AvailableLanguages.cs index c385cd8e8..ecaecf646 100644 --- a/Flow.Launcher.Core/Resource/AvailableLanguages.cs +++ b/Flow.Launcher.Core/Resource/AvailableLanguages.cs @@ -30,7 +30,6 @@ namespace Flow.Launcher.Core.Resource public static Language Vietnamese = new Language("vi-vn", "Tiếng Việt"); public static Language Hebrew = new Language("he", "עברית"); - public static List GetAvailableLanguages() { List languages = new List @@ -63,5 +62,38 @@ namespace Flow.Launcher.Core.Resource }; return languages; } + + public static string GetSystemTranslation(string languageCode) + { + return languageCode switch + { + "en" => "System", + "zh-cn" => "系统", + "zh-tw" => "系統", + "uk-UA" => "Система", + "ru" => "Система", + "fr" => "Système", + "ja" => "システム", + "nl" => "Systeem", + "pl" => "System", + "da" => "System", + "de" => "System", + "ko" => "시스템", + "sr" => "Систем", + "pt-pt" => "Sistema", + "pt-br" => "Sistema", + "es" => "Sistema", + "es-419" => "Sistema", + "it" => "Sistema", + "nb-NO" => "System", + "sk" => "Systém", + "tr" => "Sistem", + "cs" => "Systém", + "ar" => "النظام", + "vi-vn" => "Hệ thống", + "he" => "מערכת", + _ => "System", + }; + } } } diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index aac6ecc1e..4db3e8633 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -179,7 +179,7 @@ namespace Flow.Launcher.Core.Resource public List LoadAvailableLanguages() { var list = AvailableLanguages.GetAvailableLanguages(); - list.Insert(0, new Language(SystemLanguageCode, "System")); + list.Insert(0, new Language(SystemLanguageCode, AvailableLanguages.GetSystemTranslation(GetSystemLanguageCode()))); return list; } From e0f0bed8223203e8676e16ecf9d2756a5fc59be1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 4 Jan 2025 00:33:24 +0800 Subject: [PATCH 034/259] Revert "Fix clipboard action under sta thread issue" --- .../NativeMethods.txt | 5 +- .../UserSettings/Settings.cs | 2 +- Flow.Launcher.Infrastructure/Win32Helper.cs | 138 ------------------ Flow.Launcher/PublicAPIInstance.cs | 39 +++-- 4 files changed, 20 insertions(+), 164 deletions(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index d8777ff27..f117534a1 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -16,7 +16,4 @@ WM_KEYUP WM_SYSKEYDOWN WM_SYSKEYUP -EnumWindows - -OleInitialize -OleUninitialize \ No newline at end of file +EnumWindows \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 83f06279c..0bcc9368d 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -230,7 +230,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings [JsonIgnore] public ObservableCollection BuiltinShortcuts { get; set; } = new() { - new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", () => Win32Helper.StartSTATaskAsync(Clipboard.GetText).Result), + new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText), new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath) }; diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 6d6c72864..867fef4f5 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -1,150 +1,12 @@ using System; using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; using System.Windows.Interop; using System.Windows; -using Windows.Win32; namespace Flow.Launcher.Infrastructure { public static class Win32Helper { - #region STA Thread - - /* - Found on https://github.com/files-community/Files - */ - - public static Task StartSTATaskAsync(Action action) - { - var taskCompletionSource = new TaskCompletionSource(); - Thread thread = new(() => - { - PInvoke.OleInitialize(); - - try - { - action(); - taskCompletionSource.SetResult(); - } - catch (System.Exception) - { - taskCompletionSource.SetResult(); - } - finally - { - PInvoke.OleUninitialize(); - } - }) - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - - public static Task StartSTATaskAsync(Func func) - { - var taskCompletionSource = new TaskCompletionSource(); - Thread thread = new(async () => - { - PInvoke.OleInitialize(); - - try - { - await func(); - taskCompletionSource.SetResult(); - } - catch (System.Exception) - { - taskCompletionSource.SetResult(); - } - finally - { - PInvoke.OleUninitialize(); - } - }) - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - - public static Task StartSTATaskAsync(Func func) - { - var taskCompletionSource = new TaskCompletionSource(); - - Thread thread = new(() => - { - PInvoke.OleInitialize(); - - try - { - taskCompletionSource.SetResult(func()); - } - catch (System.Exception) - { - taskCompletionSource.SetResult(default); - } - finally - { - PInvoke.OleUninitialize(); - } - }) - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - - public static Task StartSTATaskAsync(Func> func) - { - var taskCompletionSource = new TaskCompletionSource(); - - Thread thread = new(async () => - { - PInvoke.OleInitialize(); - try - { - taskCompletionSource.SetResult(await func()); - } - catch (System.Exception) - { - taskCompletionSource.SetResult(default); - } - finally - { - PInvoke.OleUninitialize(); - } - }) - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - - #endregion - #region Blur Handling /* diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index dcdb798ff..f0295cf24 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -117,38 +117,35 @@ namespace Flow.Launcher ShellCommand.Execute(startInfo); } - public async void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true) + public void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true) { if (string.IsNullOrEmpty(stringToCopy)) return; - await Win32Helper.StartSTATaskAsync(() => + var isFile = File.Exists(stringToCopy); + if (directCopy && (isFile || Directory.Exists(stringToCopy))) { - var isFile = File.Exists(stringToCopy); - if (directCopy && (isFile || Directory.Exists(stringToCopy))) - { - var paths = new StringCollection + var paths = new StringCollection { stringToCopy }; - Clipboard.SetFileDropList(paths); + Clipboard.SetFileDropList(paths); - if (showDefaultNotification) - ShowMsg( - $"{GetTranslation("copy")} {(isFile ? GetTranslation("fileTitle") : GetTranslation("folderTitle"))}", - GetTranslation("completedSuccessfully")); - } - else - { - Clipboard.SetDataObject(stringToCopy); + if (showDefaultNotification) + ShowMsg( + $"{GetTranslation("copy")} {(isFile ? GetTranslation("fileTitle") : GetTranslation("folderTitle"))}", + GetTranslation("completedSuccessfully")); + } + else + { + Clipboard.SetDataObject(stringToCopy); - if (showDefaultNotification) - ShowMsg( - $"{GetTranslation("copy")} {GetTranslation("textTitle")}", - GetTranslation("completedSuccessfully")); - } - }); + if (showDefaultNotification) + ShowMsg( + $"{GetTranslation("copy")} {GetTranslation("textTitle")}", + GetTranslation("completedSuccessfully")); + } } public void StartLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Visible; From 5d623123fc72554a87a8fbf8d0e33f52a3638d3c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 4 Jan 2025 14:02:50 +0800 Subject: [PATCH 035/259] Fix operator equal application issue --- Flow.Launcher.Infrastructure/FileExplorerHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs index b738b9c88..65f424e33 100644 --- a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs +++ b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs @@ -68,7 +68,7 @@ namespace Flow.Launcher.Infrastructure var numRemaining = hWnds.Count; PInvoke.EnumWindows((wnd, _) => { - var searchIndex = hWnds.FindIndex(x => x.HWND == wnd.Value); + var searchIndex = hWnds.FindIndex(x => x.HWND == wnd.Value.ToInt64()); if (searchIndex != -1) { z[searchIndex] = index; From 37058f765185341a08007d4c713d944e25303b79 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 4 Jan 2025 21:55:44 +0800 Subject: [PATCH 036/259] Improve code quality. --- .../Flow.Launcher.Plugin.PluginsManager/Main.cs | 2 +- .../PluginsManager.cs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index bec84f484..156135f81 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -51,7 +51,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return query.FirstSearch.ToLower() switch { //search could be url, no need ToLower() when passed in - Settings.InstallCommand => await pluginManager.RequestInstallOrUpdate(query.SecondToEndSearch, token, query.IsReQuery), + Settings.InstallCommand => await pluginManager.RequestInstallOrUpdateAsync(query.SecondToEndSearch, token, query.IsReQuery), Settings.UninstallCommand => pluginManager.RequestUninstall(query.SecondToEndSearch), Settings.UpdateCommand => await pluginManager.RequestUpdateAsync(query.SecondToEndSearch, token, query.IsReQuery), _ => pluginManager.GetDefaultHotKeys().Where(hotkey => diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 305d248d3..b1b1a7502 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -324,7 +324,7 @@ namespace Flow.Launcher.Plugin.PluginsManager string.Format( Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"), x.Name)); - }, TaskContinuationOptions.OnlyOnFaulted); + }, token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); return true; }, @@ -337,7 +337,7 @@ namespace Flow.Launcher.Plugin.PluginsManager }); // Update all result - if (resultsForUpdate.Count() > 1) + if (resultsForUpdate.Count > 1) { var updateAllResult = new Result { @@ -351,13 +351,13 @@ namespace Flow.Launcher.Plugin.PluginsManager { message = string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_prompt"), - resultsForUpdate.Count(), Environment.NewLine); + resultsForUpdate.Count, Environment.NewLine); } else { message = string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_prompt_no_restart"), - resultsForUpdate.Count()); + resultsForUpdate.Count); } if (Context.API.ShowMsgBox(message, @@ -401,7 +401,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_title"), string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_success_restart"), - resultsForUpdate.Count())); + resultsForUpdate.Count)); Context.API.RestartApp(); } else @@ -409,7 +409,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_title"), string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_success_no_restart"), - resultsForUpdate.Count())); + resultsForUpdate.Count)); } return true; @@ -545,7 +545,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.GetAllPlugins().Any(x => x.Metadata.Website.StartsWith(constructedUrlPart)); } - internal async ValueTask> RequestInstallOrUpdate(string search, CancellationToken token, + internal async ValueTask> RequestInstallOrUpdateAsync(string search, CancellationToken token, bool usePrimaryUrlOnly = false) { await PluginsManifest.UpdateManifestAsync(token, usePrimaryUrlOnly); From 562b233c157f2d11bc00f744f2772223037c4eb4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 4 Jan 2025 23:11:13 +0800 Subject: [PATCH 037/259] Add progress box support for downloading plugin --- Flow.Launcher.Core/ProgressBoxEx.xaml | 106 ++++++++++++++++++ Flow.Launcher.Core/ProgressBoxEx.xaml.cs | 76 +++++++++++++ .../PluginsManager.cs | 59 +++++++++- 3 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 Flow.Launcher.Core/ProgressBoxEx.xaml create mode 100644 Flow.Launcher.Core/ProgressBoxEx.xaml.cs diff --git a/Flow.Launcher.Core/ProgressBoxEx.xaml b/Flow.Launcher.Core/ProgressBoxEx.xaml new file mode 100644 index 000000000..4cce82221 --- /dev/null +++ b/Flow.Launcher.Core/ProgressBoxEx.xaml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /// URL to download file /// path to save downloaded file + /// + /// Action to report progress. The input of the action is the progress value which is a double value between 0 and 100. + /// It will be called if url support range request and the reportProgress is not null. + /// /// place to store file /// Task showing the progress - Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default); + Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action reportProgress = null, CancellationToken token = default); /// /// Add ActionKeyword for specific plugin diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 95d371fb0..7706a64ba 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -164,8 +164,8 @@ namespace Flow.Launcher public Task HttpGetStreamAsync(string url, CancellationToken token = default) => Http.GetStreamAsync(url); - public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, - CancellationToken token = default) => Http.DownloadAsync(url, filePath, token); + public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action reportProgress = null, + CancellationToken token = default) => Http.DownloadAsync(url, filePath, reportProgress, token); public void AddActionKeyword(string pluginId, string newActionKeyword) => PluginManager.AddActionKeyword(pluginId, newActionKeyword); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index b6495d8f2..aee76e65e 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -17,8 +17,6 @@ namespace Flow.Launcher.Plugin.PluginsManager { internal class PluginsManager { - private static readonly HttpClient HttpClient = new(); - private const string zip = "zip"; private PluginInitContext Context { get; set; } @@ -144,75 +142,37 @@ namespace Flow.Launcher.Plugin.PluginsManager var filePath = Path.Combine(Path.GetTempPath(), downloadFilename); - var downloadCancelled = false; var exceptionHappened = false; try { + using var cts = new CancellationTokenSource(); + if (!plugin.IsFromLocalInstallPath) { if (File.Exists(filePath)) File.Delete(filePath); - using var cts = new CancellationTokenSource(); - using var response = await HttpClient.GetAsync(plugin.UrlDownload, HttpCompletionOption.ResponseHeadersRead, cts.Token).ConfigureAwait(false); - - response.EnsureSuccessStatusCode(); - - var totalBytes = response.Content.Headers.ContentLength ?? -1L; - var canReportProgress = totalBytes != -1; - var prgBoxTitle = $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.Name}"; - if (canReportProgress) - { - await Context.API.ShowProgressBoxAsync(prgBoxTitle, - async (reportProgress) => + await Context.API.ShowProgressBoxAsync(prgBoxTitle, + async (reportProgress) => + { + if (reportProgress == null) { - if (reportProgress == null) - { - // when reportProgress is null, it means there is expcetion with the progress box - // so we record it with exceptionHappened and return so that progress box will close instantly - exceptionHappened = true; - return; - } - else - { - await using var contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true); - - var buffer = new byte[8192]; - long totalRead = 0; - int read; - - while ((read = await contentStream.ReadAsync(buffer).ConfigureAwait(false)) > 0) - { - await fileStream.WriteAsync(buffer.AsMemory(0, read)).ConfigureAwait(false); - totalRead += read; - - var progressValue = totalRead * 100 / totalBytes; - - // check if user cancelled download before reporting progress - if (downloadCancelled) - return; - else - reportProgress(progressValue); - } - } - }, - () => + // when reportProgress is null, it means there is expcetion with the progress box + // so we record it with exceptionHappened and return so that progress box will close instantly + exceptionHappened = true; + return; + } + else { - cts.Cancel(); - downloadCancelled = true; - }); + await Http.DownloadAsync(plugin.UrlDownload, filePath, reportProgress, cts.Token).ConfigureAwait(false); + } + }, cts.Cancel); - // if exception happened while downloading and user does not cancel downloading, - // we need to redownload the plugin - if (exceptionHappened && (!downloadCancelled)) - await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false); - } - else - { - await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false); - } + // if exception happened while downloading and user does not cancel downloading, + // we need to redownload the plugin + if (exceptionHappened && (!cts.IsCancellationRequested)) + await Http.DownloadAsync(plugin.UrlDownload, filePath, null, cts.Token).ConfigureAwait(false); } else { @@ -220,7 +180,7 @@ namespace Flow.Launcher.Plugin.PluginsManager } // check if user cancelled download before installing plugin - if (downloadCancelled) + if (cts.IsCancellationRequested) return; else Install(plugin, filePath); From 32cac76c827681b436bd8bdc8de03e608181260c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 12 Jan 2025 18:44:52 +0800 Subject: [PATCH 078/259] Improve Settings management --- .../UserSettings/Settings.cs | 16 ++++++++++++++-- Flow.Launcher/App.xaml.cs | 8 ++++++-- .../ViewModel/SettingWindowViewModel.cs | 13 +++---------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 0bcc9368d..3e43e3d32 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Drawing; using System.Text.Json.Serialization; using System.Windows; using Flow.Launcher.Infrastructure.Hotkey; +using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedModels; using Flow.Launcher.ViewModel; @@ -13,6 +13,18 @@ namespace Flow.Launcher.Infrastructure.UserSettings { public class Settings : BaseModel, IHotkeySettings { + private FlowLauncherJsonStorage _storage; + + public void Initialize(FlowLauncherJsonStorage storage) + { + _storage = storage; + } + + public void Save() + { + _storage.Save(); + } + private string language = "en"; private string _theme = Constant.DefaultTheme; public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}"; diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 58da35e85..9d7a0671e 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -14,6 +14,7 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Image; using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; @@ -52,6 +53,10 @@ namespace Flow.Launcher { await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { + var storage = new FlowLauncherJsonStorage(); + _settings = storage.Load(); + _settings.Initialize(storage); + _portable.PreStartCleanUpAfterPortabilityUpdate(); Log.Info( @@ -62,8 +67,7 @@ namespace Flow.Launcher var imageLoadertask = ImageLoader.InitializeAsync(); - _settingsVM = new SettingWindowViewModel(_updater, _portable); - _settings = _settingsVM.Settings; + _settingsVM = new SettingWindowViewModel(_settings, _updater, _portable); _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings); diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 04dd6312b..95a1eb675 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -1,6 +1,5 @@ using Flow.Launcher.Core; using Flow.Launcher.Core.Configuration; -using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -8,21 +7,17 @@ namespace Flow.Launcher.ViewModel; public class SettingWindowViewModel : BaseModel { - private readonly FlowLauncherJsonStorage _storage; - public Updater Updater { get; } public IPortable Portable { get; } public Settings Settings { get; } - public SettingWindowViewModel(Updater updater, IPortable portable) + public SettingWindowViewModel(Settings settings, Updater updater, IPortable portable) { - _storage = new FlowLauncherJsonStorage(); - + Settings = settings; Updater = updater; Portable = portable; - Settings = _storage.Load(); } public async void UpdateApp() @@ -30,14 +25,12 @@ public class SettingWindowViewModel : BaseModel await Updater.UpdateAppAsync(App.API, false); } - - /// /// Save Flow settings. Plugins settings are not included. /// public void Save() { - _storage.Save(); + Settings.Save(); } public double SettingWindowWidth From 1b76a2bc1a1c3356b3bab5c3be61b3427b1de7fd Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 12 Jan 2025 19:45:36 +0800 Subject: [PATCH 079/259] Use dependency injection for all services --- .../Flow.Launcher.Infrastructure.csproj | 1 + .../PinyinAlphabet.cs | 8 ++- Flow.Launcher.Infrastructure/StringMatcher.cs | 5 +- Flow.Launcher/App.xaml.cs | 61 +++++++++++-------- Flow.Launcher/Flow.Launcher.csproj | 5 +- Flow.Launcher/PublicAPIInstance.cs | 12 ++-- Flow.Launcher/ViewModel/MainViewModel.cs | 5 +- .../ViewModel/SettingWindowViewModel.cs | 11 ++-- 8 files changed, 65 insertions(+), 43 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 1475252ca..84b603161 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -54,6 +54,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 7d7235968..8eaa757be 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -6,6 +6,7 @@ using System.Text; using JetBrains.Annotations; using Flow.Launcher.Infrastructure.UserSettings; using ToolGood.Words.Pinyin; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.Infrastructure { @@ -129,7 +130,12 @@ namespace Flow.Launcher.Infrastructure private Settings _settings; - public void Initialize([NotNull] Settings settings) + public PinyinAlphabet() + { + Initialize(Ioc.Default.GetRequiredService()); + } + + private void Initialize([NotNull] Settings settings) { _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index bd5dbdda9..7134fc760 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -1,4 +1,5 @@ -using Flow.Launcher.Plugin.SharedModels; +using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Plugin.SharedModels; using System; using System.Collections.Generic; using System.Linq; @@ -15,7 +16,7 @@ namespace Flow.Launcher.Infrastructure public StringMatcher(IAlphabet alphabet = null) { - _alphabet = alphabet; + _alphabet = Ioc.Default.GetRequiredService(); } public static StringMatcher Instance { get; internal set; } diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 9d7a0671e..8cd054148 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core; using Flow.Launcher.Core.Configuration; using Flow.Launcher.Core.ExternalPlugins.Environments; @@ -18,23 +19,18 @@ using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch; namespace Flow.Launcher { - public partial class App : IDisposable, ISingleInstanceApp, IApp + public partial class App : IDisposable, ISingleInstanceApp { - public IPublicAPI PublicAPI => API; public static PublicAPIInstance API { get; private set; } private const string Unique = "Flow.Launcher_Unique_Application_Mutex"; private static bool _disposed; private Settings _settings; - private MainViewModel _mainVM; - private SettingWindowViewModel _settingsVM; - private readonly Updater _updater = new Updater(Flow.Launcher.Properties.Settings.Default.GithubRepo); - private readonly Portable _portable = new Portable(); - private readonly PinyinAlphabet _alphabet = new PinyinAlphabet(); - private StringMatcher _stringMatcher; [STAThread] public static void Main() @@ -53,37 +49,51 @@ namespace Flow.Launcher { await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { + // Initialize settings var storage = new FlowLauncherJsonStorage(); _settings = storage.Load(); _settings.Initialize(storage); + _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); - _portable.PreStartCleanUpAfterPortabilityUpdate(); + // Configure the dependency injection container + var host = Host.CreateDefaultBuilder() + .UseContentRoot(AppContext.BaseDirectory) + .ConfigureServices(services => services + .AddSingleton(_ => _settings) + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + ).Build(); + Ioc.Default.ConfigureServices(host.Services); - Log.Info( - "|App.OnStartup|Begin Flow Launcher startup ----------------------------------------------------"); + Ioc.Default.GetRequiredService().Initialize(Launcher.Properties.Settings.Default.GithubRepo); + + Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate(); + + Log.Info("|App.OnStartup|Begin Flow Launcher startup ----------------------------------------------------"); Log.Info($"|App.OnStartup|Runtime info:{ErrorReporting.RuntimeInfo()}"); + RegisterAppDomainExceptions(); RegisterDispatcherUnhandledException(); var imageLoadertask = ImageLoader.InitializeAsync(); - _settingsVM = new SettingWindowViewModel(_settings, _updater, _portable); - _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); - AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings); - _alphabet.Initialize(_settings); - _stringMatcher = new StringMatcher(_alphabet); - StringMatcher.Instance = _stringMatcher; - _stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision; + var stringMatcher = Ioc.Default.GetRequiredService(); + StringMatcher.Instance = stringMatcher; + stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision; InternationalizationManager.Instance.Settings = _settings; InternationalizationManager.Instance.ChangeLanguage(_settings.Language); PluginManager.LoadPlugins(_settings.PluginSettings); - _mainVM = new MainViewModel(_settings); - API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet); + API = Ioc.Default.GetRequiredService() as PublicAPIInstance; Http.API = API; Http.Proxy = _settings.Proxy; @@ -91,14 +101,15 @@ namespace Flow.Launcher await PluginManager.InitializePluginsAsync(API); await imageLoadertask; - var window = new MainWindow(_settings, _mainVM); + var mainVM = Ioc.Default.GetRequiredService(); + var window = new MainWindow(_settings, mainVM); Log.Info($"|App.OnStartup|Dependencies Info:{ErrorReporting.DependenciesInfo()}"); Current.MainWindow = window; Current.MainWindow.Title = Constant.FlowLauncher; - HotKeyMapper.Initialize(_mainVM); + HotKeyMapper.Initialize(mainVM); // main windows needs initialized before theme change because of blur settings ThemeManager.Instance.Settings = _settings; @@ -147,11 +158,11 @@ namespace Flow.Launcher { // check update every 5 hours var timer = new PeriodicTimer(TimeSpan.FromHours(5)); - await _updater.UpdateAppAsync(API); + await Ioc.Default.GetRequiredService().UpdateAppAsync(API); while (await timer.WaitForNextTickAsync()) // check updates on startup - await _updater.UpdateAppAsync(API); + await Ioc.Default.GetRequiredService().UpdateAppAsync(API); } }); } @@ -194,7 +205,7 @@ namespace Flow.Launcher public void OnSecondAppStarted() { - _mainVM.Show(); + Ioc.Default.GetRequiredService().Show(); } } } diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 4ec249c2b..cab3915d5 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -83,12 +83,13 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive + + all diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index f0295cf24..50765294c 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -25,7 +25,7 @@ using Flow.Launcher.Infrastructure.Storage; using System.Collections.Concurrent; using System.Diagnostics; using System.Collections.Specialized; -using Flow.Launcher.Core; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher { @@ -33,15 +33,15 @@ namespace Flow.Launcher { private readonly SettingWindowViewModel _settingsVM; private readonly MainViewModel _mainVM; - private readonly PinyinAlphabet _alphabet; + private readonly IAlphabet _alphabet; #region Constructor - public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, PinyinAlphabet alphabet) + public PublicAPIInstance() { - _settingsVM = settingsVM; - _mainVM = mainVM; - _alphabet = alphabet; + _settingsVM = Ioc.Default.GetRequiredService(); + _mainVM = Ioc.Default.GetRequiredService(); + _alphabet = Ioc.Default.GetRequiredService(); GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback; WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 55bc8d1b3..f5141a8fa 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -25,6 +25,7 @@ using System.Windows.Input; using System.ComponentModel; using Flow.Launcher.Infrastructure.Image; using System.Windows.Media; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.ViewModel { @@ -58,13 +59,13 @@ namespace Flow.Launcher.ViewModel #region Constructor - public MainViewModel(Settings settings) + public MainViewModel() { _queryTextBeforeLeaveResults = ""; _queryText = ""; _lastQuery = new Query(); - Settings = settings; + Settings = Ioc.Default.GetRequiredService(); Settings.PropertyChanged += (_, args) => { switch (args.PropertyName) diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 95a1eb675..7549db1a3 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -1,4 +1,5 @@ -using Flow.Launcher.Core; +using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Core; using Flow.Launcher.Core.Configuration; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -13,11 +14,11 @@ public class SettingWindowViewModel : BaseModel public Settings Settings { get; } - public SettingWindowViewModel(Settings settings, Updater updater, IPortable portable) + public SettingWindowViewModel() { - Settings = settings; - Updater = updater; - Portable = portable; + Settings = Ioc.Default.GetRequiredService(); + Updater = Ioc.Default.GetRequiredService(); + Portable = Ioc.Default.GetRequiredService(); } public async void UpdateApp() From a748141b1e8d7342336068ef65cc0890eac63992 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 12 Jan 2025 19:47:49 +0800 Subject: [PATCH 080/259] Use IPublicAPI instead --- Flow.Launcher/App.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 8cd054148..9b86c6cc4 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -27,7 +27,7 @@ namespace Flow.Launcher { public partial class App : IDisposable, ISingleInstanceApp { - public static PublicAPIInstance API { get; private set; } + public static IPublicAPI API { get; private set; } private const string Unique = "Flow.Launcher_Unique_Application_Mutex"; private static bool _disposed; private Settings _settings; @@ -93,7 +93,7 @@ namespace Flow.Launcher PluginManager.LoadPlugins(_settings.PluginSettings); - API = Ioc.Default.GetRequiredService() as PublicAPIInstance; + API = Ioc.Default.GetRequiredService(); Http.API = API; Http.Proxy = _settings.Proxy; From 3cb9d1dce4b606cc80fb3a7fc9e51da08237c1b8 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 12 Jan 2025 20:04:44 +0800 Subject: [PATCH 081/259] Remove IApp & AppExtensions and use dependency injection instead --- Flow.Launcher.Core/AppExtensions.cs | 15 ------------ Flow.Launcher.Core/Configuration/Portable.cs | 24 +++++++++++-------- .../Environments/AbstractPluginEnvironment.cs | 11 +++++---- .../Environments/PythonEnvironment.cs | 2 +- .../Environments/TypeScriptEnvironment.cs | 2 +- .../Environments/TypeScriptV2Environment.cs | 2 +- Flow.Launcher.Core/IApp.cs | 13 ---------- Flow.Launcher.Core/Plugin/PluginManager.cs | 2 +- Flow.Launcher.Core/Plugin/PluginsLoader.cs | 3 ++- .../Resource/Internationalization.cs | 3 ++- Flow.Launcher.Core/Resource/Theme.cs | 7 ++++-- Flow.Launcher.Core/Updater.cs | 17 +++++++------ Flow.Launcher/App.xaml.cs | 2 ++ .../ViewModel/SettingWindowViewModel.cs | 10 ++++++-- 14 files changed, 54 insertions(+), 59 deletions(-) delete mode 100644 Flow.Launcher.Core/AppExtensions.cs delete mode 100644 Flow.Launcher.Core/IApp.cs diff --git a/Flow.Launcher.Core/AppExtensions.cs b/Flow.Launcher.Core/AppExtensions.cs deleted file mode 100644 index b02612d72..000000000 --- a/Flow.Launcher.Core/AppExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Windows; -using Flow.Launcher.Plugin; - -namespace Flow.Launcher.Core; - -/// -/// Extension properties and functions of the current application singleton object. -/// -public static class AppExtensions -{ - /// - /// Gets the public API of the current application singleton object. - /// - public static IPublicAPI API => (Application.Current as IApp)!.PublicAPI; -} diff --git a/Flow.Launcher.Core/Configuration/Portable.cs b/Flow.Launcher.Core/Configuration/Portable.cs index cb375c586..069154364 100644 --- a/Flow.Launcher.Core/Configuration/Portable.cs +++ b/Flow.Launcher.Core/Configuration/Portable.cs @@ -9,11 +9,15 @@ using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.SharedCommands; using System.Linq; +using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Plugin; namespace Flow.Launcher.Core.Configuration { public class Portable : IPortable { + private readonly IPublicAPI API = Ioc.Default.GetRequiredService(); + /// /// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish /// @@ -40,7 +44,7 @@ namespace Flow.Launcher.Core.Configuration #endif IndicateDeletion(DataLocation.PortableDataPath); - AppExtensions.API.ShowMsgBox("Flow Launcher needs to restart to finish disabling portable mode, " + + API.ShowMsgBox("Flow Launcher needs to restart to finish disabling portable mode, " + "after the restart your portable data profile will be deleted and roaming data profile kept"); UpdateManager.RestartApp(Constant.ApplicationFileName); @@ -64,7 +68,7 @@ namespace Flow.Launcher.Core.Configuration #endif IndicateDeletion(DataLocation.RoamingDataPath); - AppExtensions.API.ShowMsgBox("Flow Launcher needs to restart to finish enabling portable mode, " + + API.ShowMsgBox("Flow Launcher needs to restart to finish enabling portable mode, " + "after the restart your roaming data profile will be deleted and portable data profile kept"); UpdateManager.RestartApp(Constant.ApplicationFileName); @@ -95,13 +99,13 @@ namespace Flow.Launcher.Core.Configuration public void MoveUserDataFolder(string fromLocation, string toLocation) { - FilesFolders.CopyAll(fromLocation, toLocation, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.CopyAll(fromLocation, toLocation, (s) => API.ShowMsgBox(s)); VerifyUserDataAfterMove(fromLocation, toLocation); } public void VerifyUserDataAfterMove(string fromLocation, string toLocation) { - FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => API.ShowMsgBox(s)); } public void CreateShortcuts() @@ -157,13 +161,13 @@ namespace Flow.Launcher.Core.Configuration // delete it and prompt the user to pick the portable data location if (File.Exists(roamingDataDeleteFilePath)) { - FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => API.ShowMsgBox(s)); - if (AppExtensions.API.ShowMsgBox("Flow Launcher has detected you enabled portable mode, " + + if (API.ShowMsgBox("Flow Launcher has detected you enabled portable mode, " + "would you like to move it to a different location?", string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes) { - FilesFolders.OpenPath(Constant.RootDirectory, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.OpenPath(Constant.RootDirectory, (s) => API.ShowMsgBox(s)); Environment.Exit(0); } @@ -172,9 +176,9 @@ namespace Flow.Launcher.Core.Configuration // delete it and notify the user about it. else if (File.Exists(portableDataDeleteFilePath)) { - FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => API.ShowMsgBox(s)); - AppExtensions.API.ShowMsgBox("Flow Launcher has detected you disabled portable mode, " + + API.ShowMsgBox("Flow Launcher has detected you disabled portable mode, " + "the relevant shortcuts and uninstaller entry have been created"); } } @@ -186,7 +190,7 @@ namespace Flow.Launcher.Core.Configuration if (roamingLocationExists && portableLocationExists) { - AppExtensions.API.ShowMsgBox(string.Format("Flow Launcher detected your user data exists both in {0} and " + + API.ShowMsgBox(string.Format("Flow Launcher detected your user data exists both in {0} and " + "{1}. {2}{2}Please delete {1} in order to proceed. No changes have occurred.", DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine)); diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs index cada05031..451df6147 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs @@ -8,11 +8,14 @@ using System.Linq; using System.Windows; using System.Windows.Forms; using Flow.Launcher.Core.Resource; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.Core.ExternalPlugins.Environments { public abstract class AbstractPluginEnvironment { + protected readonly IPublicAPI API = Ioc.Default.GetRequiredService(); + internal abstract string Language { get; } internal abstract string EnvName { get; } @@ -25,7 +28,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal virtual string FileDialogFilter => string.Empty; - internal abstract string PluginsSettingsFilePath { get; set; } + internal abstract string PluginsSettingsFilePath { get; set; } internal List PluginMetadataList; @@ -57,7 +60,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments EnvName, Environment.NewLine ); - if (AppExtensions.API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No) + if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No) { var msg = string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName); string selectedFile; @@ -82,7 +85,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments } else { - AppExtensions.API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language)); + API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language)); Log.Error("PluginsLoader", $"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.", $"{Language}Environment"); @@ -98,7 +101,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments if (expectedPath == currentPath) return; - FilesFolders.RemoveFolderIfExists(installedDirPath, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.RemoveFolderIfExists(installedDirPath, (s) => API.ShowMsgBox(s)); InstallEnvironment(); diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs index 56bc20b4f..607c19062 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs @@ -28,7 +28,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal override void InstallEnvironment() { - FilesFolders.RemoveFolderIfExists(InstallPath, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s)); // Python 3.11.4 is no longer Windows 7 compatible. If user is on Win 7 and // uses Python plugin they need to custom install and use v3.8.9 diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs index 1d43b815a..399f7cc03 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs @@ -25,7 +25,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal override void InstallEnvironment() { - FilesFolders.RemoveFolderIfExists(InstallPath, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s)); DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath).Wait(); diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs index 49bf4e958..e8cb72e11 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs @@ -25,7 +25,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal override void InstallEnvironment() { - FilesFolders.RemoveFolderIfExists(InstallPath, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s)); DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath).Wait(); diff --git a/Flow.Launcher.Core/IApp.cs b/Flow.Launcher.Core/IApp.cs deleted file mode 100644 index 233fd5ed1..000000000 --- a/Flow.Launcher.Core/IApp.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Flow.Launcher.Plugin; - -namespace Flow.Launcher.Core -{ - /// - /// Interface for the current application singleton object exposing the properties - /// and functions that can be accessed from anywhere in the application. - /// - public interface IApp - { - public IPublicAPI PublicAPI { get; } - } -} diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 9e1cf3b9d..a776c10ab 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -519,7 +519,7 @@ namespace Flow.Launcher.Core.Plugin var newPluginPath = Path.Combine(installDirectory, folderName); - FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => AppExtensions.API.ShowMsgBox(s)); + FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => API.ShowMsgBox(s)); Directory.Delete(tempFolderPluginPath, true); diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs index 8cbeb7473..4827cf69d 100644 --- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs +++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.ExternalPlugins.Environments; #pragma warning disable IDE0005 using Flow.Launcher.Infrastructure.Logger; @@ -119,7 +120,7 @@ namespace Flow.Launcher.Core.Plugin _ = Task.Run(() => { - AppExtensions.API.ShowMsgBox($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" + + Ioc.Default.GetRequiredService().ShowMsgBox($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" + $"{errorPluginString}{Environment.NewLine}{Environment.NewLine}" + $"Please refer to the logs for more information", "", MessageBoxButton.OK, MessageBoxImage.Warning); diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index a1cefabe3..de066dda1 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -11,6 +11,7 @@ using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using System.Globalization; using System.Threading.Tasks; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.Core.Resource { @@ -124,7 +125,7 @@ namespace Flow.Launcher.Core.Resource // "Do you want to search with pinyin?" string text = languageToSet == AvailableLanguages.Chinese ? "是否启用拼音搜索?" : "是否啓用拼音搜索?" ; - if (AppExtensions.API.ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No) + if (Ioc.Default.GetRequiredService().ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No) return false; return true; diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 8622d4caf..2749da532 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -11,6 +11,8 @@ using System.Windows.Media.Effects; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Plugin; namespace Flow.Launcher.Core.Resource { @@ -22,6 +24,7 @@ namespace Flow.Launcher.Core.Resource private const int ShadowExtraMargin = 32; + private readonly IPublicAPI API = Ioc.Default.GetRequiredService(); private readonly List _themeDirectories = new List(); private ResourceDictionary _oldResource; private string _oldTheme; @@ -108,7 +111,7 @@ namespace Flow.Launcher.Core.Resource Log.Error($"|Theme.ChangeTheme|Theme <{theme}> path can't be found"); if (theme != defaultTheme) { - AppExtensions.API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_path_not_exists"), theme)); + API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_path_not_exists"), theme)); ChangeTheme(defaultTheme); } return false; @@ -118,7 +121,7 @@ namespace Flow.Launcher.Core.Resource Log.Error($"|Theme.ChangeTheme|Theme <{theme}> fail to parse"); if (theme != defaultTheme) { - AppExtensions.API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_parse_error"), theme)); + API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_parse_error"), theme)); ChangeTheme(defaultTheme); } return false; diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 8745d54b7..373418055 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -17,14 +17,17 @@ using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using System.Text.Json.Serialization; using System.Threading; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.Core { public class Updater { - public string GitHubRepository { get; } + private readonly IPublicAPI API = Ioc.Default.GetRequiredService(); - public Updater(string gitHubRepository) + public string GitHubRepository { get; set; } + + public void Initialize(string gitHubRepository) { GitHubRepository = gitHubRepository; } @@ -53,7 +56,7 @@ namespace Flow.Launcher.Core if (newReleaseVersion <= currentVersion) { if (!silentUpdate) - AppExtensions.API.ShowMsgBox(api.GetTranslation("update_flowlauncher_already_on_latest")); + API.ShowMsgBox(api.GetTranslation("update_flowlauncher_already_on_latest")); return; } @@ -68,9 +71,9 @@ namespace Flow.Launcher.Core if (DataLocation.PortableDataLocationInUse()) { var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}"; - FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination, (s) => AppExtensions.API.ShowMsgBox(s)); - if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination, (s) => AppExtensions.API.ShowMsgBox(s))) - AppExtensions.API.ShowMsgBox(string.Format(api.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"), + FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination, (s) => API.ShowMsgBox(s)); + if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination, (s) => API.ShowMsgBox(s))) + API.ShowMsgBox(string.Format(api.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"), DataLocation.PortableDataPath, targetDestination)); } @@ -83,7 +86,7 @@ namespace Flow.Launcher.Core Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}"); - if (AppExtensions.API.ShowMsgBox(newVersionTips, api.GetTranslation("update_flowlauncher_new_update"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) + if (API.ShowMsgBox(newVersionTips, api.GetTranslation("update_flowlauncher_new_update"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) { UpdateManager.RestartApp(Constant.ApplicationFileName); } diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 9b86c6cc4..0d6d9855c 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -74,6 +74,8 @@ namespace Flow.Launcher Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate(); + Ioc.Default.GetRequiredService().Initialize(); + Log.Info("|App.OnStartup|Begin Flow Launcher startup ----------------------------------------------------"); Log.Info($"|App.OnStartup|Runtime info:{ErrorReporting.RuntimeInfo()}"); diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 7549db1a3..bbd47e731 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -8,15 +8,21 @@ namespace Flow.Launcher.ViewModel; public class SettingWindowViewModel : BaseModel { - public Updater Updater { get; } + public Updater Updater { get; private set; } - public IPortable Portable { get; } + public IPortable Portable { get; private set; } public Settings Settings { get; } public SettingWindowViewModel() { Settings = Ioc.Default.GetRequiredService(); + } + + public void Initialize() + { + // We don not initialize Updater and Portable in the constructor because we want to avoid + // recrusive dependency injection Updater = Ioc.Default.GetRequiredService(); Portable = Ioc.Default.GetRequiredService(); } From 2a423f09bb3fe6c3dfb6dd9f03cce4ce410c5936 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 13 Jan 2025 09:36:14 +0800 Subject: [PATCH 082/259] Improve code quality --- Flow.Launcher.Infrastructure/StringMatcher.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 7134fc760..b3a265e29 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -8,13 +8,13 @@ namespace Flow.Launcher.Infrastructure { public class StringMatcher { - private readonly MatchOption _defaultMatchOption = new MatchOption(); + private readonly MatchOption _defaultMatchOption = new(); public SearchPrecisionScore UserSettingSearchPrecision { get; set; } private readonly IAlphabet _alphabet; - public StringMatcher(IAlphabet alphabet = null) + public StringMatcher() { _alphabet = Ioc.Default.GetRequiredService(); } @@ -242,16 +242,16 @@ namespace Flow.Launcher.Infrastructure return false; } - private bool IsAcronymChar(string stringToCompare, int compareStringIndex) + private static bool IsAcronymChar(string stringToCompare, int compareStringIndex) => char.IsUpper(stringToCompare[compareStringIndex]) || compareStringIndex == 0 || // 0 index means char is the start of the compare string, which is an acronym char.IsWhiteSpace(stringToCompare[compareStringIndex - 1]); - private bool IsAcronymNumber(string stringToCompare, int compareStringIndex) + private static bool IsAcronymNumber(string stringToCompare, int compareStringIndex) => stringToCompare[compareStringIndex] >= 0 && stringToCompare[compareStringIndex] <= 9; // To get the index of the closest space which preceeds the first matching index - private int CalculateClosestSpaceIndex(List spaceIndices, int firstMatchIndex) + private static int CalculateClosestSpaceIndex(List spaceIndices, int firstMatchIndex) { var closestSpaceIndex = -1; From ff110b3c49ec139da1222e3ffcb210596eb4642e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 13 Jan 2025 10:01:50 +0800 Subject: [PATCH 083/259] Fix test project build issue --- Flow.Launcher.Infrastructure/StringMatcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index b3a265e29..5822057a2 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -14,9 +14,9 @@ namespace Flow.Launcher.Infrastructure private readonly IAlphabet _alphabet; - public StringMatcher() + public StringMatcher(IAlphabet alphabet = null) { - _alphabet = Ioc.Default.GetRequiredService(); + _alphabet = alphabet ?? Ioc.Default.GetRequiredService(); } public static StringMatcher Instance { get; internal set; } From c3f71c213e8b24870292f4489515558850c9c5b7 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 13 Jan 2025 10:18:35 +0800 Subject: [PATCH 084/259] Revert "Fix test project build issue" This reverts commit ff110b3c49ec139da1222e3ffcb210596eb4642e. --- Flow.Launcher.Infrastructure/StringMatcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 5822057a2..b3a265e29 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -14,9 +14,9 @@ namespace Flow.Launcher.Infrastructure private readonly IAlphabet _alphabet; - public StringMatcher(IAlphabet alphabet = null) + public StringMatcher() { - _alphabet = alphabet ?? Ioc.Default.GetRequiredService(); + _alphabet = Ioc.Default.GetRequiredService(); } public static StringMatcher Instance { get; internal set; } From 3bebb690935e4b99a508f5a9e98593760f45360c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 13 Jan 2025 10:21:14 +0800 Subject: [PATCH 085/259] Fix unitest build issue --- Flow.Launcher.Infrastructure/StringMatcher.cs | 6 +++++ Flow.Launcher.Test/FuzzyMatcherTest.cs | 22 ++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index b3a265e29..f5f02cbfc 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -19,6 +19,12 @@ namespace Flow.Launcher.Infrastructure _alphabet = Ioc.Default.GetRequiredService(); } + // This is a workaround to allow unit tests to set the instance + public StringMatcher(IAlphabet alphabet) + { + _alphabet = alphabet; + } + public static StringMatcher Instance { get; internal set; } public static MatchResult FuzzySearch(string query, string stringToCompare) diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index d7f143218..d97ce227c 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -21,6 +21,8 @@ namespace Flow.Launcher.Test private const string MicrosoftSqlServerManagementStudio = "Microsoft SQL Server Management Studio"; private const string VisualStudioCode = "Visual Studio Code"; + private readonly IAlphabet alphabet = null; + public List GetSearchStrings() => new List { @@ -59,7 +61,7 @@ namespace Flow.Launcher.Test }; var results = new List(); - var matcher = new StringMatcher(); + var matcher = new StringMatcher(alphabet); foreach (var str in sources) { results.Add(new Result @@ -81,7 +83,7 @@ namespace Flow.Launcher.Test public void WhenNotAllCharactersFoundInSearchString_ThenShouldReturnZeroScore(string searchString) { var compareString = "Can have rum only in my glass"; - var matcher = new StringMatcher(); + var matcher = new StringMatcher(alphabet); var scoreResult = matcher.FuzzyMatch(searchString, compareString).RawScore; Assert.True(scoreResult == 0); @@ -97,7 +99,7 @@ namespace Flow.Launcher.Test string searchTerm) { var results = new List(); - var matcher = new StringMatcher(); + var matcher = new StringMatcher(alphabet); foreach (var str in GetSearchStrings()) { results.Add(new Result @@ -147,7 +149,7 @@ namespace Flow.Launcher.Test string queryString, string compareString, int expectedScore) { // When, Given - var matcher = new StringMatcher {UserSettingSearchPrecision = SearchPrecisionScore.Regular}; + var matcher = new StringMatcher(alphabet) {UserSettingSearchPrecision = SearchPrecisionScore.Regular}; var rawScore = matcher.FuzzyMatch(queryString, compareString).RawScore; // Should @@ -181,7 +183,7 @@ namespace Flow.Launcher.Test bool expectedPrecisionResult) { // When - var matcher = new StringMatcher {UserSettingSearchPrecision = expectedPrecisionScore}; + var matcher = new StringMatcher(alphabet) {UserSettingSearchPrecision = expectedPrecisionScore}; // Given var matchResult = matcher.FuzzyMatch(queryString, compareString); @@ -232,7 +234,7 @@ namespace Flow.Launcher.Test bool expectedPrecisionResult) { // When - var matcher = new StringMatcher {UserSettingSearchPrecision = expectedPrecisionScore}; + var matcher = new StringMatcher(alphabet) {UserSettingSearchPrecision = expectedPrecisionScore}; // Given var matchResult = matcher.FuzzyMatch(queryString, compareString); @@ -260,7 +262,7 @@ namespace Flow.Launcher.Test string queryString, string compareString1, string compareString2) { // When - var matcher = new StringMatcher {UserSettingSearchPrecision = SearchPrecisionScore.Regular}; + var matcher = new StringMatcher(alphabet) {UserSettingSearchPrecision = SearchPrecisionScore.Regular}; // Given var compareString1Result = matcher.FuzzyMatch(queryString, compareString1); @@ -293,7 +295,7 @@ namespace Flow.Launcher.Test string queryString, string compareString1, string compareString2) { // When - var matcher = new StringMatcher { UserSettingSearchPrecision = SearchPrecisionScore.Regular }; + var matcher = new StringMatcher(alphabet) { UserSettingSearchPrecision = SearchPrecisionScore.Regular }; // Given var compareString1Result = matcher.FuzzyMatch(queryString, compareString1); @@ -323,7 +325,7 @@ namespace Flow.Launcher.Test string secondName, string secondDescription, string secondExecutableName) { // Act - var matcher = new StringMatcher(); + var matcher = new StringMatcher(alphabet); var firstNameMatch = matcher.FuzzyMatch(queryString, firstName).RawScore; var firstDescriptionMatch = matcher.FuzzyMatch(queryString, firstDescription).RawScore; var firstExecutableNameMatch = matcher.FuzzyMatch(queryString, firstExecutableName).RawScore; @@ -358,7 +360,7 @@ namespace Flow.Launcher.Test public void WhenGivenAnAcronymQuery_ShouldReturnAcronymScore(string queryString, string compareString, int desiredScore) { - var matcher = new StringMatcher(); + var matcher = new StringMatcher(alphabet); var score = matcher.FuzzyMatch(queryString, compareString).Score; Assert.IsTrue(score == desiredScore, $@"Query: ""{queryString}"" From 8d8384965ea5d39c62d7ce2b865114555b393146 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 13 Jan 2025 12:00:45 +0800 Subject: [PATCH 086/259] Improve dependency injection in updater & settings view model & settings page --- Flow.Launcher.Core/Updater.cs | 20 ++++++++-------- Flow.Launcher/App.xaml.cs | 7 +++--- .../CustomQueryHotkeySetting.xaml.cs | 5 +--- Flow.Launcher/PublicAPIInstance.cs | 20 +++++++++++----- .../ViewModels/SettingsPaneAboutViewModel.cs | 2 +- .../SettingsPaneGeneralViewModel.cs | 2 +- .../ViewModels/SettingsPaneHotkeyViewModel.cs | 5 ++-- Flow.Launcher/SettingWindow.xaml.cs | 18 ++++++++++----- .../ViewModel/SettingWindowViewModel.cs | 23 ++----------------- 9 files changed, 46 insertions(+), 56 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 373418055..7a25447b4 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -34,14 +34,14 @@ namespace Flow.Launcher.Core private SemaphoreSlim UpdateLock { get; } = new SemaphoreSlim(1); - public async Task UpdateAppAsync(IPublicAPI api, bool silentUpdate = true) + public async Task UpdateAppAsync(bool silentUpdate = true) { await UpdateLock.WaitAsync().ConfigureAwait(false); try { if (!silentUpdate) - api.ShowMsg(api.GetTranslation("pleaseWait"), - api.GetTranslation("update_flowlauncher_update_check")); + API.ShowMsg(API.GetTranslation("pleaseWait"), + API.GetTranslation("update_flowlauncher_update_check")); using var updateManager = await GitHubUpdateManagerAsync(GitHubRepository).ConfigureAwait(false); @@ -56,13 +56,13 @@ namespace Flow.Launcher.Core if (newReleaseVersion <= currentVersion) { if (!silentUpdate) - API.ShowMsgBox(api.GetTranslation("update_flowlauncher_already_on_latest")); + API.ShowMsgBox(API.GetTranslation("update_flowlauncher_already_on_latest")); return; } if (!silentUpdate) - api.ShowMsg(api.GetTranslation("update_flowlauncher_update_found"), - api.GetTranslation("update_flowlauncher_updating")); + API.ShowMsg(API.GetTranslation("update_flowlauncher_update_found"), + API.GetTranslation("update_flowlauncher_updating")); await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply).ConfigureAwait(false); @@ -73,7 +73,7 @@ namespace Flow.Launcher.Core var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}"; FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination, (s) => API.ShowMsgBox(s)); if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination, (s) => API.ShowMsgBox(s))) - API.ShowMsgBox(string.Format(api.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"), + API.ShowMsgBox(string.Format(API.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"), DataLocation.PortableDataPath, targetDestination)); } @@ -86,7 +86,7 @@ namespace Flow.Launcher.Core Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}"); - if (API.ShowMsgBox(newVersionTips, api.GetTranslation("update_flowlauncher_new_update"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) + if (API.ShowMsgBox(newVersionTips, API.GetTranslation("update_flowlauncher_new_update"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) { UpdateManager.RestartApp(Constant.ApplicationFileName); } @@ -99,8 +99,8 @@ namespace Flow.Launcher.Core Log.Exception($"|Updater.UpdateApp|Error Occurred", e); if (!silentUpdate) - api.ShowMsg(api.GetTranslation("update_flowlauncher_fail"), - api.GetTranslation("update_flowlauncher_check_connection")); + API.ShowMsg(API.GetTranslation("update_flowlauncher_fail"), + API.GetTranslation("update_flowlauncher_check_connection")); } finally { diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 0d6d9855c..9384aae3d 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -74,8 +74,6 @@ namespace Flow.Launcher Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate(); - Ioc.Default.GetRequiredService().Initialize(); - Log.Info("|App.OnStartup|Begin Flow Launcher startup ----------------------------------------------------"); Log.Info($"|App.OnStartup|Runtime info:{ErrorReporting.RuntimeInfo()}"); @@ -96,6 +94,7 @@ namespace Flow.Launcher PluginManager.LoadPlugins(_settings.PluginSettings); API = Ioc.Default.GetRequiredService(); + ((PublicAPIInstance)API).Initialize(); Http.API = API; Http.Proxy = _settings.Proxy; @@ -160,11 +159,11 @@ namespace Flow.Launcher { // check update every 5 hours var timer = new PeriodicTimer(TimeSpan.FromHours(5)); - await Ioc.Default.GetRequiredService().UpdateAppAsync(API); + await Ioc.Default.GetRequiredService().UpdateAppAsync(); while (await timer.WaitForNextTickAsync()) // check updates on startup - await Ioc.Default.GetRequiredService().UpdateAppAsync(API); + await Ioc.Default.GetRequiredService().UpdateAppAsync(); } }); } diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index 47460ff7d..eab2705d0 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -6,20 +6,17 @@ using System.Linq; using System.Windows; using System.Windows.Input; using System.Windows.Controls; -using Flow.Launcher.Core; namespace Flow.Launcher { public partial class CustomQueryHotkeySetting : Window { - private SettingWindow _settingWidow; private bool update; private CustomPluginHotkey updateCustomHotkey; public Settings Settings { get; } - public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings) + public CustomQueryHotkeySetting(Settings settings) { - _settingWidow = settingWidow; Settings = settings; InitializeComponent(); } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 50765294c..54e97f6c6 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -26,6 +26,7 @@ using System.Collections.Concurrent; using System.Diagnostics; using System.Collections.Specialized; using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Core; namespace Flow.Launcher { @@ -33,19 +34,26 @@ namespace Flow.Launcher { private readonly SettingWindowViewModel _settingsVM; private readonly MainViewModel _mainVM; - private readonly IAlphabet _alphabet; - #region Constructor + private Updater _updater; + + #region Constructor & Initialization public PublicAPIInstance() { _settingsVM = Ioc.Default.GetRequiredService(); _mainVM = Ioc.Default.GetRequiredService(); - _alphabet = Ioc.Default.GetRequiredService(); GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback; WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); } + public void Initialize() + { + // We need to initialize Updater not in the constructor because we want to avoid + // recrusive dependency injection + _updater = Ioc.Default.GetRequiredService(); + } + #endregion #region Public API @@ -78,14 +86,14 @@ namespace Flow.Launcher public event VisibilityChangedEventHandler VisibilityChanged { add => _mainVM.VisibilityChanged += value; remove => _mainVM.VisibilityChanged -= value; } - public void CheckForNewUpdate() => _settingsVM.UpdateApp(); + public void CheckForNewUpdate() => _ = _updater.UpdateAppAsync(false); public void SaveAppAllSettings() { PluginManager.Save(); _mainVM.Save(); _settingsVM.Save(); - ImageLoader.Save(); + _ = ImageLoader.Save(); } public Task ReloadAllPluginData() => PluginManager.ReloadDataAsync(); @@ -105,7 +113,7 @@ namespace Flow.Launcher { Application.Current.Dispatcher.Invoke(() => { - SettingWindow sw = SingletonWindowOpener.Open(this, _settingsVM); + SettingWindow sw = SingletonWindowOpener.Open(); }); } diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs index 05fb16f5c..cb434f399 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs @@ -96,7 +96,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel } [RelayCommand] - private Task UpdateApp() => _updater.UpdateAppAsync(App.API, false); + private Task UpdateApp() => _updater.UpdateAppAsync(false); private void ClearLogFolder() { diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs index 3d94355e6..4e498ba23 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs @@ -160,7 +160,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel private void UpdateApp() { - _ = _updater.UpdateAppAsync(App.API, false); + _ = _updater.UpdateAppAsync(false); } public bool AutoUpdates diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs index fb57f499b..b13aaefe3 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs @@ -7,7 +7,6 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; -using Flow.Launcher.Core; namespace Flow.Launcher.SettingPages.ViewModels; @@ -71,7 +70,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel return; } - var window = new CustomQueryHotkeySetting(null, Settings); + var window = new CustomQueryHotkeySetting(Settings); window.UpdateItem(item); window.ShowDialog(); } @@ -79,7 +78,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel [RelayCommand] private void CustomHotkeyAdd() { - new CustomQueryHotkeySetting(null, Settings).ShowDialog(); + new CustomQueryHotkeySetting(Settings).ShowDialog(); } [RelayCommand] diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index cb3f1e4a1..ab639e987 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -3,6 +3,7 @@ using System.Windows; using System.Windows.Forms; using System.Windows.Input; using System.Windows.Interop; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core; using Flow.Launcher.Core.Configuration; using Flow.Launcher.Helper; @@ -17,16 +18,21 @@ namespace Flow.Launcher; public partial class SettingWindow { + private readonly Updater _updater; + private readonly IPortable _portable; private readonly IPublicAPI _api; private readonly Settings _settings; private readonly SettingWindowViewModel _viewModel; - public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel) + public SettingWindow() { + var viewModel = Ioc.Default.GetRequiredService(); _settings = viewModel.Settings; DataContext = viewModel; _viewModel = viewModel; - _api = api; + _updater = Ioc.Default.GetRequiredService(); + _portable = Ioc.Default.GetRequiredService(); + _api = Ioc.Default.GetRequiredService(); InitializePosition(); InitializeComponent(); } @@ -125,7 +131,7 @@ public partial class SettingWindow WindowState = _settings.SettingWindowState; } - private bool IsPositionValid(double top, double left) + private static bool IsPositionValid(double top, double left) { foreach (var screen in Screen.AllScreens) { @@ -145,7 +151,7 @@ public partial class SettingWindow var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0); var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0); - var left = (dip2.X - this.ActualWidth) / 2 + dip1.X; + var left = (dip2.X - ActualWidth) / 2 + dip1.X; return left; } @@ -154,13 +160,13 @@ public partial class SettingWindow var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y); var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height); - var top = (dip2.Y - this.ActualHeight) / 2 + dip1.Y - 20; + var top = (dip2.Y - ActualHeight) / 2 + dip1.Y - 20; return top; } private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) { - var paneData = new PaneData(_settings, _viewModel.Updater, _viewModel.Portable); + var paneData = new PaneData(_settings, _updater, _portable); if (args.IsSettingsSelected) { ContentFrame.Navigate(typeof(SettingsPaneGeneral), paneData); diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index bbd47e731..37276a1ad 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -1,37 +1,18 @@ using CommunityToolkit.Mvvm.DependencyInjection; -using Flow.Launcher.Core; -using Flow.Launcher.Core.Configuration; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; namespace Flow.Launcher.ViewModel; -public class SettingWindowViewModel : BaseModel +public partial class SettingWindowViewModel : BaseModel { - public Updater Updater { get; private set; } - - public IPortable Portable { get; private set; } - - public Settings Settings { get; } + public Settings Settings { get; init; } public SettingWindowViewModel() { Settings = Ioc.Default.GetRequiredService(); } - public void Initialize() - { - // We don not initialize Updater and Portable in the constructor because we want to avoid - // recrusive dependency injection - Updater = Ioc.Default.GetRequiredService(); - Portable = Ioc.Default.GetRequiredService(); - } - - public async void UpdateApp() - { - await Updater.UpdateAppAsync(App.API, false); - } - /// /// Save Flow settings. Plugins settings are not included. /// From 43965f4751fc31f978ae272c22bc9dab703ed006 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 22:11:23 +0000 Subject: [PATCH 087/259] Bump BitFaster.Caching from 2.5.2 to 2.5.3 Bumps [BitFaster.Caching](https://github.com/bitfaster/BitFaster.Caching) from 2.5.2 to 2.5.3. - [Release notes](https://github.com/bitfaster/BitFaster.Caching/releases) - [Commits](https://github.com/bitfaster/BitFaster.Caching/compare/v2.5.2...v2.5.3) --- updated-dependencies: - dependency-name: BitFaster.Caching dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Flow.Launcher.Infrastructure.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 1475252ca..1d6ee5c86 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -53,7 +53,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 8e5d77878af93e42de831b505a6c926e271917c0 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 18 Jan 2025 20:51:06 +1100 Subject: [PATCH 088/259] remove equality test --- .../Plugins/JsonRPCPluginTest.cs | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs b/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs index b4e0736c6..42a4630fe 100644 --- a/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs +++ b/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs @@ -63,28 +63,5 @@ namespace Flow.Launcher.Test.Plugins }) }; - [TestCaseSource(typeof(JsonRPCPluginTest), nameof(ResponseModelsSource))] - public async Task GivenModel_WhenSerializeWithDifferentNamingPolicy_ThenExpectSameResult_Async(JsonRPCQueryResponseModel reference) - { - var camelText = JsonSerializer.Serialize(reference, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); - - var pascalText = JsonSerializer.Serialize(reference); - - var results1 = await QueryAsync(new Query { Search = camelText }, default); - var results2 = await QueryAsync(new Query { Search = pascalText }, default); - - Assert.IsNotNull(results1); - Assert.IsNotNull(results2); - - foreach (var ((result1, result2), referenceResult) in results1.Zip(results2).Zip(reference.Result)) - { - Assert.AreEqual(result1.Title, result2.Title); - Assert.AreEqual(result1.Title, referenceResult.Title); - - Assert.IsNotNull(result1); - Assert.IsNotNull(result1.AsyncAction); - } - } - } } From 874a785be40cf57755fd0ebadfb554f6517ac8e8 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 18 Jan 2025 21:06:11 +1100 Subject: [PATCH 089/259] cache keywordIndex --- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 758250421..d48583f26 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -26,20 +26,21 @@ namespace Flow.Launcher.Plugin.Sys LoadThemes(); } - string search = query.Search[(query.Search.IndexOf(Keyword, StringComparison.Ordinal) + Keyword.Length + 1)..]; + int keywordIndex = query.Search.IndexOf(Keyword, StringComparison.Ordinal); + string search = query.Search[(keywordIndex + Keyword.Length + 1)..]; if (string.IsNullOrWhiteSpace(search)) { return themes.Select(CreateThemeResult) - .OrderBy(x => x.Title) - .ToList(); + .OrderBy(x => x.Title) + .ToList(); } return themes.Select(theme => (theme, matchResult: context.API.FuzzySearch(search, theme))) - .Where(x => x.matchResult.IsSearchPrecisionScoreMet()) - .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData)) - .OrderBy(x => x.Title) - .ToList(); + .Where(x => x.matchResult.IsSearchPrecisionScoreMet()) + .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData)) + .OrderBy(x => x.Title) + .ToList(); } private void OnVisibilityChanged(object sender, VisibilityChangedEventArgs args) From 40050545005adcfaa2acec8f046deeaea79d3049 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 18 Jan 2025 21:16:04 +1100 Subject: [PATCH 090/259] implement the complete IDisposable pattern --- .../Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index d48583f26..ca19bd33d 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -83,12 +83,31 @@ namespace Flow.Launcher.Plugin.Sys }; } + private bool disposed; + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + // Dispose managed resources + if (context?.API != null) + { + context.API.VisibilityChanged -= OnVisibilityChanged; + } + } + // Free unmanaged resources + disposed = true; + } + } + ~ThemeSelector() + { + Dispose(false); + } public void Dispose() { - if (context != null && context.API != null) - { - context.API.VisibilityChanged -= OnVisibilityChanged; - } + Dispose(true); + GC.SuppressFinalize(this); } } } From abe943b69339963dff909ecf5c8d9aaa6dc391ce Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 18 Jan 2025 18:39:44 +0800 Subject: [PATCH 091/259] Fix system language code fetch issue --- .../Resource/Internationalization.cs | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index 70f23c897..13efdda56 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -23,19 +23,45 @@ namespace Flow.Launcher.Core.Resource private const string Extension = ".xaml"; private readonly List _languageDirectories = new List(); private readonly List _oldResources = new List(); + private readonly string SystemLanguageCode; public Internationalization() { AddFlowLauncherLanguageDirectory(); + SystemLanguageCode = GetSystemLanguageCode(); } - private void AddFlowLauncherLanguageDirectory() { var directory = Path.Combine(Constant.ProgramDirectory, Folder); _languageDirectories.Add(directory); } + private static string GetSystemLanguageCode() + { + var availableLanguages = AvailableLanguages.GetAvailableLanguages(); + + // Retrieve the language identifiers for the current culture + var currentCulture = CultureInfo.CurrentCulture; + var twoLetterCode = currentCulture.TwoLetterISOLanguageName; + var threeLetterCode = currentCulture.ThreeLetterISOLanguageName; + var fullName = currentCulture.Name; + + // Try to find a match in the available languages list + foreach (var language in availableLanguages) + { + var languageCode = language.LanguageCode; + + if (string.Equals(languageCode, twoLetterCode, StringComparison.OrdinalIgnoreCase) || + string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) || + string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase)) + { + return languageCode; + } + } + + return DefaultLanguageCode; + } internal void AddPluginLanguageDirectories(IEnumerable plugins) { @@ -74,7 +100,7 @@ namespace Flow.Launcher.Core.Resource var isSystem = false; if (languageCode == Constant.SystemLanguageCode) { - languageCode = GetSystemLanguageCode(); + languageCode = SystemLanguageCode; isSystem = true; } @@ -178,36 +204,10 @@ namespace Flow.Launcher.Core.Resource public List LoadAvailableLanguages() { var list = AvailableLanguages.GetAvailableLanguages(); - list.Insert(0, new Language(Constant.SystemLanguageCode, AvailableLanguages.GetSystemTranslation(GetSystemLanguageCode()))); + list.Insert(0, new Language(Constant.SystemLanguageCode, AvailableLanguages.GetSystemTranslation(SystemLanguageCode))); return list; } - private string GetSystemLanguageCode() - { - var availableLanguages = AvailableLanguages.GetAvailableLanguages(); - - // Retrieve the language identifiers for the current culture - var currentCulture = CultureInfo.CurrentCulture; - var twoLetterCode = currentCulture.TwoLetterISOLanguageName; - var threeLetterCode = currentCulture.ThreeLetterISOLanguageName; - var fullName = currentCulture.Name; - - // Try to find a match in the available languages list - foreach (var language in availableLanguages) - { - var languageCode = language.LanguageCode; - - if (string.Equals(languageCode, twoLetterCode, StringComparison.OrdinalIgnoreCase) || - string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) || - string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase)) - { - return languageCode; - } - } - - return DefaultLanguageCode; - } - public string GetTranslation(string key) { var translation = Application.Current.TryFindResource(key); From fce3b3ae3d7ebb59747e3a94fb4011acce325141 Mon Sep 17 00:00:00 2001 From: Odotocodot <48138990+Odotocodot@users.noreply.github.com> Date: Sat, 18 Jan 2025 13:18:48 +0000 Subject: [PATCH 092/259] Fix crash on theme search --- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index ca19bd33d..3ea90197d 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -26,8 +26,7 @@ namespace Flow.Launcher.Plugin.Sys LoadThemes(); } - int keywordIndex = query.Search.IndexOf(Keyword, StringComparison.Ordinal); - string search = query.Search[(keywordIndex + Keyword.Length + 1)..]; + string search = query.SecondToEndSearch; if (string.IsNullOrWhiteSpace(search)) { @@ -52,7 +51,7 @@ namespace Flow.Launcher.Plugin.Sys } private void LoadThemes() - => themes = ThemeManager.Instance.LoadAvailableThemes().Select(Path.GetFileNameWithoutExtension); + => themes = ThemeManager.Instance.LoadAvailableThemes().Select(x => x.FileNameWithoutExtension); private static Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); From 1bf045f3e729f39e835bc1a6b3e7f9416a9c5bda Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 19 Jan 2025 15:15:02 +0800 Subject: [PATCH 093/259] Make fileMode usage between progress and non-progress paths consistent --- Flow.Launcher.Infrastructure/Http/Http.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 0b5d1b05a..0b3f2be65 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -97,7 +97,7 @@ namespace Flow.Launcher.Infrastructure.Http if (canReportProgress && reportProgress != null) { await using var contentStream = await response.Content.ReadAsStreamAsync(token); - await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true); + await using var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8192, true); var buffer = new byte[8192]; long totalRead = 0; From c32435f2ed741249289d573c5092bbc0e8cb036a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 19 Jan 2025 15:44:26 +0800 Subject: [PATCH 094/259] Use api to call download function & Add message box for all download operations --- .../PluginsManager.cs | 129 ++++++++++-------- 1 file changed, 71 insertions(+), 58 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index aee76e65e..ce51e8700 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -142,37 +142,15 @@ namespace Flow.Launcher.Plugin.PluginsManager var filePath = Path.Combine(Path.GetTempPath(), downloadFilename); - var exceptionHappened = false; try { using var cts = new CancellationTokenSource(); if (!plugin.IsFromLocalInstallPath) { - if (File.Exists(filePath)) - File.Delete(filePath); - - var prgBoxTitle = $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.Name}"; - await Context.API.ShowProgressBoxAsync(prgBoxTitle, - async (reportProgress) => - { - if (reportProgress == null) - { - // when reportProgress is null, it means there is expcetion with the progress box - // so we record it with exceptionHappened and return so that progress box will close instantly - exceptionHappened = true; - return; - } - else - { - await Http.DownloadAsync(plugin.UrlDownload, filePath, reportProgress, cts.Token).ConfigureAwait(false); - } - }, cts.Cancel); - - // if exception happened while downloading and user does not cancel downloading, - // we need to redownload the plugin - if (exceptionHappened && (!cts.IsCancellationRequested)) - await Http.DownloadAsync(plugin.UrlDownload, filePath, null, cts.Token).ConfigureAwait(false); + await DeleteFileAndDownloadMsgBoxAsync( + $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.Name}", + plugin.UrlDownload, filePath, cts); } else { @@ -221,6 +199,34 @@ namespace Flow.Launcher.Plugin.PluginsManager } } + private async Task DeleteFileAndDownloadMsgBoxAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts) + { + if (File.Exists(filePath)) + File.Delete(filePath); + + var exceptionHappened = false; + await Context.API.ShowProgressBoxAsync(prgBoxTitle, + async (reportProgress) => + { + if (reportProgress == null) + { + // when reportProgress is null, it means there is expcetion with the progress box + // so we record it with exceptionHappened and return so that progress box will close instantly + exceptionHappened = true; + return; + } + else + { + await Context.API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false); + } + }, cts.Cancel); + + // if exception happened while downloading and user does not cancel downloading, + // we need to redownload the plugin + if (exceptionHappened && (!cts.IsCancellationRequested)) + await Context.API.HttpDownloadAsync(downloadUrl, filePath).ConfigureAwait(false); + } + internal async ValueTask> RequestUpdateAsync(string search, CancellationToken token, bool usePrimaryUrlOnly = false) { @@ -308,43 +314,48 @@ namespace Flow.Launcher.Plugin.PluginsManager _ = Task.Run(async delegate { + using var cts = new CancellationTokenSource(); + if (!x.PluginNewUserPlugin.IsFromLocalInstallPath) { - if (File.Exists(downloadToFilePath)) - { - File.Delete(downloadToFilePath); - } - - await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath) - .ConfigureAwait(false); + await DeleteFileAndDownloadMsgBoxAsync( + $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {x.PluginNewUserPlugin.Name}", + x.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts); } else { downloadToFilePath = x.PluginNewUserPlugin.LocalInstallPath; } - - PluginManager.UpdatePlugin(x.PluginExistingMetadata, x.PluginNewUserPlugin, - downloadToFilePath); - - if (Settings.AutoRestartAfterChanging) + // check if user cancelled download before installing plugin + if (cts.IsCancellationRequested) { - Context.API.ShowMsg( - Context.API.GetTranslation("plugin_pluginsmanager_update_title"), - string.Format( - Context.API.GetTranslation( - "plugin_pluginsmanager_update_success_restart"), - x.Name)); - Context.API.RestartApp(); + return; } else { - Context.API.ShowMsg( - Context.API.GetTranslation("plugin_pluginsmanager_update_title"), - string.Format( - Context.API.GetTranslation( - "plugin_pluginsmanager_update_success_no_restart"), - x.Name)); + PluginManager.UpdatePlugin(x.PluginExistingMetadata, x.PluginNewUserPlugin, + downloadToFilePath); + + if (Settings.AutoRestartAfterChanging) + { + Context.API.ShowMsg( + Context.API.GetTranslation("plugin_pluginsmanager_update_title"), + string.Format( + Context.API.GetTranslation( + "plugin_pluginsmanager_update_success_restart"), + x.Name)); + Context.API.RestartApp(); + } + else + { + Context.API.ShowMsg( + Context.API.GetTranslation("plugin_pluginsmanager_update_title"), + string.Format( + Context.API.GetTranslation( + "plugin_pluginsmanager_update_success_no_restart"), + x.Name)); + } } }).ContinueWith(t => { @@ -405,16 +416,18 @@ namespace Flow.Launcher.Plugin.PluginsManager try { - if (File.Exists(downloadToFilePath)) - { - File.Delete(downloadToFilePath); - } + using var cts = new CancellationTokenSource(); - await Http.DownloadAsync(plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath) - .ConfigureAwait(false); + await DeleteFileAndDownloadMsgBoxAsync( + $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.PluginNewUserPlugin.Name}", + plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts); - PluginManager.UpdatePlugin(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, - downloadToFilePath); + // check if user cancelled download before installing plugin + if (cts.IsCancellationRequested) + return; + else + PluginManager.UpdatePlugin(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, + downloadToFilePath); } catch (Exception ex) { From d21b9362cf098c99030ba8a91fd545cf418c2991 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Mon, 20 Jan 2025 09:14:28 -0600 Subject: [PATCH 095/259] do not try catch the error for jsonrpc v2 --- Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs | 45 ++++++-------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs index 5a6633525..305b28150 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs @@ -26,54 +26,33 @@ namespace Flow.Launcher.Core.Plugin protected override async Task ExecuteResultAsync(JsonRPCResult result) { - try - { - var res = await RPC.InvokeAsync(result.JsonRPCAction.Method, - argument: result.JsonRPCAction.Parameters); + var res = await RPC.InvokeAsync(result.JsonRPCAction.Method, + argument: result.JsonRPCAction.Parameters); - return res.Hide; - } - catch - { - return false; - } + return res.Hide; } private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext()); public override List LoadContextMenus(Result selectedResult) { - try - { - var res = JTF.Run(() => RPC.InvokeWithCancellationAsync("context_menu", - new object[] { selectedResult.ContextData })); + var res = JTF.Run(() => RPC.InvokeWithCancellationAsync("context_menu", + new object[] { selectedResult.ContextData })); - var results = ParseResults(res); + var results = ParseResults(res); - return results; - } - catch - { - return new List(); - } + return results; } public override async Task> QueryAsync(Query query, CancellationToken token) { - try - { - var res = await RPC.InvokeWithCancellationAsync("query", - new object[] { query, Settings.Inner }, - token); + var res = await RPC.InvokeWithCancellationAsync("query", + new object[] { query, Settings.Inner }, + token); - var results = ParseResults(res); + var results = ParseResults(res); - return results; - } - catch - { - return new List(); - } + return results; } From 5d164293b915d9c5d924b739ea3e0f13ad386542 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 22:39:42 +0000 Subject: [PATCH 096/259] Bump FSharp.Core from 9.0.100 to 9.0.101 Bumps [FSharp.Core](https://github.com/dotnet/fsharp) from 9.0.100 to 9.0.101. - [Release notes](https://github.com/dotnet/fsharp/releases) - [Changelog](https://github.com/dotnet/fsharp/blob/main/release-notes.md) - [Commits](https://github.com/dotnet/fsharp/commits) --- updated-dependencies: - dependency-name: FSharp.Core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index 8aeca4699..df2f4d2cb 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -54,7 +54,7 @@ - + From 198442621a94de8aabf26e56d58dec751080c294 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 21 Jan 2025 14:37:14 +0800 Subject: [PATCH 097/259] Add support for record key --- Flow.Launcher.Plugin/Result.cs | 17 +++++++++++++++ Flow.Launcher/Storage/TopMostRecord.cs | 18 ++++++++++++---- Flow.Launcher/Storage/UserSelectedRecord.cs | 24 ++++++++++++++++----- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index c6ca81cf3..bb005752e 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -185,6 +185,16 @@ namespace Flow.Launcher.Plugin TitleHighlightData = TitleHighlightData, OriginQuery = OriginQuery, PluginDirectory = PluginDirectory, + ContextData = ContextData, + PluginID = PluginID, + TitleToolTip = TitleToolTip, + SubTitleToolTip = SubTitleToolTip, + PreviewPanel = PreviewPanel, + ProgressBar = ProgressBar, + ProgressBarColor = ProgressBarColor, + Preview = Preview, + AddSelectedCount = AddSelectedCount, + RecordKey = RecordKey }; } @@ -252,6 +262,13 @@ namespace Flow.Launcher.Plugin /// public const int MaxScore = int.MaxValue; + /// + /// The key to identify the record. This is used when FL checks whether the result is the topmost record. Or FL calculates the hashcode of the result for user selected records. + /// This can be useful when your plugin will change the Title or SubTitle of the result dynamically. + /// If the plugin does not specific this, FL just uses Title and SubTitle to identify this result. + /// + public string RecordKey { get; set; } = string.Empty; + /// /// Info of the preview section of a /// diff --git a/Flow.Launcher/Storage/TopMostRecord.cs b/Flow.Launcher/Storage/TopMostRecord.cs index cbd0b88fc..05cf01401 100644 --- a/Flow.Launcher/Storage/TopMostRecord.cs +++ b/Flow.Launcher/Storage/TopMostRecord.cs @@ -33,7 +33,8 @@ namespace Flow.Launcher.Storage { PluginID = result.PluginID, Title = result.Title, - SubTitle = result.SubTitle + SubTitle = result.SubTitle, + RecordKey = result.RecordKey }; records.AddOrUpdate(result.OriginQuery.RawQuery, record, (key, oldValue) => record); } @@ -49,12 +50,21 @@ namespace Flow.Launcher.Storage public string Title { get; set; } public string SubTitle { get; set; } public string PluginID { get; set; } + public string RecordKey { get; set; } public bool Equals(Result r) { - return Title == r.Title - && SubTitle == r.SubTitle - && PluginID == r.PluginID; + if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey)) + { + return Title == r.Title + && SubTitle == r.SubTitle + && PluginID == r.PluginID; + } + else + { + return RecordKey == r.RecordKey + && PluginID == r.PluginID; + } } } } diff --git a/Flow.Launcher/Storage/UserSelectedRecord.cs b/Flow.Launcher/Storage/UserSelectedRecord.cs index d6405005d..6da36747d 100644 --- a/Flow.Launcher/Storage/UserSelectedRecord.cs +++ b/Flow.Launcher/Storage/UserSelectedRecord.cs @@ -15,7 +15,6 @@ namespace Flow.Launcher.Storage [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public Dictionary records { get; private set; } - public UserSelectedRecord() { recordsWithQuery = new Dictionary(); @@ -45,8 +44,15 @@ namespace Flow.Launcher.Storage private static int GenerateResultHashCode(Result result) { - int hashcode = GenerateStaticHashCode(result.Title); - return GenerateStaticHashCode(result.SubTitle, hashcode); + if (string.IsNullOrEmpty(result.RecordKey)) + { + int hashcode = GenerateStaticHashCode(result.Title); + return GenerateStaticHashCode(result.SubTitle, hashcode); + } + else + { + return GenerateStaticHashCode(result.RecordKey); + } } private static int GenerateQueryAndResultHashCode(Query query, Result result) @@ -58,8 +64,16 @@ namespace Flow.Launcher.Storage int hashcode = GenerateStaticHashCode(query.ActionKeyword); hashcode = GenerateStaticHashCode(query.Search, hashcode); - hashcode = GenerateStaticHashCode(result.Title, hashcode); - hashcode = GenerateStaticHashCode(result.SubTitle, hashcode); + + if (string.IsNullOrEmpty(result.RecordKey)) + { + hashcode = GenerateStaticHashCode(result.Title, hashcode); + hashcode = GenerateStaticHashCode(result.SubTitle, hashcode); + } + else + { + hashcode = GenerateStaticHashCode(result.RecordKey, hashcode); + } return hashcode; } From ed399371976b60436eeb9042c59696859eed3caf Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 21 Jan 2025 16:19:28 +0800 Subject: [PATCH 098/259] Initialize App.API earlier & Improve code quality --- Flow.Launcher/App.xaml.cs | 5 ++--- Flow.Launcher/PublicAPIInstance.cs | 13 ++----------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 9384aae3d..a64c9e750 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -70,6 +70,8 @@ namespace Flow.Launcher ).Build(); Ioc.Default.ConfigureServices(host.Services); + API = Ioc.Default.GetRequiredService(); + Ioc.Default.GetRequiredService().Initialize(Launcher.Properties.Settings.Default.GithubRepo); Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate(); @@ -93,9 +95,6 @@ namespace Flow.Launcher PluginManager.LoadPlugins(_settings.PluginSettings); - API = Ioc.Default.GetRequiredService(); - ((PublicAPIInstance)API).Initialize(); - Http.API = API; Http.Proxy = _settings.Proxy; diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 54e97f6c6..0329d6973 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -35,9 +35,7 @@ namespace Flow.Launcher private readonly SettingWindowViewModel _settingsVM; private readonly MainViewModel _mainVM; - private Updater _updater; - - #region Constructor & Initialization + #region Constructor public PublicAPIInstance() { @@ -47,13 +45,6 @@ namespace Flow.Launcher WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); } - public void Initialize() - { - // We need to initialize Updater not in the constructor because we want to avoid - // recrusive dependency injection - _updater = Ioc.Default.GetRequiredService(); - } - #endregion #region Public API @@ -86,7 +77,7 @@ namespace Flow.Launcher public event VisibilityChangedEventHandler VisibilityChanged { add => _mainVM.VisibilityChanged += value; remove => _mainVM.VisibilityChanged -= value; } - public void CheckForNewUpdate() => _ = _updater.UpdateAppAsync(false); + public void CheckForNewUpdate() => _ = Ioc.Default.GetRequiredService().UpdateAppAsync(false); public void SaveAppAllSettings() { From f9983b587712bdc439022f4ac19bda46133d9ab8 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 22 Jan 2025 12:25:56 +0800 Subject: [PATCH 099/259] Move dependency injection codes to constructor --- Flow.Launcher/App.xaml.cs | 47 +++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index a64c9e750..d983ab000 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -30,7 +30,31 @@ namespace Flow.Launcher public static IPublicAPI API { get; private set; } private const string Unique = "Flow.Launcher_Unique_Application_Mutex"; private static bool _disposed; - private Settings _settings; + private readonly Settings _settings; + + public App() + { + // Initialize settings + var storage = new FlowLauncherJsonStorage(); + _settings = storage.Load(); + _settings.Initialize(storage); + _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); + + // Configure the dependency injection container + var host = Host.CreateDefaultBuilder() + .UseContentRoot(AppContext.BaseDirectory) + .ConfigureServices(services => services + .AddSingleton(_ => _settings) + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + ).Build(); + Ioc.Default.ConfigureServices(host.Services); + } [STAThread] public static void Main() @@ -49,27 +73,6 @@ namespace Flow.Launcher { await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { - // Initialize settings - var storage = new FlowLauncherJsonStorage(); - _settings = storage.Load(); - _settings.Initialize(storage); - _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); - - // Configure the dependency injection container - var host = Host.CreateDefaultBuilder() - .UseContentRoot(AppContext.BaseDirectory) - .ConfigureServices(services => services - .AddSingleton(_ => _settings) - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - ).Build(); - Ioc.Default.ConfigureServices(host.Services); - API = Ioc.Default.GetRequiredService(); Ioc.Default.GetRequiredService().Initialize(Launcher.Properties.Settings.Default.GithubRepo); From fec553c87ca451d2d5cac3e1e71998e702fe8b8c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 24 Jan 2025 12:11:48 +0800 Subject: [PATCH 100/259] Improve uninstaller check function --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 39 +++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index e311a0b94..5ccccc24e 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -41,9 +41,13 @@ namespace Flow.Launcher.Plugin.Program "uninst000.exe", "uninstall.exe" }; - // For cases when the uninstaller is named like "Uninstall Program Name.exe" - private const string CommonUninstallerPrefix = "uninstall"; - private const string CommonUninstallerSuffix = ".exe"; + private static readonly string[] commonUninstallerPrefixs = + { + "uninstall", + "卸载" + }; + private const string ExeUninstallerSuffix = ".exe"; + private const string InkUninstallerSuffix = ".lnk"; static Main() { @@ -96,10 +100,33 @@ namespace Flow.Launcher.Plugin.Program { if (!_settings.HideUninstallers) return true; if (program is not Win32 win32) return true; + + // First check the executable path var fileName = Path.GetFileName(win32.ExecutablePath); - return !commonUninstallerNames.Contains(fileName, StringComparer.OrdinalIgnoreCase) && - !(fileName.StartsWith(CommonUninstallerPrefix, StringComparison.OrdinalIgnoreCase) && - fileName.EndsWith(CommonUninstallerSuffix, StringComparison.OrdinalIgnoreCase)); + // For cases when the uninstaller is named like "uninst.exe" + if (commonUninstallerNames.Contains(fileName, StringComparer.OrdinalIgnoreCase)) return false; + // For cases when the uninstaller is named like "Uninstall Program Name.exe" + foreach (var prefix in commonUninstallerPrefixs) + { + if (fileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) && + fileName.EndsWith(ExeUninstallerSuffix, StringComparison.OrdinalIgnoreCase)) + return false; + } + + // Second check the ink path + if (!string.IsNullOrEmpty(win32.LnkResolvedPath)) + { + var inkFileName = Path.GetFileName(win32.FullPath); + // For cases when the uninstaller is named like "Uninstall Program Name.ink" + foreach (var prefix in commonUninstallerPrefixs) + { + if (inkFileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) && + inkFileName.EndsWith(InkUninstallerSuffix, StringComparison.OrdinalIgnoreCase)) + return false; + } + } + + return true; } public async Task InitAsync(PluginInitContext context) From 71dad9f35616b0d0f6f2a3df4c7dca5791ec17ba Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 24 Jan 2025 18:35:11 +0800 Subject: [PATCH 101/259] Add support for more uninstaller prefixs --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 27 ++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 5ccccc24e..511794f89 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -43,8 +43,31 @@ namespace Flow.Launcher.Plugin.Program }; private static readonly string[] commonUninstallerPrefixs = { - "uninstall", - "卸载" + "uninstall",//en + "卸载",//zh-cn + "卸載",//zh-tw + "видалити",//uk-UA + "удалить",//ru + "désinstaller",//fr + "アンインストール",//ja + "deïnstalleren",//nl + "odinstaluj",//pl + "afinstallere",//da + "deinstallieren",//de + "삭제",//ko + "деинсталирај",//sr + "desinstalar",//pt-pt + "desinstalar",//pt-br + "desinstalar",//es + "desinstalar",//es-419 + "disinstallare",//it + "avinstallere",//nb-NO + "odinštalovať",//sk + "kaldır",//tr + "odinstalovat",//cs + "إلغاء التثبيت",//ar + "gỡ bỏ",//vi-vn + "הסרה"//he }; private const string ExeUninstallerSuffix = ".exe"; private const string InkUninstallerSuffix = ".lnk"; From 0c7dc07c743df01bce72c001061ede34b9b0fc08 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 26 Jan 2025 09:34:07 +1100 Subject: [PATCH 102/259] fix typo --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 511794f89..00b97e114 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -136,7 +136,7 @@ namespace Flow.Launcher.Plugin.Program return false; } - // Second check the ink path + // Second check the lnk path if (!string.IsNullOrEmpty(win32.LnkResolvedPath)) { var inkFileName = Path.GetFileName(win32.FullPath); From 0e700cdfcc5aced08e75e19c38f33836d7276628 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sun, 26 Jan 2025 10:42:32 +1100 Subject: [PATCH 103/259] rename GetSystemLanguageCode method + add comment --- Flow.Launcher.Core/Resource/Internationalization.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index 13efdda56..ef38e8be0 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -28,7 +28,7 @@ namespace Flow.Launcher.Core.Resource public Internationalization() { AddFlowLauncherLanguageDirectory(); - SystemLanguageCode = GetSystemLanguageCode(); + SystemLanguageCode = GetSystemLanguageCodeAtStartup(); } private void AddFlowLauncherLanguageDirectory() @@ -37,11 +37,13 @@ namespace Flow.Launcher.Core.Resource _languageDirectories.Add(directory); } - private static string GetSystemLanguageCode() + private static string GetSystemLanguageCodeAtStartup() { var availableLanguages = AvailableLanguages.GetAvailableLanguages(); - // Retrieve the language identifiers for the current culture + // Retrieve the language identifiers for the current culture. + // ChangeLanguage method overrides the CultureInfo.CurrentCulture, so this needs to + // be called at startup in order to get the correct lang code of system. var currentCulture = CultureInfo.CurrentCulture; var twoLetterCode = currentCulture.TwoLetterISOLanguageName; var threeLetterCode = currentCulture.ThreeLetterISOLanguageName; From 1562c88ea71a0f56033553016682a51bc019d590 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 26 Jan 2025 20:07:40 +0800 Subject: [PATCH 104/259] Improve context menu item action response --- Flow.Launcher/ViewModel/MainViewModel.cs | 4 ++++ Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs | 1 + Plugins/Flow.Launcher.Plugin.Program/Main.cs | 2 ++ 3 files changed, 7 insertions(+) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 55bc8d1b3..b12e97e0b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1273,6 +1273,8 @@ namespace Flow.Launcher.ViewModel { _topMostRecord.Remove(result); App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success")); + App.API.BackToQueryResults(); + App.API.ReQuery(); return false; } }; @@ -1289,6 +1291,8 @@ namespace Flow.Launcher.ViewModel { _topMostRecord.AddOrUpdate(result); App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success")); + App.API.BackToQueryResults(); + App.API.ReQuery(); return false; } }; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs index feccc74c8..3f3b7cb58 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs @@ -242,6 +242,7 @@ namespace Flow.Launcher.Plugin.Explorer var name = "Plugin: Folder"; var message = $"File not found: {e.Message}"; Context.API.ShowMsgError(name, message); + return false; } return true; diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 00b97e114..6ba7047f2 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -264,6 +264,8 @@ namespace Flow.Launcher.Plugin.Program Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"), Context.API.GetTranslation( "flowlauncher_plugin_program_disable_dlgtitle_success_message")); + Context.API.BackToQueryResults(); + Context.API.ReQuery(); return false; }, IcoPath = "Images/disable.png", From ae5186dacfad5fd354867b1ec254edaa913e0a52 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 26 Jan 2025 20:21:30 +0800 Subject: [PATCH 105/259] Remove context menu cache --- Flow.Launcher/ViewModel/MainViewModel.cs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index b12e97e0b..2d232ebdd 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -34,8 +34,6 @@ namespace Flow.Launcher.ViewModel private bool _isQueryRunning; private Query _lastQuery; - private Result lastContextMenuResult = new Result(); - private List lastContextMenuResults = new List(); private string _queryTextBeforeLeaveResults; private readonly FlowLauncherJsonStorage _historyItemsStorage; @@ -986,19 +984,10 @@ namespace Flow.Launcher.ViewModel if (selected != null) // SelectedItem returns null if selection is empty. { List results; - if (selected == lastContextMenuResult) - { - results = lastContextMenuResults; - } - else - { + results = PluginManager.GetContextMenusForPlugin(selected); - lastContextMenuResults = results; - lastContextMenuResult = selected; results.Add(ContextMenuTopMost(selected)); results.Add(ContextMenuPluginInfo(selected.PluginID)); - } - if (!string.IsNullOrEmpty(query)) { @@ -1381,8 +1370,6 @@ namespace Flow.Launcher.ViewModel lastHistoryIndex = 1; // Trick for no delay MainWindowOpacity = 0; - lastContextMenuResult = new Result(); - lastContextMenuResults = new List(); if (ExternalPreviewVisible) CloseExternalPreview(); From 00de8611e1996d724c48672b5712c4db8f071b63 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 26 Jan 2025 20:37:41 +0800 Subject: [PATCH 106/259] Remove useless obsolete constructor --- Flow.Launcher.Plugin/Query.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs index b41675a1a..e182491c2 100644 --- a/Flow.Launcher.Plugin/Query.cs +++ b/Flow.Launcher.Plugin/Query.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; namespace Flow.Launcher.Plugin { @@ -9,15 +6,6 @@ namespace Flow.Launcher.Plugin { public Query() { } - [Obsolete("Use the default Query constructor.")] - public Query(string rawQuery, string search, string[] terms, string[] searchTerms, string actionKeyword = "") - { - Search = search; - RawQuery = rawQuery; - SearchTerms = searchTerms; - ActionKeyword = actionKeyword; - } - /// /// Raw query, this includes action keyword if it has /// We didn't recommend use this property directly. You should always use Search property. From 95c8475c436b687822ddee2b342da5e4945225b3 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 26 Jan 2025 20:45:58 +0800 Subject: [PATCH 107/259] Fix null exception when result is from context menu & Add documents --- Flow.Launcher/Storage/TopMostRecord.cs | 2 ++ Flow.Launcher/Storage/UserSelectedRecord.cs | 2 ++ Flow.Launcher/ViewModel/MainViewModel.cs | 14 +++++++++----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/Storage/TopMostRecord.cs b/Flow.Launcher/Storage/TopMostRecord.cs index cbd0b88fc..e76c57493 100644 --- a/Flow.Launcher/Storage/TopMostRecord.cs +++ b/Flow.Launcher/Storage/TopMostRecord.cs @@ -12,6 +12,8 @@ namespace Flow.Launcher.Storage internal bool IsTopMost(Result result) { + // origin query is null when user select the context menu item directly of one item from query list + // in this case, we do not need to check if the result is top most if (records.IsEmpty || result.OriginQuery == null || !records.TryGetValue(result.OriginQuery.RawQuery, out var value)) { diff --git a/Flow.Launcher/Storage/UserSelectedRecord.cs b/Flow.Launcher/Storage/UserSelectedRecord.cs index d6405005d..4f62d2b08 100644 --- a/Flow.Launcher/Storage/UserSelectedRecord.cs +++ b/Flow.Launcher/Storage/UserSelectedRecord.cs @@ -51,6 +51,8 @@ namespace Flow.Launcher.Storage private static int GenerateQueryAndResultHashCode(Query query, Result result) { + // query is null when user select the context menu item directly of one item from query list + // so we only need to consider the result if (query == null) { return GenerateResultHashCode(result); diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 2d232ebdd..5c3251bfc 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -396,11 +396,15 @@ namespace Flow.Launcher.ViewModel }) .ConfigureAwait(false); - if (SelectedIsFromQueryResults()) { _userSelectedRecord.Add(result); - _history.Add(result.OriginQuery.RawQuery); + // origin query is null when user select the context menu item directly of one item from query list + // so we don't want to add it to history + if (result.OriginQuery != null) + { + _history.Add(result.OriginQuery.RawQuery); + } lastHistoryIndex = 1; } @@ -985,9 +989,9 @@ namespace Flow.Launcher.ViewModel { List results; - results = PluginManager.GetContextMenusForPlugin(selected); - results.Add(ContextMenuTopMost(selected)); - results.Add(ContextMenuPluginInfo(selected.PluginID)); + results = PluginManager.GetContextMenusForPlugin(selected); + results.Add(ContextMenuTopMost(selected)); + results.Add(ContextMenuPluginInfo(selected.PluginID)); if (!string.IsNullOrEmpty(query)) { From 80f54ba0de3b55c6ef1cac360078dddd9a1e07a4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 26 Jan 2025 20:51:12 +0800 Subject: [PATCH 108/259] Fix more possible origin query null exception & Remove useless load function --- Flow.Launcher/Storage/TopMostRecord.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/Storage/TopMostRecord.cs b/Flow.Launcher/Storage/TopMostRecord.cs index e76c57493..a2af6fe92 100644 --- a/Flow.Launcher/Storage/TopMostRecord.cs +++ b/Flow.Launcher/Storage/TopMostRecord.cs @@ -26,11 +26,25 @@ namespace Flow.Launcher.Storage internal void Remove(Result result) { + // origin query is null when user select the context menu item directly of one item from query list + // in this case, we do not need to remove the record + if (result.OriginQuery == null) + { + return; + } + records.Remove(result.OriginQuery.RawQuery, out _); } internal void AddOrUpdate(Result result) { + // origin query is null when user select the context menu item directly of one item from query list + // in this case, we do not need to add or update the record + if (result.OriginQuery == null) + { + return; + } + var record = new Record { PluginID = result.PluginID, @@ -39,11 +53,6 @@ namespace Flow.Launcher.Storage }; records.AddOrUpdate(result.OriginQuery.RawQuery, record, (key, oldValue) => record); } - - public void Load(Dictionary dictionary) - { - records = new ConcurrentDictionary(dictionary); - } } public class Record From 1c7e29013e96efb1abecdb3bb9f1a2043017b49c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 27 Jan 2025 09:11:27 +0800 Subject: [PATCH 109/259] Fix setting window freeze issue & Improve singleton window opener --- Flow.Launcher/Helper/SingletonWindowOpener.cs | 21 +++++++++++++++---- Flow.Launcher/SettingWindow.xaml.cs | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/Helper/SingletonWindowOpener.cs b/Flow.Launcher/Helper/SingletonWindowOpener.cs index b5c2d8b55..5282b61f9 100644 --- a/Flow.Launcher/Helper/SingletonWindowOpener.cs +++ b/Flow.Launcher/Helper/SingletonWindowOpener.cs @@ -10,16 +10,29 @@ public static class SingletonWindowOpener { var window = Application.Current.Windows.OfType().FirstOrDefault(x => x.GetType() == typeof(T)) ?? (T)Activator.CreateInstance(typeof(T), args); - + // Fix UI bug // Add `window.WindowState = WindowState.Normal` // If only use `window.Show()`, Settings-window doesn't show when minimized in taskbar // Not sure why this works tho // Probably because, when `.Show()` fails, `window.WindowState == Minimized` (not `Normal`) // https://stackoverflow.com/a/59719760/4230390 - window.WindowState = WindowState.Normal; - window.Show(); - + // Ensure the window is not minimized before showing it + if (window.WindowState == WindowState.Minimized) + { + window.WindowState = WindowState.Normal; + } + + // Ensure the window is visible + if (!window.IsVisible) + { + window.Show(); + } + else + { + window.Activate(); // Bring the window to the foreground if already open + } + window.Focus(); return (T)window; diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index cb3f1e4a1..d5b303516 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -34,11 +34,11 @@ public partial class SettingWindow private void OnLoaded(object sender, RoutedEventArgs e) { RefreshMaximizeRestoreButton(); - // Fix (workaround) for the window freezes after lock screen (Win+L) + // Fix (workaround) for the window freezes after lock screen (Win+L) or sleep // https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; HwndTarget hwndTarget = hwndSource.CompositionTarget; - hwndTarget.RenderMode = RenderMode.Default; + hwndTarget.RenderMode = RenderMode.SoftwareOnly; // Must use software only render mode here InitializePosition(); } From 23a1e5bc5853d2f6a4ba0e83c1c36ac960da40d9 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 27 Jan 2025 09:39:12 +0800 Subject: [PATCH 110/259] Initialize public api instance in constructor so that we can use App.API all the time --- Flow.Launcher/App.xaml.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index d983ab000..f800ccd5d 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -54,6 +54,9 @@ namespace Flow.Launcher .AddSingleton() ).Build(); Ioc.Default.ConfigureServices(host.Services); + + // Initialize the public API first + API = Ioc.Default.GetRequiredService(); } [STAThread] @@ -73,8 +76,6 @@ namespace Flow.Launcher { await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { - API = Ioc.Default.GetRequiredService(); - Ioc.Default.GetRequiredService().Initialize(Launcher.Properties.Settings.Default.GithubRepo); Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate(); From ed16d340cb1c43464b9046a2672edc5d189c01bc Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 27 Jan 2025 09:40:24 +0800 Subject: [PATCH 111/259] Improve code quality --- Flow.Launcher.Core/Plugin/PluginManager.cs | 6 +++--- Flow.Launcher.Infrastructure/Http/Http.cs | 3 ++- Flow.Launcher/App.xaml.cs | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index a776c10ab..0e8a4b776 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -14,6 +14,7 @@ using ISavable = Flow.Launcher.Plugin.ISavable; using Flow.Launcher.Plugin.SharedCommands; using System.Text.Json; using Flow.Launcher.Core.Resource; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.Core.Plugin { @@ -28,7 +29,7 @@ namespace Flow.Launcher.Core.Plugin public static readonly HashSet GlobalPlugins = new(); public static readonly Dictionary NonGlobalPlugins = new(); - public static IPublicAPI API { private set; get; } + public static IPublicAPI API { get; private set; } = Ioc.Default.GetRequiredService(); private static PluginsSettings Settings; private static List _metadatas; @@ -158,9 +159,8 @@ namespace Flow.Launcher.Core.Plugin /// Call initialize for all plugins /// /// return the list of failed to init plugins or null for none - public static async Task InitializePluginsAsync(IPublicAPI api) + public static async Task InitializePluginsAsync() { - API = api; var failedPlugins = new ConcurrentQueue(); var InitTasks = AllPlugins.Select(pair => Task.Run(async delegate diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 14b8eef4e..3711a6b0d 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -8,6 +8,7 @@ using Flow.Launcher.Infrastructure.UserSettings; using System; using System.Threading; using Flow.Launcher.Plugin; +using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.Infrastructure.Http { @@ -17,7 +18,7 @@ namespace Flow.Launcher.Infrastructure.Http private static HttpClient client = new HttpClient(); - public static IPublicAPI API { get; set; } + private static IPublicAPI API { get; set; } = Ioc.Default.GetRequiredService(); static Http() { diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index f800ccd5d..5f7f097e0 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -99,10 +99,9 @@ namespace Flow.Launcher PluginManager.LoadPlugins(_settings.PluginSettings); - Http.API = API; Http.Proxy = _settings.Proxy; - await PluginManager.InitializePluginsAsync(API); + await PluginManager.InitializePluginsAsync(); await imageLoadertask; var mainVM = Ioc.Default.GetRequiredService(); From 6a2389f4b8c95d87ee72041a0e78812333fe3fd3 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 27 Jan 2025 10:45:05 +0800 Subject: [PATCH 112/259] Fix test project build issue --- Flow.Launcher.Infrastructure/Http/Http.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 3711a6b0d..78545a87b 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -18,8 +18,6 @@ namespace Flow.Launcher.Infrastructure.Http private static HttpClient client = new HttpClient(); - private static IPublicAPI API { get; set; } = Ioc.Default.GetRequiredService(); - static Http() { // need to be added so it would work on a win10 machine @@ -79,7 +77,7 @@ namespace Flow.Launcher.Infrastructure.Http } catch (UriFormatException e) { - API.ShowMsg("Please try again", "Unable to parse Http Proxy"); + Ioc.Default.GetRequiredService().ShowMsg("Please try again", "Unable to parse Http Proxy"); Log.Exception("Flow.Launcher.Infrastructure.Http", "Unable to parse Uri", e); } } From 70c8ea18fc59fc743142e1b9c53b6c062a89138d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 27 Jan 2025 09:11:27 +0800 Subject: [PATCH 113/259] Fix setting window freeze issue & Improve singleton window opener --- Flow.Launcher/Helper/SingletonWindowOpener.cs | 21 +++++++++++++++---- Flow.Launcher/SettingWindow.xaml.cs | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/Helper/SingletonWindowOpener.cs b/Flow.Launcher/Helper/SingletonWindowOpener.cs index b5c2d8b55..5282b61f9 100644 --- a/Flow.Launcher/Helper/SingletonWindowOpener.cs +++ b/Flow.Launcher/Helper/SingletonWindowOpener.cs @@ -10,16 +10,29 @@ public static class SingletonWindowOpener { var window = Application.Current.Windows.OfType().FirstOrDefault(x => x.GetType() == typeof(T)) ?? (T)Activator.CreateInstance(typeof(T), args); - + // Fix UI bug // Add `window.WindowState = WindowState.Normal` // If only use `window.Show()`, Settings-window doesn't show when minimized in taskbar // Not sure why this works tho // Probably because, when `.Show()` fails, `window.WindowState == Minimized` (not `Normal`) // https://stackoverflow.com/a/59719760/4230390 - window.WindowState = WindowState.Normal; - window.Show(); - + // Ensure the window is not minimized before showing it + if (window.WindowState == WindowState.Minimized) + { + window.WindowState = WindowState.Normal; + } + + // Ensure the window is visible + if (!window.IsVisible) + { + window.Show(); + } + else + { + window.Activate(); // Bring the window to the foreground if already open + } + window.Focus(); return (T)window; diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 4cc125fa4..bdc7675ef 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -35,11 +35,11 @@ public partial class SettingWindow private void OnLoaded(object sender, RoutedEventArgs e) { RefreshMaximizeRestoreButton(); - // Fix (workaround) for the window freezes after lock screen (Win+L) + // Fix (workaround) for the window freezes after lock screen (Win+L) or sleep // https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; HwndTarget hwndTarget = hwndSource.CompositionTarget; - hwndTarget.RenderMode = RenderMode.Default; + hwndTarget.RenderMode = RenderMode.SoftwareOnly; // Must use software only render mode here InitializePosition(); } From f9518c073df83ec24c8c7f979ed4cda87c117449 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Mon, 27 Jan 2025 16:39:07 +1100 Subject: [PATCH 114/259] New Crowdin updates (#3062) * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations resources.resx (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations resources.resx (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations resources.resx (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (Polish) [ci skip] * New translations en.xaml (French) [ci skip] * New translations en.xaml (French) [ci skip] * New translations en.xaml (Russian) [ci skip] * New translations en.xaml (Russian) [ci skip] * New translations en.xaml (Russian) [ci skip] * New translations en.xaml (Russian) [ci skip] * New translations resources.resx (Portuguese) [ci skip] * New translations en.xaml (French) [ci skip] * New translations en.xaml (Arabic) [ci skip] * New translations en.xaml (Czech) [ci skip] * New translations en.xaml (Danish) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (Italian) [ci skip] * New translations en.xaml (Japanese) [ci skip] * New translations en.xaml (Korean) [ci skip] * New translations en.xaml (Dutch) [ci skip] * New translations en.xaml (Polish) [ci skip] * New translations en.xaml (Portuguese) [ci skip] * New translations en.xaml (Russian) [ci skip] * New translations en.xaml (Slovak) [ci skip] * New translations en.xaml (Turkish) [ci skip] * New translations en.xaml (Ukrainian) [ci skip] * New translations en.xaml (Chinese Simplified) [ci skip] * New translations en.xaml (Chinese Traditional) [ci skip] * New translations en.xaml (Vietnamese) [ci skip] * New translations en.xaml (Portuguese, Brazilian) [ci skip] * New translations en.xaml (Norwegian Bokmal) [ci skip] * New translations en.xaml (Serbian (Latin)) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Spanish, Latin America) [ci skip] * New translations en.xaml (Slovak) [ci skip] * New translations en.xaml (French) [ci skip] * New translations en.xaml (Portuguese) [ci skip] * New translations en.xaml (Dutch) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations resources.resx (Hebrew) [ci skip] * New translations resources.resx (Hebrew) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations resources.resx (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations resources.resx (Hebrew) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Hebrew) [ci skip] * New translations en.xaml (French) [ci skip] * New translations en.xaml (Arabic) [ci skip] * New translations en.xaml (Czech) [ci skip] * New translations en.xaml (Danish) [ci skip] * New translations en.xaml (German) [ci skip] * New translations en.xaml (Italian) [ci skip] * New translations en.xaml (Japanese) [ci skip] * New translations en.xaml (Korean) [ci skip] * New translations en.xaml (Dutch) [ci skip] * New translations en.xaml (Polish) [ci skip] * New translations en.xaml (Portuguese) [ci skip] * New translations en.xaml (Russian) [ci skip] * New translations en.xaml (Slovak) [ci skip] * New translations en.xaml (Turkish) [ci skip] * New translations en.xaml (Ukrainian) [ci skip] * New translations en.xaml (Chinese Simplified) [ci skip] * New translations en.xaml (Chinese Traditional) [ci skip] * New translations en.xaml (Vietnamese) [ci skip] * New translations en.xaml (Portuguese, Brazilian) [ci skip] * New translations en.xaml (Norwegian Bokmal) [ci skip] * New translations en.xaml (Serbian (Latin)) [ci skip] * New translations en.xaml (Spanish, Latin America) [ci skip] * New translations en.xaml (Slovak) [ci skip] * New translations en.xaml (French) [ci skip] * New translations en.xaml (Spanish (Modern)) [ci skip] * New translations en.xaml (Portuguese) [ci skip] --------- Co-authored-by: Kevin Zhang <45326534+taooceros@users.noreply.github.com> --- Flow.Launcher/Languages/ar.xaml | 2 + Flow.Launcher/Languages/cs.xaml | 2 + Flow.Launcher/Languages/da.xaml | 2 + Flow.Launcher/Languages/de.xaml | 18 +- Flow.Launcher/Languages/es-419.xaml | 2 + Flow.Launcher/Languages/es.xaml | 6 +- Flow.Launcher/Languages/fr.xaml | 2 + Flow.Launcher/Languages/he.xaml | 458 +++ Flow.Launcher/Languages/it.xaml | 2 + Flow.Launcher/Languages/ja.xaml | 2 + Flow.Launcher/Languages/ko.xaml | 2 + Flow.Launcher/Languages/nb.xaml | 2 + Flow.Launcher/Languages/nl.xaml | 2 + Flow.Launcher/Languages/pl.xaml | 4 +- Flow.Launcher/Languages/pt-br.xaml | 2 + Flow.Launcher/Languages/pt-pt.xaml | 2 + Flow.Launcher/Languages/ru.xaml | 11 +- Flow.Launcher/Languages/sk.xaml | 3 +- Flow.Launcher/Languages/sr.xaml | 2 + Flow.Launcher/Languages/tr.xaml | 2 + Flow.Launcher/Languages/uk-UA.xaml | 2 + Flow.Launcher/Languages/vi.xaml | 2 + Flow.Launcher/Languages/zh-cn.xaml | 2 + Flow.Launcher/Languages/zh-tw.xaml | 2 + Flow.Launcher/Properties/Resources.he-IL.resx | 130 + .../Languages/de.xaml | 2 +- .../Languages/es.xaml | 2 +- .../Languages/he.xaml | 28 + .../Languages/de.xaml | 4 +- .../Languages/he.xaml | 15 + .../Languages/de.xaml | 22 +- .../Languages/he.xaml | 165 ++ .../Languages/ru.xaml | 10 +- .../Languages/de.xaml | 4 +- .../Languages/he.xaml | 9 + .../Languages/he.xaml | 63 + .../Languages/de.xaml | 10 +- .../Languages/he.xaml | 11 + .../Languages/de.xaml | 2 +- .../Languages/fr.xaml | 2 +- .../Languages/he.xaml | 95 + .../Languages/he.xaml | 17 + .../Languages/ru.xaml | 2 +- .../Languages/es.xaml | 2 +- .../Languages/he.xaml | 63 + .../Languages/de.xaml | 10 +- .../Languages/he.xaml | 17 + .../Languages/ar.xaml | 3 +- .../Languages/cs.xaml | 3 +- .../Languages/da.xaml | 3 +- .../Languages/de.xaml | 23 +- .../Languages/es-419.xaml | 3 +- .../Languages/es.xaml | 3 +- .../Languages/fr.xaml | 5 +- .../Languages/he.xaml | 52 + .../Languages/it.xaml | 3 +- .../Languages/ja.xaml | 3 +- .../Languages/ko.xaml | 3 +- .../Languages/nb.xaml | 3 +- .../Languages/nl.xaml | 3 +- .../Languages/pl.xaml | 3 +- .../Languages/pt-br.xaml | 3 +- .../Languages/pt-pt.xaml | 3 +- .../Languages/ru.xaml | 5 +- .../Languages/sk.xaml | 3 +- .../Languages/sr.xaml | 3 +- .../Languages/tr.xaml | 3 +- .../Languages/uk-UA.xaml | 3 +- .../Languages/vi.xaml | 3 +- .../Languages/zh-cn.xaml | 3 +- .../Languages/zh-tw.xaml | 3 +- .../Properties/Resources.de-DE.resx | 40 +- .../Properties/Resources.he-IL.resx | 2514 +++++++++++++++++ .../Properties/Resources.pt-PT.resx | 44 +- 74 files changed, 3835 insertions(+), 129 deletions(-) create mode 100644 Flow.Launcher/Languages/he.xaml create mode 100644 Flow.Launcher/Properties/Resources.he-IL.resx create mode 100644 Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.Program/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.Shell/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.Url/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.he-IL.resx diff --git a/Flow.Launcher/Languages/ar.xaml b/Flow.Launcher/Languages/ar.xaml index b096e7489..fa5c968d4 100644 --- a/Flow.Launcher/Languages/ar.xaml +++ b/Flow.Launcher/Languages/ar.xaml @@ -65,6 +65,8 @@ حفظ الاستعلام الأخير اختيار الاستعلام الأخير تفريغ الاستعلام الأخير + Preserve Last Action Keyword + Select Last Action Keyword ارتفاع ثابت للنافذة ارتفاع النافذة غير قابل للتعديل عن طريق السحب. الحد الأقصى للنتائج المعروضة diff --git a/Flow.Launcher/Languages/cs.xaml b/Flow.Launcher/Languages/cs.xaml index 8bc572c11..05adf095b 100644 --- a/Flow.Launcher/Languages/cs.xaml +++ b/Flow.Launcher/Languages/cs.xaml @@ -65,6 +65,8 @@ Zachovat poslední dotaz Vybrat poslední dotaz Smazat poslední dotaz + Preserve Last Action Keyword + Select Last Action Keyword Fixed Window Height The window height is not adjustable by dragging. Počet zobrazených výsledků diff --git a/Flow.Launcher/Languages/da.xaml b/Flow.Launcher/Languages/da.xaml index f8e3ea4a5..36970ad53 100644 --- a/Flow.Launcher/Languages/da.xaml +++ b/Flow.Launcher/Languages/da.xaml @@ -65,6 +65,8 @@ Preserve Last Query Select last Query Empty last Query + Preserve Last Action Keyword + Select Last Action Keyword Fixed Window Height The window height is not adjustable by dragging. Maksimum antal resultater vist diff --git a/Flow.Launcher/Languages/de.xaml b/Flow.Launcher/Languages/de.xaml index 600d96e25..7f2e2bd8d 100644 --- a/Flow.Launcher/Languages/de.xaml +++ b/Flow.Launcher/Languages/de.xaml @@ -65,6 +65,8 @@ Letzte Abfrage beibehalten Letzte Abfrage auswählen Letzte Abfrage leeren + Preserve Last Action Keyword + Select Last Action Keyword Feste Fensterhöhe Die Fensterhöhe ist durch Ziehen nicht anpassbar. Maximal gezeigte Ergebnisse @@ -77,7 +79,7 @@ Einstellung für Neuer Tab, Neues Fenster, Privater Modus. Python-Pfad Node.js-Pfad - Bitte wählen Sie das Programm Node.js aus + Bitte wählen Sie die ausführbare Datei Node.js aus Bitte wählen Sie pythonw.exe aus Tippen immer im englischen Modus starten Ändern Sie Ihre Eingabemethode temporär in den englischen Modus, wenn Sie Flow aktivieren. @@ -166,8 +168,8 @@ Individuell anpassen Fenstermodus Opazität - Theme {0} ist nicht vorhanden, Fallback auf Standard-Theme - Theme {0} konnte nicht geladen werden, Fallback auf Standard-Theme + Theme {0} ist nicht vorhanden, Fallback auf Default-Theme + Theme {0} konnte nicht geladen werden, Fallback auf Default-Theme Theme-Ordner Theme-Ordner öffnen Farbschema @@ -175,7 +177,7 @@ Hell Dunkel Soundeffekt - Einen kleinen Sound abspielen, wenn das Suchfenster geöffnet wird + Einen kurzen Sound abspielen, wenn das Suchfenster geöffnet wird Lautstärke der Soundeffekte Lautstärke des Soundeffekts anpassen Windows Media Player ist nicht verfügbar und ist für die Lautstärkeregelung von Flow erforderlich. Bitte überprüfen Sie Ihre Installation, wenn Sie die Lautstärke anpassen müssen. @@ -287,8 +289,8 @@ Versionshinweise Tipps zur Nutzung DevTools - Ordner Einstellungen - Ordner Logs + Ordner »Settings« + Ordner »Logs« Logs löschen Sind Sie sicher, dass Sie alle Logs löschen wollen? Assistent @@ -411,8 +413,8 @@ Wenn Sie bei der Eingabe eines Shortcuts ein '@'-Präfix hinzufügen, stimmt die Willkommen bei Flow Launcher Hallo, dies ist das erste Mal, dass Sie Flow Launcher ausführen! Bevor Sie beginnen, hilft dieser Assistent bei der Einrichtung von Flow Launcher. Sie können dies überspringen, wenn Sie möchten. Bitte wählen Sie eine Sprache - Suchen und führen Sie alle Dateien und Anwendungen auf Ihrem PC aus - Suchen Sie alles in Anwendungen, Dateien, Lesezeichen, YouTube, Twitter und vielem mehr. Alles bequem über Ihre Tastatur, ohne die Maus zu berühren. + Alle Dateien und Anwendungen auf Ihrem PC suchen und ausführen + Durchsuchen Sie alles von Anwendungen, Dateien, Lesezeichen, YouTube, Twitter und vielem mehr. Alles bequem über Ihre Tastatur, ohne die Maus zu berühren. Flow Launcher startet mit dem unten stehenden Hotkey, probieren Sie ihn gleich aus. Um ihn zu ändern, klicken Sie auf die Eingabe und drücken Sie den gewünschten Hotkey auf der Tastatur. Hotkeys Aktions-Schlüsselwort und Befehle diff --git a/Flow.Launcher/Languages/es-419.xaml b/Flow.Launcher/Languages/es-419.xaml index 9a682269c..0556c59ae 100644 --- a/Flow.Launcher/Languages/es-419.xaml +++ b/Flow.Launcher/Languages/es-419.xaml @@ -65,6 +65,8 @@ Conservar última consulta Seleccionar última consulta Borrar última consulta + Preserve Last Action Keyword + Select Last Action Keyword Fixed Window Height The window height is not adjustable by dragging. Máximo de resultados mostrados diff --git a/Flow.Launcher/Languages/es.xaml b/Flow.Launcher/Languages/es.xaml index 328d98d41..bf22aea48 100644 --- a/Flow.Launcher/Languages/es.xaml +++ b/Flow.Launcher/Languages/es.xaml @@ -65,6 +65,8 @@ Mantener la última consulta Seleccionar la última consulta Limpiar la última consulta + Conservar palabra clave de última acción + Seleccionar palabra clave de última acción Altura de la ventana fija La altura de la ventana no se puede ajustar arrastrando el ratón. Número máximo de resultados mostrados @@ -218,7 +220,7 @@ Abrir menú contextual nativo Abrir ventana de configuración Copiar ruta del archivo - Cambia a Modo Juego + Cambiar a Modo Juego Cambiar historial Abrir carpeta contenedora Ejecutar como administrador @@ -293,7 +295,7 @@ ¿Está seguro de que desea eliminar todos los registros? Asistente Ubicación de datos del usuario - La configuración del usuario y los complementos instalados se guardan en la carpeta de datos del usuario. Esta ubicación puede variar dependiendo de si está en modo portátil o no. + La configuración del usuario y los complementos instalados se guardan en la carpeta de datos del usuario. Esta ubicación puede variar dependiendo de si está en modo portable o no. Abrir carpeta diff --git a/Flow.Launcher/Languages/fr.xaml b/Flow.Launcher/Languages/fr.xaml index b171dcc9e..e978e91ec 100644 --- a/Flow.Launcher/Languages/fr.xaml +++ b/Flow.Launcher/Languages/fr.xaml @@ -65,6 +65,8 @@ Conserver la dernière recherche Sélectionner la dernière recherche Ne pas afficher la dernière recherche + Conserver le mot clé de la dernière action + Sélectionnez le mot clé de la dernière action Hauteur de fenêtre fixe La hauteur de la fenêtre n'est pas réglable par glissement. Résultats maximums à afficher diff --git a/Flow.Launcher/Languages/he.xaml b/Flow.Launcher/Languages/he.xaml new file mode 100644 index 000000000..eeb33da17 --- /dev/null +++ b/Flow.Launcher/Languages/he.xaml @@ -0,0 +1,458 @@ + + + + + Flow detected you have installed {0} plugins, which will require {1} to run. Would you like to download {1}? + {2}{2} + Click no if it's already installed, and you will be prompted to select the folder that contains the {1} executable + + אנא בחר את קובץ ההפעלה {0} + לא ניתן להגדיר נתיב הפעלה {0}, אנא נסה שוב בהגדרות Flow (גלול עד למטה). + נכשל בהפעלת תוספים + תוספים: {0} - נכשלים בטעינה ויהיו מושבתים, אנא צור קשר עם יוצרי התוספים לקבלת עזרה + + + רישום מקש הקיצור "{0}" נכשל. ייתכן שמקש הקיצור נמצא בשימוש על ידי תוכנה אחרת. שנה למקש קיצור אחר, או צא מהתוכנה האחרת. + Flow Launcher + לא ניתן היה להפעיל את {0} + פורמט קובץ תוסף Flow Launcher לא חוקי + הגדר כגבוה ביותר בשאילתה זו + בטל העלאה בשאילתה זו + בצע שאילתה: {0} + Last execution time: {0} + פתח + הגדרות + אודות + יציאה + סגור + העתק + גזור + הדבק + Undo + בחר הכל + קובץ + תיקייה + טקסט + מצב משחק + השהה את השימוש במקשי קיצור. + Position Reset + Reset search window position + + + הגדרות + כללי + מצב נייד + אחסן את כל ההגדרות ונתוני המשתמש בתיקייה אחת (שימושי בשימוש עם כוננים נשלפים או שירותי ענן). + הפעל את Flow Launcher בעת הפעלת Window + שגיאה בהגדרת ההפעלה בעת הפעלת windows + הסתר את Flow Launcher כאשר הוא אינו החלון הפעיל + אל תציג התראות על גרסה חדשה + מיקום חלון החיפוש + זכור את המיקום האחרון + Monitor with Mouse Cursor + Monitor with Focused Window + צג ראשי + צג מותאם אישית + Search Window Position on Monitor + Center + Center Top + Left Top + Right Top + Custom Position + שפה + Last Query Style + Show/Hide previous results when Flow Launcher is reactivated. + Preserve Last Query + Select last Query + Empty last Query + Preserve Last Action Keyword + Select Last Action Keyword + Fixed Window Height + The window height is not adjustable by dragging. + Maximum results shown + You can also quickly adjust this by using CTRL+Plus and CTRL+Minus. + Ignore hotkeys in fullscreen mode + Disable Flow Launcher activation when a full screen application is active (Recommended for games). + Default File Manager + Select the file manager to use when opening the folder. + Default Web Browser + Setting for New Tab, New Window, Private Mode. + Python Path + Node.js Path + Please select the Node.js executable + Please select pythonw.exe + Always Start Typing in English Mode + Temporarily change your input method to English mode when activating Flow. + Auto Update + Select + Hide Flow Launcher on startup + Flow Launcher search window is hidden in the tray after starting up. + Hide tray icon + When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window. + Query Search Precision + Changes minimum match score required for results. + None + Low + Regular + Search with Pinyin + Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese. + Always Preview + Always open preview panel when Flow activates. Press {0} to toggle preview. + Shadow effect is not allowed while current theme has blur effect enabled + + + Search Plugin + Ctrl+F to search plugins + No results found + Please try a different search. + Plugin + תוספים + מצא תוספים נוספים + On + Off + Action keyword Setting + Action keyword + Current action keyword + New action keyword + Change Action Keywords + Current Priority + New Priority + Priority + Change Plugin Results Priority + Plugin Directory + by + Init time: + Query time: + Version + Website + Uninstall + + + + חנות תוספים + New Release + Recently Updated + תוספים + Installed + רענן + התקן + Uninstall + עדכון + Plugin already installed + New Version + This plugin has been updated within the last 7 days + New Update is Available + + + + + ערכת נושא + Appearance + גלריית ערכות נושא + How to create a theme + Hi There + Explorer + Search for files, folders and file contents + WebSearch + Search the web with different search engine support + Program + Launch programs as admin or a different user + ProcessKiller + Terminate unwanted processes + Search Bar Height + Item Height + Query Box Font + Result Title Font + Result Subtitle Font + Reset + Customize + Window Mode + Opacity + Theme {0} not exists, fallback to default theme + Fail to load theme {0}, fallback to default theme + Theme Folder + Open Theme Folder + Color Scheme + System Default + בהיר + כהה + Sound Effect + Play a small sound when the search window opens + Sound Effect Volume + Adjust the volume of the sound effect + Windows Media Player is unavailable and is required for Flow's volume adjustment. Please check your installation if you need to adjust volume. + Animation + Use Animation in UI + Animation Speed + The speed of the UI animation + Slow + Medium + Fast + Custom + Clock + Date + This theme supports two(light/dark) modes. + This theme supports Blur Transparent Background. + + + + Hotkey + Hotkeys + Open Flow Launcher + Enter shortcut to show/hide Flow Launcher. + Toggle Preview + Enter shortcut to show/hide preview in search window. + Hotkey Presets + List of currently registered hotkeys + Open Result Modifier Key + Select a modifier key to open selected result via keyboard. + Show Hotkey + Show result selection hotkey with results. + Auto Complete + Runs autocomplete for the selected items. + Select Next Item + Select Previous Item + Next Page + Previous Page + Cycle Previous Query + Cycle Next Query + Open Context Menu + Open Native Context Menu + Open Setting Window + Copy File Path + Toggle Game Mode + Toggle History + Open Containing Folder + Run As Admin + Refresh Search Results + Reload Plugins Data + Quick Adjust Window Width + Quick Adjust Window Height + Use when require plugins to reload and update their existing data. + You can add one more hotkey for this function. + Custom Query Hotkeys + Custom Query Shortcuts + Built-in Shortcuts + שאילתה + Shortcut + Expansion + Description + מחק + ערוך + הוסף + None + אנא בחר פריט + Are you sure you want to delete {0} plugin hotkey? + Are you sure you want to delete shortcut: {0} with expansion {1}? + Get text from clipboard. + Get path from active explorer. + Query window shadow effect + Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited. + Window Width Size + You can also quickly adjust this by using Ctrl+[ and Ctrl+]. + Use Segoe Fluent Icons + Use Segoe Fluent Icons for query results where supported + Press Key + + + HTTP Proxy + Enable HTTP Proxy + HTTP Server + Port + User Name + Password + Test Proxy + שמור + Server field can't be empty + Port field can't be empty + Invalid port format + Proxy configuration saved successfully + Proxy configured correctly + Proxy connection failed + + + אודות + Website + GitHub + Docs + Version + Icons + You have activated Flow Launcher {0} times + Check for Updates + Become A Sponsor + New version {0} is available, would you like to restart Flow Launcher to use the update? + בדיקת העדכונים נכשלה, אנא בדוק את הגדרות החיבור ואת הגדרות ה-Proxy שלך לכתובת api.github.com. + + Download updates failed, please check your connection and proxy settings to github-cloud.s3.amazonaws.com, + or go to https://github.com/Flow-Launcher/Flow.Launcher/releases to download updates manually. + + Release Notes + Usage Tips + DevTools + Setting Folder + Log Folder + Clear Logs + Are you sure you want to delete all logs? + אשף + User Data Location + User settings and installed plugins are saved in the user data folder. This location may vary depending on whether it's in portable mode or not. + Open Folder + + + Select File Manager + Please specify the file location of the file manager you using and add arguments as required. The "%d" represents the directory path to open for, used by the Arg for Folder field and for commands opening specific directories. The "%f" represents the file path to open for, used by the Arg for File field and for commands opening specific files. + For example, if the file manager uses a command such as "totalcmd.exe /A c:\windows" to open the c:\windows directory, the File Manager Path will be totalcmd.exe, and the Arg For Folder will be /A "%d". Certain file managers like QTTabBar may just require a path to be supplied, in this instance use "%d" as the File Manager Path and leave the rest of the fileds blank. + File Manager + Profile Name + File Manager Path + Arg For Folder + Arg For File + + + Default Web Browser + The default setting follows the OS default browser setting. If specified separately, flow uses that browser. + Browser + Browser Name + Browser Path + New Window + New Tab + Private Mode + + + Change Priority + Greater the number, the higher the result will be ranked. Try setting it as 5. If you want the results to be lower than any other plugin's, provide a negative number + Please provide an valid integer for Priority! + + + Old Action Keyword + New Action Keyword + ביטול + בוצע + Can't find specified plugin + New Action Keyword can't be empty + This new Action Keyword is already assigned to another plugin, please choose a different one + הצליח + הושלם בהצלחה + 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 + Press a custom hotkey to open Flow Launcher and input the specified query automatically. + תצוגה מקדימה + Hotkey is unavailable, please select a new hotkey + Invalid plugin hotkey + עדכון + Binding Hotkey + Current hotkey is unavailable. + This hotkey is reserved for "{0}" and can't be used. Please choose another hotkey. + This hotkey is already in use by "{0}". If you press "Overwrite", it will be removed from "{0}". + Press the keys you want to use for this function. + + + Custom Query Shortcut + Enter a shortcut that automatically expands to the specified query. + A shortcut is expanded when it exactly matches the query. + +If you add an '@' prefix while inputting a shortcut, it matches any position in the query. Builtin shortcuts match any position in a query. + + Shortcut already exists, please enter a new Shortcut or edit the existing one. + Shortcut and/or its expansion is empty. + + + שמור + Overwrite + ביטול + Reset + מחק + OK + Yes + No + + + Version + זמן + Please tell us how application crashed so we can fix it + שלח דיווח + ביטול + כללי + חריגים + Exception Type + Source + Stack Trace + Sending + Report sent successfully + Failed to send report + Flow Launcher got an error + + + Please wait... + + + Checking for new update + You already have the latest Flow Launcher version + Update found + Updating... + + Flow Launcher was not able to move your user profile data to the new update version. + Please manually move your profile data folder from {0} to {1} + + עדכון חדש + New Flow Launcher release {0} is now available + An error occurred while trying to install software updates + עדכון + ביטול + העדכון נכשל + Check your connection and try updating proxy settings to github-cloud.s3.amazonaws.com. + This upgrade will restart Flow Launcher + Following files will be updated + Update files + Update description + + + דלג + Welcome to Flow Launcher + Hello, this is the first time you are running Flow Launcher! + Before starting, this wizard will assist in setting up Flow Launcher. You can skip this if you wish. Please choose a language + Search and run all files and applications on your PC + Search everything from applications, files, bookmarks, YouTube, Twitter and more. All from the comfort of your keyboard without ever touching the mouse. + Flow Launcher starts with the hotkey below, go ahead and try it out now. To change it, click on the input and press the desired hotkey on the keyboard. + Hotkeys + Action Keyword and Commands + Search the web, launch applications or run various functions through Flow Launcher plugins. Certain functions start with an action keyword, and if necessary, they can be used without action keywords. Try the queries below in Flow Launcher. + Let's Start Flow Launcher + Finished. Enjoy Flow Launcher. Don't forget the hotkey to start :) + + + + Back / Context Menu + Item Navigation + Open Context Menu + Open Containing Folder + Run as Admin / Open Folder in Default File Manager + Query History + Back to Result in Context Menu + Autocomplete + Open / Run Selected Item + Open Setting Window + Reload Plugin Data + + Select first result + Select last result + Run current query again + Open result + Open result #{0} + + Weather + Weather in Google Result + > ping 8.8.8.8 + Shell Command + s Bluetooth + Bluetooth in Windows Settings + sn + Sticky Notes + + + File Size + Created + Last Modified + diff --git a/Flow.Launcher/Languages/it.xaml b/Flow.Launcher/Languages/it.xaml index ddb1d5555..372f4630e 100644 --- a/Flow.Launcher/Languages/it.xaml +++ b/Flow.Launcher/Languages/it.xaml @@ -65,6 +65,8 @@ Conserva ultima ricerca Seleziona ultima ricerca Cancella ultima ricerca + Preserve Last Action Keyword + Select Last Action Keyword Altezza Finestra Fissa L'altezza della finestra non si può regolare trascinando. Numero massimo di risultati mostrati diff --git a/Flow.Launcher/Languages/ja.xaml b/Flow.Launcher/Languages/ja.xaml index 962b68017..e7671367a 100644 --- a/Flow.Launcher/Languages/ja.xaml +++ b/Flow.Launcher/Languages/ja.xaml @@ -65,6 +65,8 @@ 前回のクエリを保存 前回のクエリを選択 前回のクエリを消去 + Preserve Last Action Keyword + Select Last Action Keyword Fixed Window Height The window height is not adjustable by dragging. 結果の最大表示件数 diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml index 81dae9179..67bf2490a 100644 --- a/Flow.Launcher/Languages/ko.xaml +++ b/Flow.Launcher/Languages/ko.xaml @@ -65,6 +65,8 @@ 직전 쿼리에 계속 입력 직전 쿼리 내용 선택 직전 쿼리 지우기 + Preserve Last Action Keyword + Select Last Action Keyword 창 높이 고정 드래그로 창 높이를 조정하지 않습니다. 표시할 결과 수 diff --git a/Flow.Launcher/Languages/nb.xaml b/Flow.Launcher/Languages/nb.xaml index b608f5c0b..e3b8e36da 100644 --- a/Flow.Launcher/Languages/nb.xaml +++ b/Flow.Launcher/Languages/nb.xaml @@ -65,6 +65,8 @@ Bevar siste spørring Velg siste spørring Tøm siste spørring + Preserve Last Action Keyword + Select Last Action Keyword Fast vindushøyde Vindushøyden kan ikke justeres ved å dra. Maksimalt antall resultater vist diff --git a/Flow.Launcher/Languages/nl.xaml b/Flow.Launcher/Languages/nl.xaml index d5bd0f284..db440c3a0 100644 --- a/Flow.Launcher/Languages/nl.xaml +++ b/Flow.Launcher/Languages/nl.xaml @@ -65,6 +65,8 @@ Behoud laatste zoekopdracht Selecteer laatste zoekopdracht Laatste zoekopdracht verwijderen + Preserve Last Action Keyword + Select Last Action Keyword Vaste venster hoogte De vensterhoogte is niet aanpasbaar door te slepen. Laat maximale resultaten zien diff --git a/Flow.Launcher/Languages/pl.xaml b/Flow.Launcher/Languages/pl.xaml index 7aa0d64b2..df7c9d2d4 100644 --- a/Flow.Launcher/Languages/pl.xaml +++ b/Flow.Launcher/Languages/pl.xaml @@ -65,6 +65,8 @@ Kliknij "nie", jeśli jest już zainstalowany. Zostaniesz wtedy popros Zachowaj ostatnie zapytanie Wybierz ostatnie zapytanie Puste ostatnie zapytanie + Preserve Last Action Keyword + Select Last Action Keyword Stała wysokość okna Wysokość okna nie jest regulowana poprzez przeciąganie. Maksymalna liczba wyników @@ -361,7 +363,7 @@ Jeśli dodasz prefiks '@' podczas wprowadzania skrótu, będzie on pasował do d Nadpisz Anuluj Zresetuj - Usu + Usuń Aktualizuj Tak Nie diff --git a/Flow.Launcher/Languages/pt-br.xaml b/Flow.Launcher/Languages/pt-br.xaml index 6f6bb4df8..4a30ffda4 100644 --- a/Flow.Launcher/Languages/pt-br.xaml +++ b/Flow.Launcher/Languages/pt-br.xaml @@ -65,6 +65,8 @@ Preservar Última Consulta Selecionar última consulta Limpar última consulta + Preserve Last Action Keyword + Select Last Action Keyword Fixed Window Height The window height is not adjustable by dragging. Máximo de resultados mostrados diff --git a/Flow.Launcher/Languages/pt-pt.xaml b/Flow.Launcher/Languages/pt-pt.xaml index 9f316220d..470bf2b4e 100644 --- a/Flow.Launcher/Languages/pt-pt.xaml +++ b/Flow.Launcher/Languages/pt-pt.xaml @@ -65,6 +65,8 @@ Clique "Não" se já tiver instalado e, de seguida, ser-lhe-á solicit Manter última consulta Selecionar última consulta Limpar última consulta + Manter palavra-chave da última ação + Selecionar palavra-chave da última ação Altura fixa de janela Não é possível ajustar o tamanho da janela por arrasto. Número máximo de resultados diff --git a/Flow.Launcher/Languages/ru.xaml b/Flow.Launcher/Languages/ru.xaml index f501fd638..1c420100f 100644 --- a/Flow.Launcher/Languages/ru.xaml +++ b/Flow.Launcher/Languages/ru.xaml @@ -1,12 +1,13 @@ + - Flow определил, что вы установили {0} плагины, которым требуется {1} для работы. Скачать {1}? + Flow detected you have installed {0} plugins, which will require {1} to run. Would you like to download {1}? {2}{2} - Кликните нет, если он уже установлен, и вам будет предложено выбрать папку, где находится исполняемый файл {1} + Click no if it's already installed, and you will be prompted to select the folder that contains the {1} executable - Пожалуйста, выберите исполняемый файл {0} - Не удалось установить путь к исполняемому файлу {0}, пожалуйста, попробуйте через настройки Flow (прокрутите вниз). + Please select the {0} executable + Unable to set {0} executable path, please try from Flow's settings (scroll down to the bottom). Fail to Init Plugins Plugins: {0} - fail to load and would be disabled, please contact plugin creator for help @@ -64,6 +65,8 @@ Сохранение последнего запроса Выбор последнего запроса Очистить последний запрос + Preserve Last Action Keyword + Select Last Action Keyword Фиксированная высота окна The window height is not adjustable by dragging. Максимальное количество результатов diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml index f91fd596d..3db778cc8 100644 --- a/Flow.Launcher/Languages/sk.xaml +++ b/Flow.Launcher/Languages/sk.xaml @@ -65,6 +65,8 @@ Ponechať Označiť Vymazať + Ponechať posledný akčný príkaz + Označiť posledný akčný príkaz Pevná výška okna Výška okna sa nedá nastaviť ťahaním. Maximum výsledkov @@ -454,4 +456,3 @@ Ak pri zadávaní skratky pred ňu pridáte "@", bude sa zhodovať s Vytvorené Upravené - diff --git a/Flow.Launcher/Languages/sr.xaml b/Flow.Launcher/Languages/sr.xaml index af32a5cfe..fc5a1e2fc 100644 --- a/Flow.Launcher/Languages/sr.xaml +++ b/Flow.Launcher/Languages/sr.xaml @@ -65,6 +65,8 @@ Sačuvaj poslednji Upit Selektuj poslednji Upit Isprazni poslednji Upit + Preserve Last Action Keyword + Select Last Action Keyword Fixed Window Height The window height is not adjustable by dragging. Maksimum prikazanih rezultata diff --git a/Flow.Launcher/Languages/tr.xaml b/Flow.Launcher/Languages/tr.xaml index ecca292d9..cfb3689c3 100644 --- a/Flow.Launcher/Languages/tr.xaml +++ b/Flow.Launcher/Languages/tr.xaml @@ -65,6 +65,8 @@ Son Sorguyu Sakla Son Sorguyu Sakla ve Tümünü Seç Sorgu Kutusunu Temizle + Preserve Last Action Keyword + Select Last Action Keyword Sabit Pencere Yükseliği Pencere yüksekliği sürükleme ile ayarlanamaz. Maksimum Sonuç Sayısı diff --git a/Flow.Launcher/Languages/uk-UA.xaml b/Flow.Launcher/Languages/uk-UA.xaml index f74efa48b..09c576150 100644 --- a/Flow.Launcher/Languages/uk-UA.xaml +++ b/Flow.Launcher/Languages/uk-UA.xaml @@ -65,6 +65,8 @@ Зберегти останній запит Вибрати останній запит Очистити останній запит + Preserve Last Action Keyword + Select Last Action Keyword Фіксована висота вікна Висота вікна не регулюється перетягуванням. Максимальна кількість результатів diff --git a/Flow.Launcher/Languages/vi.xaml b/Flow.Launcher/Languages/vi.xaml index 802d4b06c..31e8ad2aa 100644 --- a/Flow.Launcher/Languages/vi.xaml +++ b/Flow.Launcher/Languages/vi.xaml @@ -65,6 +65,8 @@ Giữ lại truy vấn cuối cùng Chọn truy vấn cuối cùng Trống truy vấn cuối cùng + Preserve Last Action Keyword + Select Last Action Keyword Giữ nguyên chiều cao cửa sổ Chiều cao cửa sổ không thể thay đổi bằng cách kéo. Số kết quả tối đa diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml index 3a8217f59..681c715fb 100644 --- a/Flow.Launcher/Languages/zh-cn.xaml +++ b/Flow.Launcher/Languages/zh-cn.xaml @@ -65,6 +65,8 @@ 保留上次搜索关键字 选择上次搜索关键字 清空上次搜索关键字 + Preserve Last Action Keyword + Select Last Action Keyword 固定窗口高度 窗口高度不能通过拖动来调整。 最大结果显示个数 diff --git a/Flow.Launcher/Languages/zh-tw.xaml b/Flow.Launcher/Languages/zh-tw.xaml index 3cdf0a7b4..44be5257b 100644 --- a/Flow.Launcher/Languages/zh-tw.xaml +++ b/Flow.Launcher/Languages/zh-tw.xaml @@ -65,6 +65,8 @@ 保留上一個查詢 選擇上一個查詢 清空上次搜尋關鍵字 + Preserve Last Action Keyword + Select Last Action Keyword Fixed Window Height The window height is not adjustable by dragging. 最大結果顯示個數 diff --git a/Flow.Launcher/Properties/Resources.he-IL.resx b/Flow.Launcher/Properties/Resources.he-IL.resx new file mode 100644 index 000000000..ca0f66f53 --- /dev/null +++ b/Flow.Launcher/Properties/Resources.he-IL.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.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\dev.ico;System.Drawing.Icon, System.Drawing, Version=4.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/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml index c5d371c6c..4d1ad4bf1 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml @@ -16,7 +16,7 @@ URL des Lesezeichens in Zwischenablage kopieren Browser laden aus: Browser-Name - URL des Lesezeichens in Zwischenablage kopieren + Pfad zu Datenverzeichnis Hinzufügen Bearbeiten Löschen diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml index b80e4f926..db87ee281 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml @@ -23,6 +23,6 @@ Navegar Otros Motor del navegador - Si no está utilizando Chrome, Firefox o Edge, o si está utilizando su versión portátil, debe añadir el directorio de datos de los marcadores y seleccionar el motor del navegador correcto para que este complemento funcione. + Si no está utilizando Chrome, Firefox o Edge, o si está utilizando su versión portable, debe añadir el directorio de datos de los marcadores y seleccionar el motor del navegador correcto para que este complemento funcione. Por ejemplo: El motor de Brave es Chromium; y la ubicación por defecto de los datos de los marcadores es: "%LOCALAPPDATA%\BraveSoftware\Brave-Browser\UserData". Para el motor de Firefox, el directorio de los marcadores es la carpeta de datos del usuario que contiene el archivo places.sqlite. diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/he.xaml new file mode 100644 index 000000000..7c6f73ed7 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/he.xaml @@ -0,0 +1,28 @@ + + + + + Browser Bookmarks + Search your browser bookmarks + + + Bookmark Data + Open bookmarks in: + New window + New tab + Set browser from path: + Choose + Copy url + Copy the bookmark's url to clipboard + Load Browser From: + Browser Name + Data Directory Path + הוסף + ערוך + מחק + Browse + Others + Browser Engine + If you are not using Chrome, Firefox or Edge, or you are using their portable version, you need to add bookmarks data directory and select correct browser engine to make this plugin work. + For example: Brave's engine is Chromium; and its default bookmarks data location is: "%LOCALAPPDATA%\BraveSoftware\Brave-Browser\UserData". For Firefox engine, the bookmarks directory is the userdata folder contains the places.sqlite file. + diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml index 47bcaacc9..d8da714dc 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml @@ -2,8 +2,8 @@ Rechner - Ermöglicht mathematische Berechnungen (z. B. 5*3-2 in Flow Launcher) - Nicht eine Zahl (NaN) + Ermöglicht mathematische Berechnungen. (Versuchen Sie 5*3-2 in Flow Launcher) + Nicht eine Zahl (NaN) Ausdruck falsch oder unvollständig (Haben Sie einige Klammern vergessen?) Diese Zahl in die Zwischenablage kopieren Dezimaltrennzeichen diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml new file mode 100644 index 000000000..15598118c --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml @@ -0,0 +1,15 @@ + + + + Calculator + Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) + Not a number (NaN) + Expression wrong or incomplete (Did you forget some parentheses?) + Copy this number to the clipboard + Decimal separator + The decimal separator to be used in the output. + Use system locale + Comma (,) + Dot (.) + Max. decimal places + diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml index e3862df76..f2df655c7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml @@ -2,7 +2,7 @@ - Bitte treffen Sie zuerst eine Auswahl. + Bitte treffen Sie zuerst eine Auswahl Bitte wählen Sie einen Ordner-Link aus Sind Sie sicher, dass Sie {0} löschen wollen? Sind Sie sicher, dass Sie diese Datei dauerhaft löschen möchten? @@ -40,8 +40,8 @@ Shell-Pfad Indexsuche ausgeschlossene Pfade Ort des Suchergebnisses als Arbeitsverzeichnis der ausführbaren Datei verwenden - Drücken Sie die Enter, um den Ordner im Default-Dateimanager zu öffnen - Use Index Search For Path Search + Drücken Sie Enter, um Ordner im Default-Dateimanager zu öffnen + Indexsuche für Pfadsuche verwenden Indexierungsoptionen Suche: Pfad-Suche: @@ -60,10 +60,10 @@ Aktiviert Deaktiviert - Content Search Engine - Directory Recursive Search Engine - Index Search Engine - Open Windows Index Option + Content-Suchmaschine + Verzeichnis Rekursive Suchmaschine + Suchmaschine indizieren + Windows-Indexierungsoptionen öffnen Ausgeschlossene Dateitypen (durch Komma getrennt) Zum Beispiel: exe,jpg,png Maximale Ergebnisse @@ -131,12 +131,12 @@ Pfad Größe Extension - Type Name + Typname Erstellungsdatum Änderungsdatum Attribute - File List FileName - Run Count + Dateilistenname + Ausführungszahl Datum kürzlich geändert Zugriffsdatum Ausführungsdatum @@ -145,7 +145,7 @@ Warnung: Dies ist keine Schnellsortieroption, Suchen können langsam sein Vollständigen Pfad suchen - Enable File/Folder Run Count + Datei-/Ordnerlaufzähler aktivieren Klicken, um Everything zu starten oder zu installieren Everything-Installation diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml new file mode 100644 index 000000000..0e1753d67 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml @@ -0,0 +1,165 @@ + + + + + Please make a selection first + Please select a folder link + Are you sure you want to delete {0}? + Are you sure you want to permanently delete this file? + Are you sure you want to permanently delete this file/folder? + Deletion successful + Successfully deleted {0} + Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword + Quick Access can not be set to the global action keyword when enabled. Please choose a specific action keyword + The required service for Windows Index Search does not appear to be running + To fix this, start the Windows Search service. Select here to remove this warning + The warning message has been switched off. As an alternative for searching files and folders, would you like to install Everything plugin?{0}{0}Select 'Yes' to install Everything plugin, or 'No' to return + Explorer Alternative + Error occurred during search: {0} + Could not open folder + Could not open file + + + מחק + ערוך + הוסף + General Setting + Customise Action Keywords + Quick Access Links + Everything Setting + Preview Panel + Size + Date Created + Date Modified + Display File Info + Date and time format + Sort Option: + Everything Path: + Launch Hidden + Editor Path + Shell Path + Index Search Excluded Paths + Use search result's location as the working directory of the executable + Hit Enter to open folder in Default File Manager + Use Index Search For Path Search + Indexing Options + Search: + Path Search: + File Content Search: + Index Search: + Quick Access: + Current Action Keyword + בוצע + Enabled + When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword + Everything + Windows Index + Direct Enumeration + File Editor Path + Folder Editor Path + Enabled + Disabled + + Content Search Engine + Directory Recursive Search Engine + Index Search Engine + Open Windows Index Option + Excluded File Types (comma seperated) + For example: exe,jpg,png + Maximum results + The maximum number of results requested from active search engine + + + Explorer + Find and manage files and folders via Windows Search or Everything + + + Ctrl + Enter to open the directory + Ctrl + Enter to open the containing folder + + + Copy path + Copy path of current item to clipboard + Copy + Copy current file to clipboard + Copy current folder to clipboard + מחק + Permanently delete current file + Permanently delete current folder + Path: + Delete the selected + Run as different user + Run the selected using a different user account + Open containing folder + Open the location that contains current item + Open With Editor: + Failed to open file at {0} with Editor {1} at {2} + Open With Shell: + Failed to open folder {0} with Shell {1} at {2} + Exclude current and sub-directories from Index Search + Excluded from Index Search + Open Windows Indexing Options + Manage indexed files and folders + Failed to open Windows Indexing Options + Add to Quick Access + Add current item to Quick Access + Successfully Added + Successfully added to Quick Access + Successfully Removed + Successfully removed from Quick Access + Add to Quick Access so it can be opened with Explorer's Search Activation action keyword + Remove from Quick Access + Remove from Quick Access + Remove current item from Quick Access + Show Windows Context Menu + Open With + Select a program to open with + + + {0} free of {1} + Open in Default File Manager + + Use '>' to search in this directory, '*' to search for file extensions or '>*' to combine both searches. + + + + Failed to load Everything SDK + אזהרה: שירות Everything אינו פועל + שגיאה במהלך שאילתה לEverything + Sort By + Name + Path + Size + Extension + Type Name + Date Created + Date Modified + Attributes + File List FileName + Run Count + Date Recently Changed + Date Accessed + Date Run + + + Warning: This is not a Fast Sort option, searches may be slow + + Search Full Path + Enable File/Folder Run Count + + Click to launch or install Everything + Everything Installation + Installing Everything service. Please wait... + Successfully installed Everything service + Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com + Click here to start it + Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you + Do you want to enable content search for Everything? + It can be very slow without index (which is only supported in Everything v1.5+) + + + Native Context Menu + Display native context menu (experimental) + Below you can specify items you want to include in the context menu, they can be partial (e.g. 'pen wit') or complete ('Open with'). + Below you can specify items you want to exclude from context menu, they can be partial (e.g. 'pen wit') or complete ('Open with'). + diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml index 38b9c29c6..911364fdf 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml @@ -43,7 +43,7 @@ Hit Enter to open folder in Default File Manager Use Index Search For Path Search Indexing Options - Search: + Поиск: Path Search: File Content Search: Index Search: @@ -78,17 +78,17 @@ Ctrl + Enter to open the containing folder - Copy path + Скопировать путь Copy path of current item to clipboard - Copy + Скопировать Copy current file to clipboard Copy current folder to clipboard Удалить Permanently delete current file Permanently delete current folder - Path: + Путь: Delete the selected - Run as different user + Запустить от имени другого пользователя Run the selected using a different user account Open containing folder Open the location that contains current item diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/de.xaml index 50d3b01ed..f39f4d4be 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/de.xaml @@ -1,9 +1,9 @@  - Plug-in-Aktions-Schlüsselwort {0} aktivieren + Aktions-Schlüsselwort für Plug-in {0} aktivieren Plug-in-Indikator - Bietet Vorschläge für Aktionswörter für Plug-ins + Bietet Vorschläge für Aktions-Schlüsselwörter für Plug-ins diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/he.xaml new file mode 100644 index 000000000..893948d3d --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/he.xaml @@ -0,0 +1,9 @@ + + + + Activate {0} plugin action keyword + + Plugin Indicator + Provides plugins action words suggestions + + diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/he.xaml new file mode 100644 index 000000000..e13a857a1 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/he.xaml @@ -0,0 +1,63 @@ + + + + + Downloading plugin + Successfully downloaded {0} + Error: Unable to download the plugin + {0} by {1} {2}{3}Would you like to uninstall this plugin? After the uninstallation Flow will automatically restart. + {0} by {1} {2}{2}Would you like to uninstall this plugin? + {0} by {1} {2}{3}Would you like to install this plugin? After the installation Flow will automatically restart. + {0} by {1} {2}{2}Would you like to install this plugin? + Plugin Install + Installing Plugin + Download and install {0} + Plugin Uninstall + Plugin {0} successfully installed. Restarting Flow, please wait... + Unable to find the plugin.json metadata file from the extracted zip file. + Error: A plugin which has the same or greater version with {0} already exists. + Error installing plugin + Error occurred while trying to install {0} + Error uninstalling plugin + No update available + All plugins are up to date + {0} by {1} {2}{3}Would you like to update this plugin? After the update Flow will automatically restart. + {0} by {1} {2}{2}Would you like to update this plugin? + Plugin Update + This plugin is already installed + Plugin Manifest Download Failed + Please check if you can connect to github.com. This error means you may not be able to install or update plugins. + Update all plugins + Would you like to update all plugins? + Would you like to update {0} plugins?{1}Flow Launcher will restart after updating all plugins. + Would you like to update {0} plugins? + {0} plugins successfully updated. Restarting Flow, please wait... + Plugin {0} successfully updated. Restarting Flow, please wait... + Installing from an unknown source + You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings) + + Plugin {0} successfully installed. Please restart Flow. + Plugin {0} successfully uninstalled. Please restart Flow. + Plugin {0} successfully updated. Please restart Flow. + {0} plugins successfully updated. Please restart Flow. + Plugin {0} has already been modified. Please restart Flow before making any further changes. + + + Plugins Manager + Management of installing, uninstalling or updating Flow Launcher plugins + Unknown Author + + + Open website + Visit the plugin's website + See source code + See the plugin's source code + Suggest an enhancement or submit an issue + Suggest an enhancement or submit an issue to the plugin developer + Go to Flow's plugins repository + Visit the PluginsManifest repository to see community-made plugin submissions + + + Install from unknown source warning + Automatically restart Flow Launcher after installing/uninstalling/updating plugins + diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/de.xaml index b3429f7af..8697818dc 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/de.xaml @@ -1,11 +1,11 @@  - Prozesskiller - Beende laufende Prozesse durch Flow Launcher + Process Killer + Laufende Prozesse aus Flow Launcher beenden - alle Instanzen von "{0} " beenden - beende {0} Prozesse - alle Instanzen beenden + Alle Instanzen von "{0}" beenden + {0} Prozesse beenden + Alle Instanzen beenden diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/he.xaml new file mode 100644 index 000000000..c4cc85463 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/he.xaml @@ -0,0 +1,11 @@ + + + + Process Killer + Kill running processes from Flow Launcher + + kill all instances of "{0}" + kill {0} processes + kill all instances + + diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/de.xaml index 81f2b7c7b..7923024ab 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/de.xaml @@ -31,7 +31,7 @@ App-Pfad ausblenden Für ausführbare Dateien wie UWP oder lnk den Dateipfad nicht mehr sichtbar machen Uninstaller ausblenden - Versteckt Programme mit gängigen Uninstaller-Namen, wie unins000.exe + Blendet Programme mit gängigen Uninstaller-Namen aus, wie unins000.exe In Programmbeschreibung suchen Flow wird in Programmbeschreibung suchen Suffixe diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/fr.xaml index 3adc1fd33..b67a1a727 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/fr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/fr.xaml @@ -75,7 +75,7 @@ Masquer ce programme des résultats Ouvrir le répertoire cible - Programme + Programmes Rechercher des programmes dans Flow Launcher Chemin d'accès invalide diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/he.xaml new file mode 100644 index 000000000..69b9324dc --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/he.xaml @@ -0,0 +1,95 @@ + + + + + Reset Default + מחק + ערוך + הוסף + Name + Enable + Enabled + Disable + Status + Enabled + Disabled + Location + All Programs + File Type + Reindex + Indexing + Index Sources + Options + UWP Apps + When enabled, Flow will load UWP Applications + Start Menu + When enabled, Flow will load programs from the start menu + Registry + When enabled, Flow will load programs from the registry + PATH + When enabled, Flow will load programs from the PATH environment variable + Hide app path + For executable files such as UWP or lnk, hide the file path from being visible + Hide uninstallers + Hides programs with common uninstaller names, such as unins000.exe + Search in Program Description + Flow will search program's description + Suffixes + Max Depth + + Directory + Browse + File Suffixes: + Maximum Search Depth (-1 is unlimited): + + Please select a program source + Are you sure you want to delete the selected program sources? + Another program source with the same location already exists. + + Program Source + Edit directory and status of this program source. + + עדכון + Program Plugin will only index files with selected suffixes and .url files with selected protocols. + Successfully updated file suffixes + File suffixes can't be empty + Protocols can't be empty + + File Suffixes + URL Protocols + Steam Games + Epic Games + Http/Https + Custom URL Protocols + Custom File Suffixes + + Insert file suffixes you want to index. Suffixes should be separated by ';'. (ex>bat;py) + + + Insert protocols of .url files you want to index. Protocols should be separated by ';', and should end with "://". (ex>ftp://;mailto://) + + + Run As Different User + Run As Administrator + Open containing folder + Disable this program from displaying + Open target folder + + Program + Search programs in Flow Launcher + + Invalid Path + + Customized Explorer + Args + You can customize the explorer used for opening the container folder by inputing the Environmental Variable of the explorer you want to use. It will be useful to use CMD to test whether the Environmental Variable is available. + Enter the customized args you want to add for your customized explorer. %s for parent directory, %f for full path (which only works for win32). Check the explorer's website for details. + + + הצליח + Error + Successfully disabled this program from displaying in your query + This app is not intended to be run as administrator + Unable to run {0} + + diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/he.xaml new file mode 100644 index 000000000..b7d02c558 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/he.xaml @@ -0,0 +1,17 @@ + + + + Replace Win+R + Close Command Prompt after pressing any key + Press any key to close this window... + Do not close Command Prompt after command execution + Always run as administrator + Run as different user + Shell + Allows to execute system commands from Flow Launcher + this command has been executed {0} times + execute command through command shell + Run As Administrator + Copy the command + Only show number of most used commands: + diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/ru.xaml index bf3864c7b..20fc3fb5d 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/ru.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/ru.xaml @@ -6,7 +6,7 @@ Press any key to close this window... Не закрывать командную строку после выполнения команды Всегда запускать с правами администратора - Run as different user + Запустить от имени другого пользователя Оболочка Allows to execute system commands from Flow Launcher эта команда была выполнена {0} раз diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml index cb8b00f52..5a5170838 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml @@ -46,7 +46,7 @@ Busca actualizaciones de Flow Launcher Accede a la documentación de Flow Launcher para más ayuda y consejos de uso Abre la ubicación donde se almacena la configuración de Flow Launcher - Cambia a Modo Juego + Cambiar a Modo Juego Correcto diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml new file mode 100644 index 000000000..b98fc47ee --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml @@ -0,0 +1,63 @@ + + + + + Command + Description + + Shutdown + Restart + Restart With Advanced Boot Options + Log Off/Sign Out + Lock + Sleep + Hibernate + Index Option + Empty Recycle Bin + Open Recycle Bin + יציאה + Save Settings + Restart Flow Launcher + הגדרות + Reload Plugin Data + Check For Update + Open Log Location + Flow Launcher Tips + Flow Launcher UserData Folder + Toggle Game Mode + + + Shutdown Computer + Restart Computer + Restart the computer with Advanced Boot Options for Safe and Debugging modes, as well as other options + Log off + Lock this computer + Close Flow Launcher + Restart Flow Launcher + Tweak Flow Launcher's settings + Put computer to sleep + Empty recycle bin + Open recycle bin + Indexing Options + Hibernate computer + Save all Flow Launcher settings + Refreshes plugin data with new content + Open Flow Launcher's log location + Check for new Flow Launcher update + Visit Flow Launcher's documentation for more help and how to use tips + Open the location where Flow Launcher's settings are stored + Toggle Game Mode + + + הצליח + All Flow Launcher settings saved + Reloaded all applicable plugin data + Are you sure you want to shut the computer down? + Are you sure you want to restart the computer? + Are you sure you want to restart the computer with Advanced Boot Options? + Are you sure you want to log off? + + System Commands + Provides System related commands. e.g. shutdown, lock, settings etc. + + diff --git a/Plugins/Flow.Launcher.Plugin.Url/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Url/Languages/de.xaml index 9ae4c17df..ee13754d5 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.Url/Languages/de.xaml @@ -5,13 +5,13 @@ Neues Fenster Neuer Tab - Öffne URL:{0} - Kann URL nicht öffnen:{0} + URL öffnen: {0} + URL kann nicht geöffnet werden: {0} URL - Öffne eine eingegebene URL mit Flow Launcher + Öffnen Sie die eingetippte URL in Flow Launcher Bitte legen Sie Ihren Browser-Pfad fest: - Auswählen - URL öffnen: {0} + Wählen + Anwendung (*.exe)|*.exe|Alle Dateien|*.* diff --git a/Plugins/Flow.Launcher.Plugin.Url/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Url/Languages/he.xaml new file mode 100644 index 000000000..418731021 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Url/Languages/he.xaml @@ -0,0 +1,17 @@ + + + + Open search in: + New Window + New Tab + + Open url:{0} + Can't open url:{0} + + URL + Open the typed URL from Flow Launcher + + Please set your browser path: + Choose + Application(*.exe)|*.exe|All files|*.* + diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml index 623a5d5fb..6e92178db 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml @@ -29,7 +29,8 @@ وبالتالي، فإن الصيغة العامة للبحث على نتفليكس هي https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard العنوان diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml index e9f59929b..849f27f05 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml @@ -29,7 +29,8 @@ Obecný vzorec pro vyhledávání Netflixu je tedy https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Název diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml index 096abc5f1..2a7d4aa32 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Title diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml index 15788acaa..0c72b11bf 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml @@ -6,7 +6,7 @@ Neues Fenster Neuer Tab Browser aus Pfad festlegen: - Auswählen + Wählen Löschen Bearbeiten Hinzufügen @@ -19,7 +19,7 @@ Suche Autovervollständigung von Suchanfragen verwenden: Daten automatisch vervollständigen aus: - Bitte wähle einen Suchdienst + Bitte wählen Sie eine Websuche aus Sind Sie sicher, dass Sie {0} löschen wollen? Wenn Sie Flow eine Suche nach einer bestimmten Website hinzufügen möchten, geben Sie zunächst eine Dummy-Textzeichenfolge in die Suchleiste dieser Website ein und starten Sie die Suche. Kopieren Sie jetzt den Inhalt der Adressleiste des Browsers und fügen Sie ihn in das URL-Feld unten ein. Ersetzen Sie Ihre Testzeichenfolge durch {q}. Zum Beispiel, wenn Sie auf Netflix nach casino suchen, steht in der Adressleiste https://www.netflix.com/search?q=Casino @@ -30,23 +30,24 @@ https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Titel Status - Wähle Symbol - Symbol + Icon auswählen + Icon Abbrechen - Ungültige Internetsuche - Bitte Titel eingeben - Aktions-Schlüsselwort ist bereits vorhanden. Bitte geben Sie ein anderes ein. - Bitte URL eingeben - Aktionsschlüsselwort existiert bereits. Bitte gebe ein anderes ein. + Ungültige Websuche + Bitte geben Sie einen Titel ein + Bitte geben Sie ein Aktions-Schlüsselwort ein + Bitte geben Sie eine URL ein + Aktions-Schlüsselwort ist bereits vorhanden. Bitte geben Sie ein anderes ein Erfolg Hinweis: Sie müssen keine benutzerdefinierten Bilder in diesem Verzeichnis ablegen, wenn die Version von Flow aktualisiert wird, gehen diese verloren. Flow kopiert automatisch jegliche Bilder außerhalb dieses Verzeichnisses herüber in den benutzerdefinierten Bildspeicherort von WebSearch. - Internetsuche + Web-Suchen Ermöglicht die Durchführung von Web-Suchen diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml index 6e992b944..517ac0918 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Título diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml index bb78d36b0..e6e4a94d2 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml @@ -29,7 +29,8 @@ De esta manera, la fórmula genérica para una búsqueda en Netflix será https://www.netflix.com/search?q={q} - + Copiar URL + Copiar URL de búsqueda al portapapeles Título diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml index f5988733e..c6b1b145c 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml @@ -29,7 +29,8 @@ Ainsi, la formule générique pour une recherche Netflix est https://www.netflix.com/search?q={q} - + Copier l'URL + Copier l'URL de la recherche dans le presse-papiers Titre @@ -45,7 +46,7 @@ Ajout Astuce : Vous n'avez pas besoin de placer des images personnalisées dans ce dossier, si la version de Flow est mise à jour, elles seront perdues. Flow copiera automatiquement toutes les images en dehors de ce dossier dans l'emplacement de l'image personnalisée de la Recherche Web. - Recherches Web + Recherches web Permet d'effectuer des recherches web diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml new file mode 100644 index 000000000..820bb141b --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml @@ -0,0 +1,52 @@ + + + + Search Source Setting + Open search in: + New Window + New Tab + Set browser from path: + Choose + מחק + ערוך + הוסף + Enabled + Enabled + Disabled + Confirm + Action Keyword + URL + Search + Use Search Query Autocomplete: + Autocomplete Data from: + Please select a web search + Are you sure you want to delete {0}? + If you want to add a search for a particular website to Flow, first enter a dummy text string in the search bar of that website, and launch the search. Now copy the contents of the browser's address bar, and paste it in the URL field below. Replace your test string with {q}. For example, if you search for casino on Netflix, its address bar reads + https://www.netflix.com/search?q=Casino + + Now copy this entire string and paste it in the URL field below. + Then replace casino with {q}. + Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} + + + Copy URL + Copy search URL to clipboard + + + Title + Status + Select Icon + Icon + ביטול + Invalid web search + Please enter a title + Please enter an action keyword + Please enter a URL + Action keyword already exists, please enter a different one + הצליח + Hint: You do not need to place custom images in this directory, if Flow's version is updated they will be lost. Flow will automatically copy any images outside of this directory across to WebSearch's custom image location. + + Web Searches + Allows to perform web searches + + diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml index dc9bd7a2e..26c1e8459 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml @@ -29,7 +29,8 @@ Così la formula generica per una ricerca su Netflix è https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Titolo diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml index b5d4df430..85ce0e282 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard タイトル diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml index 1f43e20c2..5ab5fffa3 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard 이름 diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml index b84daeb87..4bba382a9 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml @@ -29,7 +29,8 @@ dvs. den generiske formelen for et søk på Netflix er https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Tittel diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml index fb6fd4353..a48d99487 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + URL kopiëren + Zoek-URL kopiëren naar klembord Title diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml index 1c426ee08..4f702d4a7 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml @@ -29,7 +29,8 @@ W ten sposób ogólna formuła wyszukiwania na Netflix to https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Tytuł diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml index b2dedeb60..d4135c795 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Title diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml index 56d65e849..16969dac7 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml @@ -29,7 +29,8 @@ Assim, a fórmula genérica de uma pesquisa na Netflix é https://www.netflix.com/search?q={q} - + Copiar URL + Copiar URL para a área de transferência Título diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml index a2ec9405a..ffe37b3ce 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml @@ -1,4 +1,4 @@ - + Search Source Setting @@ -28,7 +28,8 @@ Then replace casino with {q}. Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Скопировать URL-адрес + Скопировать URL поиска в буфер обмена diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml index e23d12a16..44b765c58 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml @@ -29,7 +29,8 @@ Všeobecný vzorec pre vyhľadávanie na Netflix je teda https://www.netflix.com/search?q={q} - + Kopírovať URL + Kopírovať URL vyhľadávanie do schránky Názov diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml index 54ee24376..5f1803655 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Title diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml index 05f3de095..1506b753b 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Başlık diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml index 87419023b..beb085d28 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml @@ -29,7 +29,8 @@ Таким чином, загальна формула для пошуку на Netflix має вигляд https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Назва diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml index a6de788b5..e3105283f 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard Tiêu đề diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml index cd05cf7b8..d3df223cc 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml @@ -29,7 +29,8 @@ 那么 Netflix 搜索的表达式就是 https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard 标题 diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml index d50d65867..eb58a4ec0 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml @@ -29,7 +29,8 @@ Thus, the generic formula for a search on Netflix is https://www.netflix.com/search?q={q} - + Copy URL + Copy search URL to clipboard 標題 diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx index a716ef4c6..dac5f82bc 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx @@ -126,7 +126,7 @@ File name, Should not translated - Barrierefreiheitsoptionen + Optionen für Barrierefreiheit Area Control Panel (legacy settings) @@ -296,7 +296,7 @@ Programme - SurfaceHub + Oberflächenhub System @@ -424,11 +424,11 @@ Mean the "Caps Lock" key - Mobilfunknetz und SIM-Karte + Mobilfunk und SIM Area NetworkAndInternet - Wählen Sie aus, welche Ordner im Startmenü angezeigt werden + Wählen Sie, welche Ordner im Start erscheinen Area Personalization @@ -547,7 +547,7 @@ Area Control Panel (legacy settings) - deuteranopia + Farbenfehlsichtigkeit Medical: Mean you don't can see red colors @@ -654,7 +654,7 @@ Area Privacy - FindFast + Schnell finden Area Control Panel (legacy settings) @@ -697,7 +697,7 @@ Area Control Panel (legacy settings) - Game DVR + DVR Area Gaming @@ -865,7 +865,7 @@ Area Apps - Messaging + Nachrichten Area Privacy @@ -876,7 +876,7 @@ Area Privacy - Microsoft Mail Post Office + Microsoft Mail Post Area Control Panel (legacy settings) @@ -1251,7 +1251,7 @@ Area System - protanopia + Protanopie Medical: Mean you don't can see green colors @@ -1332,7 +1332,7 @@ Area Control Panel (legacy settings) - schedtasks + sedtasks File name, Should not translated @@ -1412,7 +1412,7 @@ Area System - Speech + Sprache Area EaseOfAccess @@ -1544,7 +1544,7 @@ Transparenz - tritanopia + Farbenblindheit (Blau) Medical: Mean you don't can see yellow and blue colors @@ -1552,7 +1552,7 @@ Area UpdateAndSecurity - TruePlay + TruePlaying Area Gaming @@ -2064,7 +2064,7 @@ Microsoft ChangJie-Einstellungen - Replace sounds with visual cues + Sounds durch visuelle Hinweise ersetzen Temporäre Internet-Dateieinstellungen ändern @@ -2079,7 +2079,7 @@ Change the mouse pointer display or speed - Back up your recovery key + Ihren Wiederherstellungsschlüssel sichern Save backup copies of your files with File History @@ -2133,7 +2133,7 @@ Change power-saving settings - Optimise for blindness + Optimieren für Blindheit @@ -2155,7 +2155,7 @@ Ihre Offline-Dateien verschlüsseln - Train the computer to recognise your voice + Trainieren Sie den Computer, Ihre Stimme zu erkennen Erweiterte Druckereinrichtung @@ -2461,10 +2461,10 @@ Set your default programs - Set up a broadband connection + Eine Breitbandverbindung einrichten - Calibrate the screen for pen or touch input + Kalibrieren des Screens für Stift- oder Toucheingabe Benutzerzertifikate verwalten diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.he-IL.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.he-IL.resx new file mode 100644 index 000000000..2b6d5aa63 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.he-IL.resx @@ -0,0 +1,2514 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + אודות + Area System + + + access.cpl + File name, Should not translated + + + Accessibility Options + Area Control Panel (legacy settings) + + + Accessory apps + Area Privacy + + + Access work or school + Area UserAccounts + + + Account info + Area Privacy + + + Accounts + Area SurfaceHub + + + Action Center + Area Control Panel (legacy settings) + + + Activation + Area UpdateAndSecurity + + + Activity history + Area Privacy + + + Add Hardware + Area Control Panel (legacy settings) + + + Add/Remove Programs + Area Control Panel (legacy settings) + + + Add your phone + Area Phone + + + Administrative Tools + Area System + + + Advanced display settings + Area System, only available on devices that support advanced display options + + + Advanced graphics + + + Advertising ID + Area Privacy, Deprecated in Windows 10, version 1809 and later + + + Airplane mode + Area NetworkAndInternet + + + Alt+Tab + Means the key combination "Tabulator+Alt" on the keyboard + + + Alternative names + + + Animations + + + App color + + + App diagnostics + Area Privacy + + + App features + Area Apps + + + App + Short/modern name for application + + + Apps and Features + Area Apps + + + System settings + Type of the setting is a "Modern Windows settings". We use the same term as used in start menu search at the moment. + + + Apps for websites + Area Apps + + + App volume and device preferences + Area System, Added in Windows 10, version 1903 + + + appwiz.cpl + File name, Should not translated + + + Area + Mean the settings area or settings category + + + Accounts + + + Administrative Tools + Area Control Panel (legacy settings) + + + Appearance and Personalization + + + Apps + + + Clock and Region + + + Control Panel + + + Cortana + + + Devices + + + Ease of access + + + Extras + + + Gaming + + + Hardware and Sound + + + Home page + + + Mixed reality + + + Network and Internet + + + Personalization + + + Phone + + + Privacy + + + Programs + + + SurfaceHub + + + System + + + System and Security + + + Time and language + + + Update and security + + + User accounts + + + Assigned access + + + Audio + Area EaseOfAccess + + + Audio alerts + + + Audio and speech + Area MixedReality, only available if the Mixed Reality Portal app is installed. + + + Automatic file downloads + Area Privacy + + + AutoPlay + Area Device + + + Background + Area Personalization + + + Background Apps + Area Privacy + + + Backup + Area UpdateAndSecurity + + + Backup and Restore + Area Control Panel (legacy settings) + + + Battery Saver + Area System, only available on devices that have a battery, such as a tablet + + + Battery Saver settings + Area System, only available on devices that have a battery, such as a tablet + + + Battery saver usage details + + + Battery use + Area System, only available on devices that have a battery, such as a tablet + + + Biometric Devices + Area Control Panel (legacy settings) + + + BitLocker Drive Encryption + Area Control Panel (legacy settings) + + + Blue light + + + Bluetooth + Area Device + + + Bluetooth devices + Area Control Panel (legacy settings) + + + Blue-yellow + + + Bopomofo IME + Area TimeAndLanguage + + + bpmf + Should not translated + + + Broadcasting + Area Gaming + + + Calendar + Area Privacy + + + Call history + Area Privacy + + + calling + + + Camera + Area Privacy + + + Cangjie IME + Area TimeAndLanguage + + + Caps Lock + Mean the "Caps Lock" key + + + Cellular and SIM + Area NetworkAndInternet + + + Choose which folders appear on Start + Area Personalization + + + Client service for NetWare + Area Control Panel (legacy settings) + + + Clipboard + Area System + + + Closed captions + Area EaseOfAccess + + + Color filters + Area EaseOfAccess + + + Color management + Area Control Panel (legacy settings) + + + Colors + Area Personalization + + + Command + The command to direct start a setting + + + Connected Devices + Area Device + + + Contacts + Area Privacy + + + Control Panel + Type of the setting is a "(legacy) Control Panel setting" + + + Copy command + + + Core Isolation + Means the protection of the system core + + + Cortana + Area Cortana + + + Cortana across my devices + Area Cortana + + + Cortana - Language + Area Cortana + + + Credential manager + Area Control Panel (legacy settings) + + + Crossdevice + + + Custom devices + + + Dark color + + + Dark mode + + + Data usage + Area NetworkAndInternet + + + Date and time + Area TimeAndLanguage + + + Default apps + Area Apps + + + Default camera + Area Device + + + Default location + Area Control Panel (legacy settings) + + + Default programs + Area Control Panel (legacy settings) + + + Default Save Locations + Area System + + + Delivery Optimization + Area UpdateAndSecurity + + + desk.cpl + File name, Should not translated + + + Desktop themes + Area Control Panel (legacy settings) + + + deuteranopia + Medical: Mean you don't can see red colors + + + Device manager + Area Control Panel (legacy settings) + + + Devices and printers + Area Control Panel (legacy settings) + + + DHCP + Should not translated + + + Dial-up + Area NetworkAndInternet + + + Direct access + Area NetworkAndInternet, only available if DirectAccess is enabled + + + Direct open your phone + Area EaseOfAccess + + + Display + Area EaseOfAccess + + + Display properties + Area Control Panel (legacy settings) + + + DNS + Should not translated + + + Documents + Area Privacy + + + Duplicating my display + Area System + + + During these hours + Area System + + + Ease of access center + Area Control Panel (legacy settings) + + + Edition + Means the "Windows Edition" + + + Email + Area Privacy + + + Email and app accounts + Area UserAccounts + + + Encryption + Area System + + + Environment + Area MixedReality, only available if the Mixed Reality Portal app is installed. + + + Ethernet + Area NetworkAndInternet + + + Exploit Protection + + + Extras + Area Extra, , only used for setting of 3rd-Party tools + + + Eye control + Area EaseOfAccess + + + Eye tracker + Area Privacy, requires eyetracker hardware + + + Family and other people + Area UserAccounts + + + Feedback and diagnostics + Area Privacy + + + File system + Area Privacy + + + FindFast + Area Control Panel (legacy settings) + + + findfast.cpl + File name, Should not translated + + + Find My Device + Area UpdateAndSecurity + + + Firewall + + + Focus assist - Quiet hours + Area System + + + Focus assist - Quiet moments + Area System + + + Folder options + Area Control Panel (legacy settings) + + + Fonts + Area EaseOfAccess + + + For developers + Area UpdateAndSecurity + + + Game bar + Area Gaming + + + Game controllers + Area Control Panel (legacy settings) + + + Game DVR + Area Gaming + + + מצב משחק + Area Gaming + + + Gateway + Should not translated + + + כללי + Area Privacy + + + Get programs + Area Control Panel (legacy settings) + + + Getting started + Area Control Panel (legacy settings) + + + Glance + Area Personalization, Deprecated in Windows 10, version 1809 and later + + + Graphics settings + Area System + + + Grayscale + + + Green week + Mean you don't can see green colors + + + Headset display + Area MixedReality, only available if the Mixed Reality Portal app is installed. + + + High contrast + Area EaseOfAccess + + + Holographic audio + + + Holographic Environment + + + Holographic Headset + + + Holographic Management + + + Home group + Area Control Panel (legacy settings) + + + ID + MEans The "Windows Identifier" + + + Image + + + Indexing options + Area Control Panel (legacy settings) + + + inetcpl.cpl + File name, Should not translated + + + Infrared + Area Control Panel (legacy settings) + + + Inking and typing + Area Privacy + + + Internet options + Area Control Panel (legacy settings) + + + intl.cpl + File name, Should not translated + + + Inverted colors + + + IP + Should not translated + + + Isolated Browsing + + + Japan IME settings + Area TimeAndLanguage, available if the Microsoft Japan input method editor is installed + + + joy.cpl + File name, Should not translated + + + Joystick properties + Area Control Panel (legacy settings) + + + jpnime + Should not translated + + + Keyboard + Area EaseOfAccess + + + Keypad + + + Keys + + + שפה + Area TimeAndLanguage + + + Light color + + + Light mode + + + Location + Area Privacy + + + Lock screen + Area Personalization + + + Magnifier + Area EaseOfAccess + + + Mail - Microsoft Exchange or Windows Messaging + Area Control Panel (legacy settings) + + + main.cpl + File name, Should not translated + + + Manage known networks + Area NetworkAndInternet + + + Manage optional features + Area Apps + + + Messaging + Area Privacy + + + Metered connection + + + Microphone + Area Privacy + + + Microsoft Mail Post Office + Area Control Panel (legacy settings) + + + mlcfg32.cpl + File name, Should not translated + + + mmsys.cpl + File name, Should not translated + + + Mobile devices + + + Mobile hotspot + Area NetworkAndInternet + + + modem.cpl + File name, Should not translated + + + Mono + + + More details + Area Cortana + + + Motion + Area Privacy + + + Mouse + Area EaseOfAccess + + + Mouse and touchpad + Area Device + + + Mouse, Fonts, Keyboard, and Printers properties + Area Control Panel (legacy settings) + + + Mouse pointer + Area EaseOfAccess + + + Multimedia properties + Area Control Panel (legacy settings) + + + Multitasking + Area System + + + Narrator + Area EaseOfAccess + + + Navigation bar + Area Personalization + + + netcpl.cpl + File name, Should not translated + + + netsetup.cpl + File name, Should not translated + + + Network + Area NetworkAndInternet + + + Network and sharing center + Area Control Panel (legacy settings) + + + Network connection + Area Control Panel (legacy settings) + + + Network properties + Area Control Panel (legacy settings) + + + Network Setup Wizard + Area Control Panel (legacy settings) + + + Network status + Area NetworkAndInternet + + + NFC + Area NetworkAndInternet + + + NFC Transactions + "NFC should not translated" + + + Night light + + + Night light settings + Area System + + + Note + + + Only available when you have connected a mobile device to your device. + + + Only available on devices that support advanced graphics options. + + + Only available on devices that have a battery, such as a tablet. + + + Deprecated in Windows 10, version 1809 (build 17763) and later. + + + Only available if Dial is paired. + + + Only available if DirectAccess is enabled. + + + Only available on devices that support advanced display options. + + + Only present if user is enrolled in WIP. + + + Requires eyetracker hardware. + + + Available if the Microsoft Japan input method editor is installed. + + + Available if the Microsoft Pinyin input method editor is installed. + + + Available if the Microsoft Wubi input method editor is installed. + + + Only available if the Mixed Reality Portal app is installed. + + + Only available on mobile and if the enterprise has deployed a provisioning package. + + + Added in Windows 10, version 1903 (build 18362). + + + Added in Windows 10, version 2004 (build 19041). + + + Only available if "settings apps" are installed, for example, by a 3rd party. + + + Only available if touchpad hardware is present. + + + Only available if the device has a Wi-Fi adapter. + + + Device must be Windows Anywhere-capable. + + + Only available if enterprise has deployed a provisioning package. + + + Notifications + Area Privacy + + + Notifications and actions + Area System + + + Num Lock + Mean the "Num Lock" key + + + nwc.cpl + File name, Should not translated + + + odbccp32.cpl + File name, Should not translated + + + ODBC Data Source Administrator (32-bit) + Area Control Panel (legacy settings) + + + ODBC Data Source Administrator (64-bit) + Area Control Panel (legacy settings) + + + Offline files + Area Control Panel (legacy settings) + + + Offline Maps + Area Apps + + + Offline Maps - Download maps + Area Apps + + + On-Screen + + + OS + Means the "Operating System" + + + Other devices + Area Privacy + + + Other options + Area EaseOfAccess + + + Other users + + + Parental controls + Area Control Panel (legacy settings) + + + Password + + + password.cpl + File name, Should not translated + + + Password properties + Area Control Panel (legacy settings) + + + Pen and input devices + Area Control Panel (legacy settings) + + + Pen and touch + Area Control Panel (legacy settings) + + + Pen and Windows Ink + Area Device + + + People Near Me + Area Control Panel (legacy settings) + + + Performance information and tools + Area Control Panel (legacy settings) + + + Permissions and history + Area Cortana + + + Personalization (category) + Area Personalization + + + Phone + Area Phone + + + Phone and modem + Area Control Panel (legacy settings) + + + Phone and modem - Options + Area Control Panel (legacy settings) + + + Phone calls + Area Privacy + + + Phone - Default apps + Area System + + + Picture + + + Pictures + Area Privacy + + + Pinyin IME settings + Area TimeAndLanguage, available if the Microsoft Pinyin input method editor is installed + + + Pinyin IME settings - domain lexicon + Area TimeAndLanguage + + + Pinyin IME settings - Key configuration + Area TimeAndLanguage + + + Pinyin IME settings - UDP + Area TimeAndLanguage + + + Playing a game full screen + Area Gaming + + + Plugin to search for Windows settings + + + Windows Settings + + + Power and sleep + Area System + + + powercfg.cpl + File name, Should not translated + + + Power options + Area Control Panel (legacy settings) + + + Presentation + + + Printers + Area Control Panel (legacy settings) + + + Printers and scanners + Area Device + + + Print screen + Mean the "Print screen" key + + + Problem reports and solutions + Area Control Panel (legacy settings) + + + Processor + + + Programs and features + Area Control Panel (legacy settings) + + + Projecting to this PC + Area System + + + protanopia + Medical: Mean you don't can see green colors + + + Provisioning + Area UserAccounts, only available if enterprise has deployed a provisioning package + + + Proximity + Area NetworkAndInternet + + + Proxy + Area NetworkAndInternet + + + Quickime + Area TimeAndLanguage + + + Quiet moments game + + + Radios + Area Privacy + + + RAM + Means the Read-Access-Memory (typical the used to inform about the size) + + + Recognition + + + Recovery + Area UpdateAndSecurity + + + Red eye + Mean red eye effect by over-the-night flights + + + Red-green + Mean the weakness you can't differ between red and green colors + + + Red week + Mean you don't can see red colors + + + Region + Area TimeAndLanguage + + + Regional language + Area TimeAndLanguage + + + Regional settings properties + Area Control Panel (legacy settings) + + + Region and language + Area Control Panel (legacy settings) + + + Region formatting + + + RemoteApp and desktop connections + Area Control Panel (legacy settings) + + + Remote Desktop + Area System + + + Scanners and cameras + Area Control Panel (legacy settings) + + + schedtasks + File name, Should not translated + + + Scheduled + + + Scheduled tasks + Area Control Panel (legacy settings) + + + Screen rotation + Area System + + + Scroll bars + + + Scroll Lock + Mean the "Scroll Lock" key + + + SDNS + Should not translated + + + Searching Windows + Area Cortana + + + SecureDNS + Should not translated + + + Security Center + Area Control Panel (legacy settings) + + + Security Processor + + + Session cleanup + Area SurfaceHub + + + Settings home page + Area Home, Overview-page for all areas of settings + + + Set up a kiosk + Area UserAccounts + + + Shared experiences + Area System + + + Shortcuts + + + wifi + dont translate this, is a short term to find entries + + + Sign-in options + Area UserAccounts + + + Sign-in options - Dynamic lock + Area UserAccounts + + + Size + Size for text and symbols + + + Sound + Area System + + + Speech + Area EaseOfAccess + + + Speech recognition + Area Control Panel (legacy settings) + + + Speech typing + + + Start + Area Personalization + + + Start places + + + Startup apps + Area Apps + + + sticpl.cpl + File name, Should not translated + + + Storage + Area System + + + Storage policies + Area System + + + Storage Sense + Area System + + + in + Example: Area "System" in System settings + + + Sync center + Area Control Panel (legacy settings) + + + Sync your settings + Area UserAccounts + + + sysdm.cpl + File name, Should not translated + + + System + Area Control Panel (legacy settings) + + + System properties and Add New Hardware wizard + Area Control Panel (legacy settings) + + + Tab + Means the key "Tabulator" on the keyboard + + + Tablet mode + Area System + + + Tablet PC settings + Area Control Panel (legacy settings) + + + Talk + + + Talk to Cortana + Area Cortana + + + Taskbar + Area Personalization + + + Taskbar color + + + Tasks + Area Privacy + + + Team Conferencing + Area SurfaceHub + + + Team device management + Area SurfaceHub + + + Text to speech + Area Control Panel (legacy settings) + + + Themes + Area Personalization + + + themes.cpl + File name, Should not translated + + + timedate.cpl + File name, Should not translated + + + Timeline + + + Touch + + + Touch feedback + + + Touchpad + Area Device + + + Transparency + + + tritanopia + Medical: Mean you don't can see yellow and blue colors + + + Troubleshoot + Area UpdateAndSecurity + + + TruePlay + Area Gaming + + + Typing + Area Device + + + Uninstall + Area MixedReality, only available if the Mixed Reality Portal app is installed. + + + USB + Area Device + + + User accounts + Area Control Panel (legacy settings) + + + Version + Means The "Windows Version" + + + Video playback + Area Apps + + + Videos + Area Privacy + + + Virtual Desktops + + + Virus + Means the virus in computers and software + + + Voice activation + Area Privacy + + + Volume + + + VPN + Area NetworkAndInternet + + + Wallpaper + + + Warmer color + + + Welcome center + Area Control Panel (legacy settings) + + + Welcome screen + Area SurfaceHub + + + wgpocpl.cpl + File name, Should not translated + + + Wheel + Area Device + + + Wi-Fi + Area NetworkAndInternet, only available if Wi-Fi calling is enabled + + + Wi-Fi Calling + Area NetworkAndInternet, only available if Wi-Fi calling is enabled + + + Wi-Fi settings + "Wi-Fi" should not translated + + + Window border + + + Windows Anytime Upgrade + Area Control Panel (legacy settings) + + + Windows Anywhere + Area UserAccounts, device must be Windows Anywhere-capable + + + Windows CardSpace + Area Control Panel (legacy settings) + + + Windows Defender + Area Control Panel (legacy settings) + + + Windows Firewall + Area Control Panel (legacy settings) + + + Windows Hello setup - Face + Area UserAccounts + + + Windows Hello setup - Fingerprint + Area UserAccounts + + + Windows Insider Program + Area UpdateAndSecurity + + + Windows Mobility Center + Area Control Panel (legacy settings) + + + Windows search + Area Cortana + + + Windows Security + Area UpdateAndSecurity + + + Windows Update + Area UpdateAndSecurity + + + Windows Update - Advanced options + Area UpdateAndSecurity + + + Windows Update - Check for updates + Area UpdateAndSecurity + + + Windows Update - Restart options + Area UpdateAndSecurity + + + Windows Update - View optional updates + Area UpdateAndSecurity + + + Windows Update - View update history + Area UpdateAndSecurity + + + Wireless + + + Workplace + + + Workplace provisioning + Area UserAccounts + + + Wubi IME settings + Area TimeAndLanguage, available if the Microsoft Wubi input method editor is installed + + + Wubi IME settings - UDP + Area TimeAndLanguage + + + Xbox Networking + Area Gaming + + + Your info + Area UserAccounts + + + Zoom + Mean zooming of things via a magnifier + + + Change device installation settings + + + Turn off background images + + + Navigation properties + + + Media streaming options + + + Make a file type always open in a specific program + + + Change the Narrator’s voice + + + Find and fix keyboard problems + + + Use screen reader + + + Show which workgroup this computer is on + + + Change mouse wheel settings + + + Manage computer certificates + + + Find and fix problems + + + Change settings for content received using Tap and send + + + Change default settings for media or devices + + + Print the speech reference card + + + Calibrate display colour + + + Manage file encryption certificates + + + View recent messages about your computer + + + Give other users access to this computer + + + Show hidden files and folders + + + Change Windows To Go start-up options + + + See which processes start up automatically when you start Windows + + + Tell if an RSS feed is available on a website + + + Add clocks for different time zones + + + Add a Bluetooth device + + + Customise the mouse buttons + + + Set tablet buttons to perform certain tasks + + + View installed fonts + + + Change the way currency is displayed + + + Edit group policy + + + Manage browser add-ons + + + Check processor speed + + + Check firewall status + + + Send or receive a file + + + Add or remove user accounts + + + Edit the system environment variables + + + Manage BitLocker + + + Auto-hide the taskbar + + + Change sound card settings + + + Make changes to accounts + + + Edit local users and groups + + + View network computers and devices + + + Install a program from the network + + + View scanners and cameras + + + Microsoft IME Register Word (Japanese) + + + Restore your files with File History + + + Turn On-Screen keyboard on or off + + + Block or allow third-party cookies + + + Find and fix audio recording problems + + + Create a recovery drive + + + Microsoft New Phonetic Settings + + + Generate a system health report + + + Fix problems with your computer + + + Back up and Restore (Windows 7) + + + Preview, delete, show or hide fonts + + + Microsoft Quick Settings + + + View reliability history + + + Access RemoteApp and desktops + + + Set up ODBC data sources + + + Reset Security Policies + + + Block or allow pop-ups + + + Turn autocomplete in Internet Explorer on or off + + + Microsoft Pinyin SimpleFast Options + + + Change what closing the lid does + + + Turn off unnecessary animations + + + Create a restore point + + + Turn off automatic window arrangement + + + Troubleshooting History + + + Diagnose your computer's memory problems + + + View recommended actions to keep Windows running smoothly + + + Change cursor blink rate + + + Add or remove programs + + + Create a password reset disk + + + Configure advanced user profile properties + + + Start or stop using AutoPlay for all media and devices + + + Change Automatic Maintenance settings + + + Specify single- or double-click to open + + + Select users who can use remote desktop + + + Show which programs are installed on your computer + + + Allow remote access to your computer + + + View advanced system settings + + + How to install a program + + + Change how your keyboard works + + + Automatically adjust for daylight saving time + + + Change the order of Windows SideShow gadgets + + + Check keyboard status + + + Control the computer without the mouse or keyboard + + + Change or remove a program + + + Change multi-touch gesture settings + + + Set up ODBC data sources (64-bit) + + + Configure proxy server + + + Change your homepage + + + Group similar windows on the taskbar + + + Change Windows SideShow settings + + + Use audio description for video + + + Change workgroup name + + + Find and fix printing problems + + + Change when the computer sleeps + + + Set up a virtual private network (VPN) connection + + + Accommodate learning abilities + + + Set up a dial-up connection + + + Set up a connection or network + + + How to change your Windows password + + + Make it easier to see the mouse pointer + + + Set up iSCSI initiator + + + Accommodate low vision + + + Manage offline files + + + Review your computer's status and resolve issues + + + Microsoft ChangJie Settings + + + Replace sounds with visual cues + + + Change temporary Internet file settings + + + Connect to the Internet + + + Find and fix audio playback problems + + + Change the mouse pointer display or speed + + + Back up your recovery key + + + Save backup copies of your files with File History + + + View current accessibility settings + + + Change tablet pen settings + + + Change how your mouse works + + + Show how much RAM is on this computer + + + Edit power plan + + + Adjust system volume + + + Defragment and optimise your drives + + + Set up ODBC data sources (32-bit) + + + Change Font Settings + + + Magnify portions of the screen using Magnifier + + + Change the file type associated with a file extension + + + View event logs + + + Manage Windows Credentials + + + Set up a microphone + + + Change how the mouse pointer looks + + + Change power-saving settings + + + Optimise for blindness + + + + + + + Turn Windows features on or off + + + Show which operating system your computer is running + + + View local services + + + Manage Work Folders + + + Encrypt your offline files + + + Train the computer to recognise your voice + + + Advanced printer setup + + + Change default printer + + + Edit environment variables for your account + + + Optimise visual display + + + Change mouse click settings + + + Change advanced colour management settings for displays, scanners and printers + + + Let Windows suggest Ease of Access settings + + + Clear disk space by deleting unnecessary files + + + View devices and printers + + + Private Character Editor + + + Record steps to reproduce a problem + + + Adjust the appearance and performance of Windows + + + Settings for Microsoft IME (Japanese) + + + Invite someone to connect to your PC and help you, or offer to help someone else + + + Run programs made for previous versions of Windows + + + Choose the order of how your screen rotates + + + Change how Windows searches + + + Set flicks to perform certain tasks + + + Change account type + + + Change screen saver + + + Change User Account Control settings + + + Turn on easy access keys + + + Identify and repair network problems + + + Find and fix networking and connection problems + + + Play CDs or other media automatically + + + View basic information about your computer + + + Choose how you open links + + + Allow Remote Assistance invitations to be sent from this computer + + + Task Manager + + + Turn flicks on or off + + + Add a language + + + View network status and tasks + + + Turn Magnifier on or off + + + See the name of this computer + + + View network connections + + + Perform recommended maintenance tasks automatically + + + Manage disk space used by your offline files + + + Turn High Contrast on or off + + + Change the way time is displayed + + + Change how web pages are displayed in tabs + + + Change the way dates and lists are displayed + + + Manage audio devices + + + Change security settings + + + Check security status + + + Delete cookies or temporary files + + + Specify which hand you write with + + + Change touch input settings + + + How to change the size of virtual memory + + + Hear text read aloud with Narrator + + + Set up USB game controllers + + + Show which domain your computer is on + + + View all problem reports + + + 16-Bit Application Support + + + Set up dialling rules + + + Enable or disable session cookies + + + Give administrative rights to a domain user + + + Choose when to turn off display + + + Move the pointer with the keypad using MouseKeys + + + Change Windows SideShow-compatible device settings + + + Adjust commonly used mobility settings + + + Change text-to-speech settings + + + Set the time and date + + + Change location settings + + + Change mouse settings + + + Manage Storage Spaces + + + Show or hide file extensions + + + Allow an app through Windows Firewall + + + Change system sounds + + + Adjust ClearType text + + + Turn screen saver on or off + + + Find and fix windows update problems + + + Change Bluetooth settings + + + Connect to a network + + + Change the search provider in Internet Explorer + + + Join a domain + + + Add a device + + + Find and fix problems with Windows Search + + + Choose a power plan + + + Change how the mouse pointer looks when it’s moving + + + Uninstall a program + + + Create and format hard disk partitions + + + Change date, time or number formats + + + Change PC wake-up settings + + + Manage network passwords + + + Change input methods + + + Manage advanced sharing settings + + + Change battery settings + + + Rename this computer + + + Lock or unlock the taskbar + + + Manage Web Credentials + + + Change the time zone + + + Start speech recognition + + + View installed updates + + + What's happened to the Quick Launch toolbar? + + + Change search options for files and folders + + + Adjust settings before giving a presentation + + + Scan a document or picture + + + Change the way measurements are displayed + + + Press key combinations one at a time + + + Restore data, files or computer from backup (Windows 7) + + + Set your default programs + + + Set up a broadband connection + + + Calibrate the screen for pen or touch input + + + Manage user certificates + + + Schedule tasks + + + Ignore repeated keystrokes using FilterKeys + + + Find and fix bluescreen problems + + + Hear a tone when keys are pressed + + + Delete browsing history + + + Change what the power buttons do + + + Create standard user account + + + Take speech tutorials + + + View system resource usage in Task Manager + + + Create an account + + + Get more features with a new edition of Windows + + + Control Panel + + + TaskLink + + + Unknown + + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx index 418ea06c5..e7f8e1683 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx @@ -1905,7 +1905,7 @@ Microsoft Quick Settings - View reliability history + Ver histórico de fiabilidade Access RemoteApp and desktops @@ -1923,7 +1923,7 @@ Ativar ou desativar conclusão automática no Internet Explorer - Microsoft Pinyin SimpleFast Options + Opções SimpleFast do Microsoft Pinyin Change what closing the lid does @@ -1947,16 +1947,16 @@ Ver ações recomendadas para manter o sistema a funcionar nas melhores condições - Change cursor blink rate + Alterar a frequência de piscar do cursor Adicionar ou remover programas - Create a password reset disk + Criar disco de redefinição da palavra-passe - Configure advanced user profile properties + Configurar propriedades avançadas do perfil de utilizador Start or stop using AutoPlay for all media and devices @@ -1971,10 +1971,10 @@ Utilizadores que podem utilizar o ambiente de trabalho remoto - Show which programs are installed on your computer + Mostre que programas estão instalados no seu computador - Allow remote access to your computer + Permitir o acesso remoto ao seu computador Ver definições avançadas do sistema @@ -1986,10 +1986,10 @@ Alterar modo de funcionamento do teclado - Automatically adjust for daylight saving time + Ajustar automaticamente para horário de verão - Change the order of Windows SideShow gadgets + Alterar a ordem dos Windows SideShow gadgets Analisar estado do teclado @@ -2037,34 +2037,34 @@ Accommodate learning abilities - Set up a dial-up connection + Configurar uma ligação telefónica - Set up a connection or network + Configurar uma ligação ou rede Como alterar a palavra-passe do Windows - Make it easier to see the mouse pointer + Tornar mais fácil ver o ponteiro do rato - Set up iSCSI initiator + Configurar o iniciador iSCSI - Accommodate low vision + Ajustar para baixa visão Gerir ficheiros offline - Review your computer's status and resolve issues + Verificar o estado do computador e resolver problemas - Microsoft ChangJie Settings + Configurações Microsoft ChangJie - Replace sounds with visual cues + Substituir sons por pistas visuais Change temporary Internet file settings @@ -2079,10 +2079,10 @@ Alterar exibição e/ou velocidade do ponteiro do rato - Back up your recovery key + Cópia de segurança da chave de recuperação - Save backup copies of your files with File History + Guardar cópias de segurança dos ficheiros no Histórico de Ficheiros View current accessibility settings @@ -2155,7 +2155,7 @@ Encrypt your offline files - Train the computer to recognise your voice + Treinar o computador para reconhecer a sua voz Configuração avançada de impressora @@ -2218,7 +2218,7 @@ Alterar proteção de ecrã - Change User Account Control settings + Alterar Configurações de Controlo da Conta do Utilizador Turn on easy access keys @@ -2455,7 +2455,7 @@ Press key combinations one at a time - Restore data, files or computer from backup (Windows 7) + Restaurar dados, ficheiros ou computador a partir de cópia de segurança (Windows 7) Set your default programs From f7edecea108ed2fe365682e97d95b73fa40668a1 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 10 Jan 2025 16:26:20 +1100 Subject: [PATCH 115/259] New Crowdin updates (#3149) New translations --- Flow.Launcher/Languages/de.xaml | 4 +- Flow.Launcher/Languages/es.xaml | 4 +- Flow.Launcher/Languages/he.xaml | 108 +++++++++--------- .../Languages/he.xaml | 28 ++--- .../Properties/Resources.de-DE.resx | 4 +- 5 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Flow.Launcher/Languages/de.xaml b/Flow.Launcher/Languages/de.xaml index 7f2e2bd8d..c7e775ae3 100644 --- a/Flow.Launcher/Languages/de.xaml +++ b/Flow.Launcher/Languages/de.xaml @@ -65,8 +65,8 @@ Letzte Abfrage beibehalten Letzte Abfrage auswählen Letzte Abfrage leeren - Preserve Last Action Keyword - Select Last Action Keyword + Letztes Aktions-Schlüsselwort beibehalten + Letztes Aktions-Schlüsselwort auswählen Feste Fensterhöhe Die Fensterhöhe ist durch Ziehen nicht anpassbar. Maximal gezeigte Ergebnisse diff --git a/Flow.Launcher/Languages/es.xaml b/Flow.Launcher/Languages/es.xaml index bf22aea48..c7595f69b 100644 --- a/Flow.Launcher/Languages/es.xaml +++ b/Flow.Launcher/Languages/es.xaml @@ -65,8 +65,8 @@ Mantener la última consulta Seleccionar la última consulta Limpiar la última consulta - Conservar palabra clave de última acción - Seleccionar palabra clave de última acción + Conservar última palabra clave de acción + Seleccionar última palabra clave de acción Altura de la ventana fija La altura de la ventana no se puede ajustar arrastrando el ratón. Número máximo de resultados mostrados diff --git a/Flow.Launcher/Languages/he.xaml b/Flow.Launcher/Languages/he.xaml index eeb33da17..f3c9bb307 100644 --- a/Flow.Launcher/Languages/he.xaml +++ b/Flow.Launcher/Languages/he.xaml @@ -9,7 +9,7 @@ אנא בחר את קובץ ההפעלה {0} לא ניתן להגדיר נתיב הפעלה {0}, אנא נסה שוב בהגדרות Flow (גלול עד למטה). נכשל בהפעלת תוספים - תוספים: {0} - נכשלים בטעינה ויהיו מושבתים, אנא צור קשר עם יוצרי התוספים לקבלת עזרה + תוספים: {0} - נכשלו בטעינה ויושבתו, אנא צור קשר עם יוצרי התוספים לקבלת עזרה רישום מקש הקיצור "{0}" נכשל. ייתכן שמקש הקיצור נמצא בשימוש על ידי תוכנה אחרת. שנה למקש קיצור אחר, או צא מהתוכנה האחרת. @@ -54,10 +54,10 @@ צג ראשי צג מותאם אישית Search Window Position on Monitor - Center - Center Top - Left Top - Right Top + מרכז + מרכז עליון + שמאל עליון + ימין עליון Custom Position שפה Last Query Style @@ -83,16 +83,16 @@ Please select pythonw.exe Always Start Typing in English Mode Temporarily change your input method to English mode when activating Flow. - Auto Update - Select + עדכון אוטומטי + בחר Hide Flow Launcher on startup Flow Launcher search window is hidden in the tray after starting up. Hide tray icon When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window. Query Search Precision Changes minimum match score required for results. - None - Low + ללא + נמוך Regular Search with Pinyin Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese. @@ -120,26 +120,26 @@ Priority Change Plugin Results Priority Plugin Directory - by + מאת Init time: Query time: - Version - Website - Uninstall + גרסה + אתר + הסר התקנה חנות תוספים - New Release + שחרור חדש Recently Updated תוספים - Installed + מותקן רענן התקן - Uninstall + הסר התקנה עדכון Plugin already installed - New Version + גרסה חדשה This plugin has been updated within the last 7 days New Update is Available @@ -164,7 +164,7 @@ Query Box Font Result Title Font Result Subtitle Font - Reset + אפס Customize Window Mode Opacity @@ -196,9 +196,9 @@ - Hotkey - Hotkeys - Open Flow Launcher + מקש קיצור + מקשי קיצור + פתח את Flow Launcher Enter shortcut to show/hide Flow Launcher. Toggle Preview Enter shortcut to show/hide preview in search window. @@ -206,24 +206,24 @@ List of currently registered hotkeys Open Result Modifier Key Select a modifier key to open selected result via keyboard. - Show Hotkey + הצג מקש קיצור Show result selection hotkey with results. Auto Complete Runs autocomplete for the selected items. Select Next Item Select Previous Item - Next Page - Previous Page + הדף הבא + הדף הקודם Cycle Previous Query Cycle Next Query Open Context Menu Open Native Context Menu Open Setting Window - Copy File Path + העתק את נתיב הקובץ Toggle Game Mode Toggle History Open Containing Folder - Run As Admin + הרץ כמנהל Refresh Search Results Reload Plugins Data Quick Adjust Window Width @@ -234,13 +234,13 @@ Custom Query Shortcuts Built-in Shortcuts שאילתה - Shortcut - Expansion - Description + קיצור דרך + הרחבה + תיאור מחק ערוך הוסף - None + ללא אנא בחר פריט Are you sure you want to delete {0} plugin hotkey? Are you sure you want to delete shortcut: {0} with expansion {1}? @@ -259,8 +259,8 @@ Enable HTTP Proxy HTTP Server Port - User Name - Password + שם משתמש + סיסמא Test Proxy שמור Server field can't be empty @@ -272,11 +272,11 @@ אודות - Website - GitHub - Docs - Version - Icons + אתר אינטרנט + Github + תיעוד + גרסה + סמלים You have activated Flow Launcher {0} times Check for Updates Become A Sponsor @@ -302,8 +302,8 @@ Select File Manager Please specify the file location of the file manager you using and add arguments as required. The "%d" represents the directory path to open for, used by the Arg for Folder field and for commands opening specific directories. The "%f" represents the file path to open for, used by the Arg for File field and for commands opening specific files. For example, if the file manager uses a command such as "totalcmd.exe /A c:\windows" to open the c:\windows directory, the File Manager Path will be totalcmd.exe, and the Arg For Folder will be /A "%d". Certain file managers like QTTabBar may just require a path to be supplied, in this instance use "%d" as the File Manager Path and leave the rest of the fileds blank. - File Manager - Profile Name + מנהל קבצים + שם פרופיל File Manager Path Arg For Folder Arg For File @@ -314,9 +314,9 @@ Browser Browser Name Browser Path - New Window - New Tab - Private Mode + חלון חדש + כרטיסייה חדשה + מצב פרטיות Change Priority @@ -362,14 +362,14 @@ If you add an '@' prefix while inputting a shortcut, it matches any position in שמור Overwrite ביטול - Reset + אפס מחק - OK - Yes - No + אישור + כן + לא - Version + גרסה זמן Please tell us how application crashed so we can fix it שלח דיווח @@ -377,21 +377,21 @@ If you add an '@' prefix while inputting a shortcut, it matches any position in כללי חריגים Exception Type - Source + מקור Stack Trace - Sending + שולח Report sent successfully Failed to send report Flow Launcher got an error - Please wait... + אנא המתן... Checking for new update You already have the latest Flow Launcher version - Update found - Updating... + עדכון נמצא + מעדכן... Flow Launcher was not able to move your user profile data to the new update version. Please manually move your profile data folder from {0} to {1} @@ -405,7 +405,7 @@ If you add an '@' prefix while inputting a shortcut, it matches any position in Check your connection and try updating proxy settings to github-cloud.s3.amazonaws.com. This upgrade will restart Flow Launcher Following files will be updated - Update files + עדכן קבצים Update description @@ -416,7 +416,7 @@ If you add an '@' prefix while inputting a shortcut, it matches any position in Search and run all files and applications on your PC Search everything from applications, files, bookmarks, YouTube, Twitter and more. All from the comfort of your keyboard without ever touching the mouse. Flow Launcher starts with the hotkey below, go ahead and try it out now. To change it, click on the input and press the desired hotkey on the keyboard. - Hotkeys + מקשי קיצור Action Keyword and Commands Search the web, launch applications or run various functions through Flow Launcher plugins. Certain functions start with an action keyword, and if necessary, they can be used without action keywords. Try the queries below in Flow Launcher. Let's Start Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml index 0e1753d67..f87dd7d63 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml @@ -29,8 +29,8 @@ Everything Setting Preview Panel Size - Date Created - Date Modified + תאריך יצירה + תאריך שינוי Display File Info Date and time format Sort Option: @@ -126,20 +126,20 @@ Failed to load Everything SDK אזהרה: שירות Everything אינו פועל שגיאה במהלך שאילתה לEverything - Sort By + מיין לפי Name - Path + נתיב Size Extension Type Name - Date Created - Date Modified - Attributes + תאריך יצירה + תאריך שינוי + מאפיינים File List FileName Run Count - Date Recently Changed - Date Accessed - Date Run + תאריך שינוי אחרון + תאריך גישה + תאריך הרצה Warning: This is not a Fast Sort option, searches may be slow @@ -149,11 +149,11 @@ Click to launch or install Everything Everything Installation - Installing Everything service. Please wait... - Successfully installed Everything service - Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com + מתקין את שירות Everything. אנא המתן... + שירות Everything הותקן בהצלחה + התקנה אוטומטית של שירות Everything נכשלה. אנא הורד אותו ידנית מ- https://www.voidtools.com Click here to start it - Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you + לא מצליח למצוא התקנה של Everything, האם תרצה לבחור מיקום באופן ידני?{0}{0}לחץ על לא וEverything יותקן עבורך אוטומטית Do you want to enable content search for Everything? It can be very slow without index (which is only supported in Everything v1.5+) diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx index dac5f82bc..dcc74d520 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx @@ -2130,7 +2130,7 @@ Ändern, wie der Mauszeiger ausschaut - Change power-saving settings + Energiespareinstellungen ändern Optimieren für Blindheit @@ -2143,7 +2143,7 @@ Windows-Features ein- oder ausschalten - Show which operating system your computer is running + Betriebssystem, welches auf deinem Computer läuft, anzeigen Lokale Dienste ansehen From 7fbb68f6b71cde6d1698a18471df2b175250dfc4 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Mon, 27 Jan 2025 16:45:09 +1100 Subject: [PATCH 116/259] version bump --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 421088133..af5aaefdc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.19.4.{build}' +version: '1.19.5.{build}' init: - ps: | From b9890a975662d2472bfb8844791da1310065045e Mon Sep 17 00:00:00 2001 From: Jeremy Date: Mon, 27 Jan 2025 16:48:43 +1100 Subject: [PATCH 117/259] bump plugin versions --- Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Calculator/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Explorer/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Program/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Shell/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Sys/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Url/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json index a7c230956..519141f6c 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json @@ -4,7 +4,7 @@ "Name": "Browser Bookmarks", "Description": "Search your browser bookmarks", "Author": "qianlifeng, Ioannis G.", - "Version": "3.3.3", + "Version": "3.3.4", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json index bb15cedf2..99e185928 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json @@ -4,7 +4,7 @@ "Name": "Calculator", "Description": "Provide mathematical calculations.(Try 5*3-2 in Flow Launcher)", "Author": "cxfksword", - "Version": "3.1.4", + "Version": "3.1.5", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Calculator.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index d5156fbfd..4eb6bb83b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json @@ -10,7 +10,7 @@ "Name": "Explorer", "Description": "Find and manage files and folders via Windows Search or Everything", "Author": "Jeremy Wu", - "Version": "3.2.3", + "Version": "3.2.4", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll", diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json index 3584d04a4..2b4870792 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json @@ -4,7 +4,7 @@ "Name": "Plugin Indicator", "Description": "Provides plugin action keyword suggestions", "Author": "qianlifeng", - "Version": "3.0.6", + "Version": "3.0.7", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginIndicator.dll", diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 6562b3cdf..df5a2c784 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json @@ -6,7 +6,7 @@ "Name": "Plugins Manager", "Description": "Management of installing, uninstalling or updating Flow Launcher plugins", "Author": "Jeremy Wu", - "Version": "3.2.3", + "Version": "3.2.4", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json index 882ccd029..956c4b4e1 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json @@ -4,7 +4,7 @@ "Name":"Process Killer", "Description":"Kill running processes from Flow", "Author":"Flow-Launcher", - "Version":"3.0.7", + "Version":"3.0.8", "Language":"csharp", "Website":"https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller", "IcoPath":"Images\\app.png", diff --git a/Plugins/Flow.Launcher.Plugin.Program/plugin.json b/Plugins/Flow.Launcher.Plugin.Program/plugin.json index 6c718ce45..5a95e75f4 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Program/plugin.json @@ -4,7 +4,7 @@ "Name": "Program", "Description": "Search programs in Flow.Launcher", "Author": "qianlifeng", - "Version": "3.3.3", + "Version": "3.3.4", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Program.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json index 6c81e8a26..681e8f751 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json @@ -4,7 +4,7 @@ "Name": "Shell", "Description": "Provide executing commands from Flow Launcher", "Author": "qianlifeng", - "Version": "3.2.4", + "Version": "3.2.5", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Shell.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json index 75be43587..90ca264cc 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json @@ -4,7 +4,7 @@ "Name": "System Commands", "Description": "Provide System related commands. e.g. shutdown,lock, setting etc.", "Author": "qianlifeng", - "Version": "3.1.6", + "Version": "3.1.7", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Sys.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Url/plugin.json b/Plugins/Flow.Launcher.Plugin.Url/plugin.json index cab056870..73d9bff30 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Url/plugin.json @@ -4,7 +4,7 @@ "Name": "URL", "Description": "Open the typed URL from Flow Launcher", "Author": "qianlifeng", - "Version": "3.0.7", + "Version": "3.0.8", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Url.dll", diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json index 0314ddfdb..6b6792ad3 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json @@ -26,7 +26,7 @@ "Name": "Web Searches", "Description": "Provide the web search ability", "Author": "qianlifeng", - "Version": "3.1.3", + "Version": "3.1.4", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll", diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json index 5c717827e..413a555d3 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json @@ -4,7 +4,7 @@ "Description": "Search settings inside Control Panel and Settings App", "Name": "Windows Settings", "Author": "TobiasSekan", - "Version": "4.0.11", + "Version": "4.0.12", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WindowsSettings.dll", From 9a8eabd5ee94366f3a90645bd45aa839f067afef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 22:56:19 +0000 Subject: [PATCH 118/259] Bump Microsoft.Data.Sqlite from 9.0.0 to 9.0.1 Bumps [Microsoft.Data.Sqlite](https://github.com/dotnet/efcore) from 9.0.0 to 9.0.1. - [Release notes](https://github.com/dotnet/efcore/releases) - [Commits](https://github.com/dotnet/efcore/compare/v9.0.0...v9.0.1) --- updated-dependencies: - dependency-name: Microsoft.Data.Sqlite dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Flow.Launcher.Plugin.BrowserBookmark.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index 03ac0491f..d7a626e1d 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -95,7 +95,7 @@ - + From 208e4a8c204749ac9c78ab32ed0172c7c1075b77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 22:56:59 +0000 Subject: [PATCH 119/259] Bump VirtualizingWrapPanel from 2.1.0 to 2.1.1 Bumps [VirtualizingWrapPanel](https://github.com/sbaeumlisberger/VirtualizingWrapPanel) from 2.1.0 to 2.1.1. - [Release notes](https://github.com/sbaeumlisberger/VirtualizingWrapPanel/releases) - [Commits](https://github.com/sbaeumlisberger/VirtualizingWrapPanel/compare/v2.1.0...v2.1.1) --- updated-dependencies: - dependency-name: VirtualizingWrapPanel dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Flow.Launcher/Flow.Launcher.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 788beddfb..16228258f 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -100,7 +100,7 @@ - + From 3260faba985a595b2df48c0541ebb9bef6aea88e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 31 Jan 2025 22:01:29 +0800 Subject: [PATCH 120/259] Add support for changing startup to logon task for faster startup experience --- .../UserSettings/Settings.cs | 1 + Flow.Launcher/App.xaml.cs | 2 +- Flow.Launcher/Flow.Launcher.csproj | 1 + Flow.Launcher/Helper/AutoStartup.cs | 115 +++++++++++++++++- .../SettingsPaneGeneralViewModel.cs | 34 +++++- .../Views/SettingsPaneGeneral.xaml | 7 ++ 6 files changed, 151 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index c412fb32f..81895fdcc 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -238,6 +238,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings public bool EnableUpdateLog { get; set; } public bool StartFlowLauncherOnSystemStartup { get; set; } = false; + public bool UseLogonTaskForStartup { get; set; } = false; public bool HideOnStartup { get; set; } = true; bool _hideNotifyIcon { get; set; } public bool HideNotifyIcon diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 4d1adc6cd..38f846d92 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -119,7 +119,7 @@ namespace Flow.Launcher { try { - Helper.AutoStartup.Enable(); + Helper.AutoStartup.Enable(_settings.UseLogonTaskForStartup); } catch (Exception e) { diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 788beddfb..570785be7 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -100,6 +100,7 @@ + diff --git a/Flow.Launcher/Helper/AutoStartup.cs b/Flow.Launcher/Helper/AutoStartup.cs index 4bff30caf..116520ecf 100644 --- a/Flow.Launcher/Helper/AutoStartup.cs +++ b/Flow.Launcher/Helper/AutoStartup.cs @@ -1,18 +1,31 @@ using System; +using System.IO; +using System.Linq; +using System.Security.Principal; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Microsoft.Win32; +using Microsoft.Win32.TaskScheduler; namespace Flow.Launcher.Helper; public class AutoStartup { private const string StartupPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; + private const string LogonTaskName = $"{Constant.FlowLauncher} Startup"; + private const string LogonTaskDesc = $"{Constant.FlowLauncher} Auto Startup"; public static bool IsEnabled { get { + // Check if logon task is enabled + if (CheckLogonTask()) + { + return true; + } + + // Check if registry is enabled try { using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); @@ -28,12 +41,45 @@ public class AutoStartup } } - public static void Disable() + private static bool CheckLogonTask() + { + using var taskService = new TaskService(); + var task = taskService.RootFolder.AllTasks.FirstOrDefault(t => t.Name == LogonTaskName); + if (task != null) + { + try + { + // Check if the action is the same as the current executable path + var action = task.Definition.Actions.FirstOrDefault()!.ToString().Trim(); + if (!Constant.ExecutablePath.Equals(action, StringComparison.OrdinalIgnoreCase) && !File.Exists(action)) + { + UnscheduleLogonTask(); + ScheduleLogonTask(); + } + } + catch (Exception) + { + Log.Error("AutoStartup", "Failed to check logon task"); + return false; + } + } + + return true; + } + + public static void Disable(bool logonTask) { try { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - key?.DeleteValue(Constant.FlowLauncher, false); + if (logonTask) + { + UnscheduleLogonTask(); + } + else + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + key?.DeleteValue(Constant.FlowLauncher, false); + } } catch (Exception e) { @@ -42,12 +88,19 @@ public class AutoStartup } } - internal static void Enable() + internal static void Enable(bool logonTask) { try { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\""); + if (logonTask) + { + ScheduleLogonTask(); + } + else + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\""); + } } catch (Exception e) { @@ -55,4 +108,54 @@ public class AutoStartup throw; } } + + private static bool ScheduleLogonTask() + { + using var td = TaskService.Instance.NewTask(); + td.RegistrationInfo.Description = LogonTaskDesc; + td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name, Delay = TimeSpan.FromSeconds(2) }); + td.Actions.Add(Constant.ExecutablePath); + + if (IsCurrentUserIsAdmin()) + { + td.Principal.RunLevel = TaskRunLevel.Highest; + } + + td.Settings.StopIfGoingOnBatteries = false; + td.Settings.DisallowStartIfOnBatteries = false; + td.Settings.ExecutionTimeLimit = TimeSpan.Zero; + + try + { + TaskService.Instance.RootFolder.RegisterTaskDefinition(LogonTaskName, td); + return true; + } + catch (Exception) + { + Log.Error("AutoStartup", "Failed to schedule logon task"); + return false; + } + } + + private static bool UnscheduleLogonTask() + { + using var taskService = new TaskService(); + try + { + taskService.RootFolder.DeleteTask(LogonTaskName); + return true; + } + catch (Exception) + { + Log.Error("AutoStartup", "Failed to unschedule logon task"); + return false; + } + } + + private static bool IsCurrentUserIsAdmin() + { + var identity = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(identity); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } } diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs index 3d94355e6..0aca761a0 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs @@ -42,9 +42,16 @@ public partial class SettingsPaneGeneralViewModel : BaseModel try { if (value) - AutoStartup.Enable(); + { + // Enable either registry or task scheduler + AutoStartup.Enable(UseLogonTaskForStartup); + } else - AutoStartup.Disable(); + { + // Disable both registry and task scheduler + AutoStartup.Disable(true); + AutoStartup.Disable(false); + } } catch (Exception e) { @@ -54,6 +61,29 @@ public partial class SettingsPaneGeneralViewModel : BaseModel } } + public bool UseLogonTaskForStartup + { + get => Settings.UseLogonTaskForStartup; + set + { + Settings.UseLogonTaskForStartup = value; + + if (StartFlowLauncherOnSystemStartup) + { + try + { + // Disable and enable to update the startup method + AutoStartup.Disable(!UseLogonTaskForStartup); + AutoStartup.Enable(UseLogonTaskForStartup); + } + catch (Exception e) + { + Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"), + e.Message); + } + } + } + } public List SearchWindowScreens { get; } = DropdownDataGeneric.GetValues("SearchWindowScreen"); diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 30e065b16..f57eba654 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -36,6 +36,13 @@ OnContent="{DynamicResource enable}" /> + + + + Date: Fri, 31 Jan 2025 22:06:53 +0800 Subject: [PATCH 121/259] Move string to resources --- Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/Languages/zh-cn.xaml | 8 ++++++-- Flow.Launcher/Languages/zh-tw.xaml | 8 ++++++-- Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 4c465d61f..8e8c9abef 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -46,6 +46,7 @@ Portable Mode Store all settings and user data in one folder (Useful when used with removable drives or cloud services). Start Flow Launcher on system startup + Use logon task instead of startup entry for faster startup experience Error setting launch on startup Hide Flow Launcher when focus is lost Do not show new version notifications diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml index 681c715fb..d2d1044af 100644 --- a/Flow.Launcher/Languages/zh-cn.xaml +++ b/Flow.Launcher/Languages/zh-cn.xaml @@ -1,5 +1,8 @@ - - + + Flow 检测到您已安装 {0} 个插件,需要 {1} 才能运行。是否要下载 {1}? @@ -44,6 +47,7 @@ 便携模式 将所有设置和用户数据存储在一个文件夹中 (可用于可移除驱动器或云服务)。 开机自启 + 使用登录任务而非启动项以更快自启 设置开机自启时出错 失去焦点时自动隐藏 Flow Launcher 不显示新版本提示 diff --git a/Flow.Launcher/Languages/zh-tw.xaml b/Flow.Launcher/Languages/zh-tw.xaml index 44be5257b..b5aa53377 100644 --- a/Flow.Launcher/Languages/zh-tw.xaml +++ b/Flow.Launcher/Languages/zh-tw.xaml @@ -1,5 +1,8 @@ - - + + Flow detected you have installed {0} plugins, which will require {1} to run. Would you like to download {1}? @@ -44,6 +47,7 @@ 便攜模式 將所有設定和使用者資料存儲在一個資料夾中(當與可移動磁碟或雲服務一起使用時很有用)。 開機時啟動 + 使用登錄任務而非啟動項以更快自啟 Error setting launch on startup 失去焦點時自動隱藏 Flow Launcher 不顯示新版本提示 diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index f57eba654..e52614e74 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -36,7 +36,7 @@ OnContent="{DynamicResource enable}" /> - + Date: Fri, 31 Jan 2025 22:22:00 +0800 Subject: [PATCH 122/259] Fix issue when checking logon task --- Flow.Launcher/Helper/AutoStartup.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Helper/AutoStartup.cs b/Flow.Launcher/Helper/AutoStartup.cs index 116520ecf..79466f1fb 100644 --- a/Flow.Launcher/Helper/AutoStartup.cs +++ b/Flow.Launcher/Helper/AutoStartup.cs @@ -56,15 +56,16 @@ public class AutoStartup UnscheduleLogonTask(); ScheduleLogonTask(); } + + return true; } catch (Exception) { Log.Error("AutoStartup", "Failed to check logon task"); - return false; } } - return true; + return false; } public static void Disable(bool logonTask) From e320ca1d492594351d81f05ab3da8838c8672dd6 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 1 Feb 2025 13:10:32 +0800 Subject: [PATCH 123/259] Add support for deleting plugin settings when uninstalling plugins --- Flow.Launcher.Core/Plugin/PluginManager.cs | 21 +++++++++++++++---- .../Languages/en.xaml | 6 ++++-- .../Languages/zh-cn.xaml | 6 ++++-- .../Languages/zh-tw.xaml | 6 ++++-- .../PluginsManager.cs | 6 +++++- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 5c4eaa1da..55bc0e2bd 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -14,6 +14,7 @@ using ISavable = Flow.Launcher.Plugin.ISavable; using Flow.Launcher.Plugin.SharedCommands; using System.Text.Json; using Flow.Launcher.Core.Resource; +using Flow.Launcher.Infrastructure.Storage; namespace Flow.Launcher.Core.Plugin { @@ -439,7 +440,7 @@ namespace Flow.Launcher.Core.Plugin public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath) { InstallPlugin(newVersion, zipFilePath, checkModified:false); - UninstallPlugin(existingVersion, removeSettings:false, checkModified:false); + UninstallPlugin(existingVersion, removeSettings:false, removePluginSettings:false, checkModified: false); _modifiedPlugins.Add(existingVersion.ID); } @@ -454,9 +455,9 @@ namespace Flow.Launcher.Core.Plugin /// /// Uninstall a plugin. /// - public static void UninstallPlugin(PluginMetadata plugin, bool removeSettings = true) + public static void UninstallPlugin(PluginMetadata plugin, bool removeSettings = true, bool removePluginSettings = false) { - UninstallPlugin(plugin, removeSettings, true); + UninstallPlugin(plugin, removeSettings, removePluginSettings, true); } #endregion @@ -529,7 +530,7 @@ namespace Flow.Launcher.Core.Plugin } } - internal static void UninstallPlugin(PluginMetadata plugin, bool removeSettings, bool checkModified) + internal static void UninstallPlugin(PluginMetadata plugin, bool removeSettings, bool removePluginSettings, bool checkModified) { if (checkModified && PluginModified(plugin.ID)) { @@ -542,6 +543,18 @@ namespace Flow.Launcher.Core.Plugin AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID); } + if (removePluginSettings) + { + var assemblyLoader = new PluginAssemblyLoader(plugin.ExecuteFilePath); + var assembly = assemblyLoader.LoadAssemblyAndDependencies(); + var assemblyName = assembly.GetName().Name; + var directoryPath = Path.Combine(DataLocation.DataDirectory(), JsonStorage.DirectoryName, Constant.Plugins, assemblyName); + if (Directory.Exists(directoryPath)) + { + Directory.Delete(directoryPath, true); + } + } + // Marked for deletion. Will be deleted on next start up using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index de6a3a2fb..573ca9051 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -15,6 +15,8 @@ Installing Plugin Download and install {0} Plugin Uninstall + Keep plugin settings + Do you want to keep the settings of the plugin for the next usage? Plugin {0} successfully installed. Restarting Flow, please wait... Unable to find the plugin.json metadata file from the extracted zip file. Error: A plugin which has the same or greater version with {0} already exists. @@ -37,13 +39,13 @@ Plugin {0} successfully updated. Restarting Flow, please wait... Installing from an unknown source You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings) - + Plugin {0} successfully installed. Please restart Flow. Plugin {0} successfully uninstalled. Please restart Flow. Plugin {0} successfully updated. Please restart Flow. {0} plugins successfully updated. Please restart Flow. Plugin {0} has already been modified. Please restart Flow before making any further changes. - + Plugins Manager Management of installing, uninstalling or updating Flow Launcher plugins diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml index 676c20a73..033bfed94 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml @@ -13,6 +13,8 @@ 正在安装插件 下载与安装 {0} 插件卸载 + 保留插件设置 + 你希望保留插件设置以便于下次使用吗? 插件安装成功。正在重新启动 Flow Launcher,请稍候... 安装失败:无法从新插件中找到plugin.json元数据文件 错误:具有相同或更高版本的 {0} 的插件已经存在。 @@ -35,13 +37,13 @@ 插件{0}更新成功。正在重新启动 Flow Launcher,请稍候... 从未知源安装 您正在从未知源安装此插件,它可能包含潜在风险!{0}{0}请确保您了解来源以及安全性。{0}{0}您想要继续吗?{0}{0}(您可以通过设置关闭此警告) - + 成功安装插件{0}。请重新启动 Flow Launcher。 成功卸载插件{0}。请重新启动 Flow Launcher。 成功更新插件{0}。请重新启动 Flow Launcher。 插件 {0} 更新成功。请重新启动 Flow Launcher。 插件 {0} 已被修改。请在进行任何进一步更改之前重新启动Flow。 - + 插件管理 安装,卸载或更新 Flow Launcher 插件 diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml index ae37579dc..c2497b70b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml @@ -13,6 +13,8 @@ Installing Plugin 下載並安裝 {0} 解除安裝擴充功能 + 保留插件設置 + 你希望保留插件設置以便於下次使用嗎? 外掛安裝成功。正在重啟 Flow,請稍後... Unable to find the plugin.json metadata file from the extracted zip file. Error: A plugin which has the same or greater version with {0} already exists. @@ -35,13 +37,13 @@ Plugin {0} successfully updated. Restarting Flow, please wait... Installing from an unknown source You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings) - + Plugin {0} successfully installed. Please restart Flow. Plugin {0} successfully uninstalled. Please restart Flow. Plugin {0} successfully updated. Please restart Flow. {0} plugins successfully updated. Please restart Flow. Plugin {0} has already been modified. Please restart Flow before making any further changes. - + 擴充功能管理 Management of installing, uninstalling or updating Flow Launcher plugins diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 305d248d3..fe3b9d3f2 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -682,7 +682,11 @@ namespace Flow.Launcher.Plugin.PluginsManager { try { - PluginManager.UninstallPlugin(plugin, removeSettings: true); + var removePluginSettings = Context.API.ShowMsgBox( + Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_subtitle"), + Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_title"), + button: MessageBoxButton.YesNo) == MessageBoxResult.No; + PluginManager.UninstallPlugin(plugin, removeSettings: true, removePluginSettings: removePluginSettings); } catch (ArgumentException e) { From bb7900c0e0da0f9a3eefbaa953c19e98cb9c06f6 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 2 Feb 2025 15:27:02 +0600 Subject: [PATCH 124/259] Add PyWin32-related directories to path for Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 4 ++++ Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 7b670742a..e40b0330e 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -58,6 +58,8 @@ namespace Flow.Launcher.Core.Plugin { var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; var libDirectory = Path.Combine(rootDirectory, "lib"); + var libPyWin32Directory = Path.Combine(libDirectory, "win32"); + var libPyWin32LibDirectory = Path.Combine(libPyWin32Directory, "lib"); var pluginDirectory = Path.Combine(rootDirectory, "plugin"); // This makes it easier for plugin authors to import their own modules. @@ -70,6 +72,8 @@ namespace Flow.Launcher.Core.Plugin import sys sys.path.append(r'{rootDirectory}') sys.path.append(r'{libDirectory}') + sys.path.append(r'{libPyWin32LibDirectory}') + sys.path.append(r'{libPyWin32Directory}') sys.path.append(r'{pluginDirectory}') import runpy diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 03ac0e661..8a9e1ff44 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -36,6 +36,8 @@ namespace Flow.Launcher.Core.Plugin { var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; var libDirectory = Path.Combine(rootDirectory, "lib"); + var libPyWin32Directory = Path.Combine(libDirectory, "win32"); + var libPyWin32LibDirectory = Path.Combine(libPyWin32Directory, "lib"); var pluginDirectory = Path.Combine(rootDirectory, "plugin"); var filePath = context.CurrentPluginMetadata.ExecuteFilePath; @@ -49,6 +51,8 @@ namespace Flow.Launcher.Core.Plugin import sys sys.path.append(r'{rootDirectory}') sys.path.append(r'{libDirectory}') + sys.path.append(r'{libPyWin32LibDirectory}') + sys.path.append(r'{libPyWin32Directory}') sys.path.append(r'{pluginDirectory}') import runpy From f708ad9ffdb823282e522b31608289e68beefcd2 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Tue, 4 Feb 2025 23:18:21 +0100 Subject: [PATCH 125/259] Add Windows Terminal to Shell Plugin --- Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 27 +++++++++++++++++++ .../Flow.Launcher.Plugin.Shell/Settings.cs | 2 ++ .../ShellSetting.xaml | 4 ++- .../ShellSetting.xaml.cs | 4 +++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index 921c6bc21..a192b8900 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -279,6 +279,33 @@ namespace Flow.Launcher.Plugin.Shell break; } + case Shell.TerminalPWSH: + { + info.filename = "wt.exe" + info.ArgumentList.Add("pwsh"); + if (_settings.LeaveShellOpen) + { + info.ArgumentList.Add("-NoExit"); + } + info.ArgumentList.Add("-Command"); + info.ArgumentList.Add(command); + break; + } + case Shell.TerminalCMD: + { + info.filename = "wt.exe" + info.ArgumentList.Add("cmd"); + if (_settings.LeaveShellOpen) + { + info.ArgumentList.Add("/k"); + } + else + { + info.ArgumentList.Add("/c"); + } + info.ArgumentList.Add(command); + break; + } default: throw new NotImplementedException(); } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs index 6f47d5d17..75cc56618 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs @@ -39,5 +39,7 @@ namespace Flow.Launcher.Plugin.Shell Powershell = 1, RunCommand = 2, Pwsh = 3, + TerminalPWSH = 4, + TerminalCMD = 5, } } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml index 2f02ef723..22f4ff22d 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml @@ -43,12 +43,14 @@ Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}" /> CMD PowerShell Pwsh + Terminal (Pwsh) + Terminal (CMD) RunCommand diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs index 24365f2aa..e981f8b74 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs @@ -91,6 +91,8 @@ namespace Flow.Launcher.Plugin.Shell Shell.Cmd => 0, Shell.Powershell => 1, Shell.Pwsh => 2, + Shell.TerminalPWSH = 3, + Shell.TerminalCMD = 4, _ => ShellComboBox.Items.Count - 1 }; @@ -101,6 +103,8 @@ namespace Flow.Launcher.Plugin.Shell 0 => Shell.Cmd, 1 => Shell.Powershell, 2 => Shell.Pwsh, + 3 => Shell.TerminalPWSH, + 4 => Shell.TerminalCMD, _ => Shell.RunCommand }; LeaveShellOpen.IsEnabled = _settings.Shell != Shell.RunCommand; From ff2f0c375cd90ff721739cdc68e406b4ecdae4d3 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Tue, 4 Feb 2025 23:39:29 +0100 Subject: [PATCH 126/259] Fix typos --- Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 4 ++-- Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index a192b8900..60c8ba1a8 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -281,7 +281,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalPWSH: { - info.filename = "wt.exe" + info.filename = "wt.exe"; info.ArgumentList.Add("pwsh"); if (_settings.LeaveShellOpen) { @@ -293,7 +293,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalCMD: { - info.filename = "wt.exe" + info.filename = "wt.exe"; info.ArgumentList.Add("cmd"); if (_settings.LeaveShellOpen) { diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs index e981f8b74..eaac8731a 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs @@ -91,8 +91,8 @@ namespace Flow.Launcher.Plugin.Shell Shell.Cmd => 0, Shell.Powershell => 1, Shell.Pwsh => 2, - Shell.TerminalPWSH = 3, - Shell.TerminalCMD = 4, + Shell.TerminalPWSH => 3, + Shell.TerminalCMD => 4, _ => ShellComboBox.Items.Count - 1 }; From 3596a77b343bd0a0332a7cde43228bb9affcaaa3 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Tue, 4 Feb 2025 23:54:04 +0100 Subject: [PATCH 127/259] Fix the rest of my mistakes --- Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 4 ++-- Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index 60c8ba1a8..fc8746e41 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -281,7 +281,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalPWSH: { - info.filename = "wt.exe"; + info.FileName = "wt.exe"; info.ArgumentList.Add("pwsh"); if (_settings.LeaveShellOpen) { @@ -293,7 +293,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalCMD: { - info.filename = "wt.exe"; + info.FileName = "wt.exe"; info.ArgumentList.Add("cmd"); if (_settings.LeaveShellOpen) { diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml index 22f4ff22d..7e35a872f 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml @@ -43,7 +43,7 @@ Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}" /> CMD From 5bb3d724c026e7cc2bd8b22079cd4e94173f14e1 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Thu, 6 Feb 2025 00:22:41 +0100 Subject: [PATCH 128/259] Use a checkbox instead of separate entries --- .../Languages/en.xaml | 3 +- .../Languages/es-419.xaml | 1 + .../Languages/es.xaml | 1 + Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 77 ++++++++----------- .../Flow.Launcher.Plugin.Shell/Settings.cs | 4 +- .../ShellSetting.xaml | 13 +++- .../ShellSetting.xaml.cs | 16 +++- 7 files changed, 57 insertions(+), 58 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml index 52aaf3c27..645a0e14f 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml @@ -7,6 +7,7 @@ Press any key to close this window... Do not close Command Prompt after command execution Always run as administrator + Use Windows Terminal Run as different user Shell Allows to execute system commands from Flow Launcher @@ -15,4 +16,4 @@ Run As Administrator Copy the command Only show number of most used commands: - \ No newline at end of file + diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml index 5ee2c43b4..f3ef0df0a 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml @@ -6,6 +6,7 @@ Press any key to close this window... No cerrar Símbolo del Sistema tras ejecutar el comando Siempre ejecutar como administrador + Ejecutar en la Terminal de Windows Ejecutar como otro usuario Shell Allows to execute system commands from Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml index a3ee35ef8..ee3193b16 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml @@ -6,6 +6,7 @@ Pulsar cualquier tecla para cerrar esta ventana... No cerrar el símbolo del sistema después de la ejecución del comando Ejecutar siempre como administrador + Ejecutar en la Terminal de Windows Ejecutar como usuario diferente Terminal Permite ejecutar comandos del sistema desde Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index fc8746e41..7f1f4bd4d 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -202,28 +202,31 @@ namespace Flow.Launcher.Plugin.Shell { case Shell.Cmd: { - info.FileName = "cmd.exe"; - info.Arguments = $"{(_settings.LeaveShellOpen ? "/k" : "/c")} {command} {(_settings.CloseShellAfterPress ? $"&& echo {context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")} && pause > nul /c" : "")}"; - - //// Use info.Arguments instead of info.ArgumentList to enable users better control over the arguments they are writing. - //// Previous code using ArgumentList, commands needed to be separated correctly: - //// Incorrect: - // info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c"); - // info.ArgumentList.Add(command); //<== info.ArgumentList.Add("mkdir \"c:\\test new\""); - - //// Correct version should be: - //info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c"); - //info.ArgumentList.Add("mkdir"); - //info.ArgumentList.Add(@"c:\test new"); - - //https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0#remarks + if (_settings.UseWindowsTerminal) + { + info.FileName = "wt.exe"; + info.ArgumentList.Add("cmd"); + } + else + { + info.FileName = "cmd.exe"; + } + info.ArgumentList.Add($"{(_settings.LeaveShellOpen ? "/k" : "/c")} {command} {(_settings.CloseShellAfterPress ? $"&& echo {context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")} && pause > nul /c" : "")}"); break; } case Shell.Powershell: { - info.FileName = "powershell.exe"; + if (_settings.UseWindowsTerminal) + { + info.FileName = "wt.exe"; + info.ArgumentList.Add("powershell"); + } + else + { + info.FileName = "powershell.exe"; + } if (_settings.LeaveShellOpen) { info.ArgumentList.Add("-NoExit"); @@ -232,21 +235,28 @@ namespace Flow.Launcher.Plugin.Shell else { info.ArgumentList.Add("-Command"); - info.ArgumentList.Add($"{command}; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'; [System.Console]::ReadKey(); exit" : "")}"); + info.ArgumentList.Add($"{command}\\; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'\\; [System.Console]::ReadKey()\\; exit" : "")}"); } break; } case Shell.Pwsh: { - info.FileName = "pwsh.exe"; + if (_settings.UseWindowsTerminal) + { + info.FileName = "wt.exe"; + info.ArgumentList.Add("pwsh"); + } + else + { + info.FileName = "pwsh.exe"; + } if (_settings.LeaveShellOpen) { info.ArgumentList.Add("-NoExit"); } info.ArgumentList.Add("-Command"); - info.ArgumentList.Add($"{command}; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'; [System.Console]::ReadKey(); exit" : "")}"); - + info.ArgumentList.Add($"{command}\\; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'\\; [System.Console]::ReadKey()\\; exit" : "")}"); break; } @@ -279,33 +289,6 @@ namespace Flow.Launcher.Plugin.Shell break; } - case Shell.TerminalPWSH: - { - info.FileName = "wt.exe"; - info.ArgumentList.Add("pwsh"); - if (_settings.LeaveShellOpen) - { - info.ArgumentList.Add("-NoExit"); - } - info.ArgumentList.Add("-Command"); - info.ArgumentList.Add(command); - break; - } - case Shell.TerminalCMD: - { - info.FileName = "wt.exe"; - info.ArgumentList.Add("cmd"); - if (_settings.LeaveShellOpen) - { - info.ArgumentList.Add("/k"); - } - else - { - info.ArgumentList.Add("/c"); - } - info.ArgumentList.Add(command); - break; - } default: throw new NotImplementedException(); } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs index 75cc56618..9ce2293a2 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs @@ -14,6 +14,8 @@ namespace Flow.Launcher.Plugin.Shell public bool RunAsAdministrator { get; set; } = true; + public bool UseWindowsTerminal { get; set; } = false; + public bool ShowOnlyMostUsedCMDs { get; set; } public int ShowOnlyMostUsedCMDsNumber { get; set; } @@ -39,7 +41,5 @@ namespace Flow.Launcher.Plugin.Shell Powershell = 1, RunCommand = 2, Pwsh = 3, - TerminalPWSH = 4, - TerminalCMD = 5, } } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml index 7e35a872f..8a3b7f115 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml @@ -16,6 +16,7 @@ + + CMD PowerShell Pwsh - Terminal (Pwsh) - Terminal (CMD) RunCommand - + + { + _settings.UseWindowsTerminal = true; + }; + + UseWindowsTerminal.Unchecked += (o, e) => + { + _settings.UseWindowsTerminal = false; + }; + ReplaceWinR.Checked += (o, e) => { _settings.ReplaceWinR = true; @@ -91,8 +103,6 @@ namespace Flow.Launcher.Plugin.Shell Shell.Cmd => 0, Shell.Powershell => 1, Shell.Pwsh => 2, - Shell.TerminalPWSH => 3, - Shell.TerminalCMD => 4, _ => ShellComboBox.Items.Count - 1 }; @@ -103,8 +113,6 @@ namespace Flow.Launcher.Plugin.Shell 0 => Shell.Cmd, 1 => Shell.Powershell, 2 => Shell.Pwsh, - 3 => Shell.TerminalPWSH, - 4 => Shell.TerminalCMD, _ => Shell.RunCommand }; LeaveShellOpen.IsEnabled = _settings.Shell != Shell.RunCommand; From 0e02a6f9cff393b1cfa7bec5bb70e1f60e87127a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 6 Feb 2025 07:51:44 +0800 Subject: [PATCH 129/259] Revert changes in non-English language files --- .../Languages/zh-cn.xaml | 9 +++++---- .../Languages/zh-tw.xaml | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml index 033bfed94..e6be9069d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml @@ -1,5 +1,8 @@ - - + + 正在下载插件... @@ -13,8 +16,6 @@ 正在安装插件 下载与安装 {0} 插件卸载 - 保留插件设置 - 你希望保留插件设置以便于下次使用吗? 插件安装成功。正在重新启动 Flow Launcher,请稍候... 安装失败:无法从新插件中找到plugin.json元数据文件 错误:具有相同或更高版本的 {0} 的插件已经存在。 diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml index c2497b70b..9736728a7 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml @@ -1,5 +1,8 @@ - - + + 正在下載擴充功能 @@ -13,8 +16,6 @@ Installing Plugin 下載並安裝 {0} 解除安裝擴充功能 - 保留插件設置 - 你希望保留插件設置以便於下次使用嗎? 外掛安裝成功。正在重啟 Flow,請稍後... Unable to find the plugin.json metadata file from the extracted zip file. Error: A plugin which has the same or greater version with {0} already exists. From 71b79da5d433c10de38241682245add9b6858359 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 6 Feb 2025 07:53:40 +0800 Subject: [PATCH 130/259] Revert auto format --- .../Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml | 5 +---- .../Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml index e6be9069d..f73516a56 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml @@ -1,8 +1,5 @@  - + 正在下载插件... diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml index 9736728a7..f1b044d25 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml @@ -1,8 +1,5 @@  - + 正在下載擴充功能 From 1ff8c3620a030294a6d30d9ae2e93ac14438457a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 6 Feb 2025 07:56:24 +0800 Subject: [PATCH 131/259] Revert changes in non-English language files --- Flow.Launcher/Languages/zh-cn.xaml | 8 ++------ Flow.Launcher/Languages/zh-tw.xaml | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml index d2d1044af..681c715fb 100644 --- a/Flow.Launcher/Languages/zh-cn.xaml +++ b/Flow.Launcher/Languages/zh-cn.xaml @@ -1,8 +1,5 @@ - - + + Flow 检测到您已安装 {0} 个插件,需要 {1} 才能运行。是否要下载 {1}? @@ -47,7 +44,6 @@ 便携模式 将所有设置和用户数据存储在一个文件夹中 (可用于可移除驱动器或云服务)。 开机自启 - 使用登录任务而非启动项以更快自启 设置开机自启时出错 失去焦点时自动隐藏 Flow Launcher 不显示新版本提示 diff --git a/Flow.Launcher/Languages/zh-tw.xaml b/Flow.Launcher/Languages/zh-tw.xaml index b5aa53377..44be5257b 100644 --- a/Flow.Launcher/Languages/zh-tw.xaml +++ b/Flow.Launcher/Languages/zh-tw.xaml @@ -1,8 +1,5 @@ - - + + Flow detected you have installed {0} plugins, which will require {1} to run. Would you like to download {1}? @@ -47,7 +44,6 @@ 便攜模式 將所有設定和使用者資料存儲在一個資料夾中(當與可移動磁碟或雲服務一起使用時很有用)。 開機時啟動 - 使用登錄任務而非啟動項以更快自啟 Error setting launch on startup 失去焦點時自動隱藏 Flow Launcher 不顯示新版本提示 From 7598a6aff507cfff363d94b9f225fa7f6955039e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 6 Feb 2025 08:08:45 +0800 Subject: [PATCH 132/259] Revert auto format --- .../Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml | 2 +- .../Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml index f73516a56..28196e55f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml @@ -1,4 +1,4 @@ - + diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml index f1b044d25..96155f440 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml @@ -1,4 +1,4 @@ - + From 1f1b31994da4ab774e9c0964de342e7129c958d8 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 6 Feb 2025 09:35:21 +0800 Subject: [PATCH 133/259] Improve argument name to avoid possible confusion --- Flow.Launcher.Core/Plugin/PluginManager.cs | 10 +++++----- .../PluginsManager.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 55bc0e2bd..fc915bcb3 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -440,7 +440,7 @@ namespace Flow.Launcher.Core.Plugin public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath) { InstallPlugin(newVersion, zipFilePath, checkModified:false); - UninstallPlugin(existingVersion, removeSettings:false, removePluginSettings:false, checkModified: false); + UninstallPlugin(existingVersion, removePluginFromSettings:false, removePluginSettings:false, checkModified: false); _modifiedPlugins.Add(existingVersion.ID); } @@ -455,9 +455,9 @@ namespace Flow.Launcher.Core.Plugin /// /// Uninstall a plugin. /// - public static void UninstallPlugin(PluginMetadata plugin, bool removeSettings = true, bool removePluginSettings = false) + public static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings = true, bool removePluginSettings = false) { - UninstallPlugin(plugin, removeSettings, removePluginSettings, true); + UninstallPlugin(plugin, removePluginFromSettings, removePluginSettings, true); } #endregion @@ -530,14 +530,14 @@ namespace Flow.Launcher.Core.Plugin } } - internal static void UninstallPlugin(PluginMetadata plugin, bool removeSettings, bool removePluginSettings, bool checkModified) + internal static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings, bool removePluginSettings, bool checkModified) { if (checkModified && PluginModified(plugin.ID)) { throw new ArgumentException($"Plugin {plugin.Name} has been modified"); } - if (removeSettings) + if (removePluginFromSettings) { Settings.Plugins.Remove(plugin.ID); AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index fe3b9d3f2..ac4f90d92 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -686,7 +686,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_subtitle"), Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_title"), button: MessageBoxButton.YesNo) == MessageBoxResult.No; - PluginManager.UninstallPlugin(plugin, removeSettings: true, removePluginSettings: removePluginSettings); + PluginManager.UninstallPlugin(plugin, removePluginFromSettings: true, removePluginSettings: removePluginSettings); } catch (ArgumentException e) { From 69bf7c6b63ff3988e583508583e7543ed1956b2e Mon Sep 17 00:00:00 2001 From: cibere <71997063+cibere@users.noreply.github.com> Date: Thu, 6 Feb 2025 18:34:44 -0800 Subject: [PATCH 134/259] add BackToQueryResults to JsonRPCPublicAPI --- .../Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs b/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs index b8bfee591..2d49e4840 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs @@ -173,5 +173,10 @@ namespace Flow.Launcher.Core.Plugin.JsonRPCV2Models { _api.OpenAppUri(appUri); } + + public void BackToQueryResults() + { + _api.BackToQueryResults(); + } } } From 646bad6deba7d2c7ac671c21d8f85330e78b8911 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 7 Feb 2025 14:15:01 +0800 Subject: [PATCH 135/259] Use parameter for function for readability --- .../PluginsManager.cs | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index ce51e8700..671489846 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -148,7 +148,7 @@ namespace Flow.Launcher.Plugin.PluginsManager if (!plugin.IsFromLocalInstallPath) { - await DeleteFileAndDownloadMsgBoxAsync( + await DownloadFileAsync( $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.Name}", plugin.UrlDownload, filePath, cts); } @@ -199,32 +199,39 @@ namespace Flow.Launcher.Plugin.PluginsManager } } - private async Task DeleteFileAndDownloadMsgBoxAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts) + private async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true) { - if (File.Exists(filePath)) + if (deleteFile && File.Exists(filePath)) File.Delete(filePath); - var exceptionHappened = false; - await Context.API.ShowProgressBoxAsync(prgBoxTitle, - async (reportProgress) => - { - if (reportProgress == null) + if (showProgress) + { + var exceptionHappened = false; + await Context.API.ShowProgressBoxAsync(prgBoxTitle, + async (reportProgress) => { - // when reportProgress is null, it means there is expcetion with the progress box - // so we record it with exceptionHappened and return so that progress box will close instantly - exceptionHappened = true; - return; - } - else - { - await Context.API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false); - } - }, cts.Cancel); + if (reportProgress == null) + { + // when reportProgress is null, it means there is expcetion with the progress box + // so we record it with exceptionHappened and return so that progress box will close instantly + exceptionHappened = true; + return; + } + else + { + await Context.API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false); + } + }, cts.Cancel); - // if exception happened while downloading and user does not cancel downloading, - // we need to redownload the plugin - if (exceptionHappened && (!cts.IsCancellationRequested)) - await Context.API.HttpDownloadAsync(downloadUrl, filePath).ConfigureAwait(false); + // if exception happened while downloading and user does not cancel downloading, + // we need to redownload the plugin + if (exceptionHappened && (!cts.IsCancellationRequested)) + await Context.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); + } + else + { + await Context.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); + } } internal async ValueTask> RequestUpdateAsync(string search, CancellationToken token, @@ -318,7 +325,7 @@ namespace Flow.Launcher.Plugin.PluginsManager if (!x.PluginNewUserPlugin.IsFromLocalInstallPath) { - await DeleteFileAndDownloadMsgBoxAsync( + await DownloadFileAsync( $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {x.PluginNewUserPlugin.Name}", x.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts); } @@ -418,7 +425,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { using var cts = new CancellationTokenSource(); - await DeleteFileAndDownloadMsgBoxAsync( + await DownloadFileAsync( $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.PluginNewUserPlugin.Name}", plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts); From a3cc5e25f9e8cad6cde6a7360a10da2400589f10 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 7 Feb 2025 16:05:35 +0800 Subject: [PATCH 136/259] Fix unix directory seperator issue --- Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs | 2 ++ .../Search/DirectoryInfo/DirectoryInfoSearch.cs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs index e7b43c555..bc1fb8e7a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs @@ -31,6 +31,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal const string DefaultContentSearchActionKeyword = "doc:"; + internal const char UnixDirectorySeparator = '/'; + internal const char DirectorySeparator = '\\'; internal const string WindowsIndexingOptions = "srchadmin.dll"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs index 9fd495f49..e3e1c62e6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Plugin.SharedCommands; using System; using System.Collections.Generic; @@ -12,6 +12,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo { internal static IEnumerable TopLevelDirectorySearch(Query query, string search, CancellationToken token) { + // if user uses the unix directory separator, we need to convert it to windows directory separator + search = search.Replace(Constants.UnixDirectorySeparator, Constants.DirectorySeparator); + var criteria = ConstructSearchCriteria(search); if (search.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > From 3ee3528e5433c6da1f6f1c37095e92c8ec9153ba Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 7 Feb 2025 16:40:45 +0800 Subject: [PATCH 137/259] Revert "Fix unix directory seperator issue" This reverts commit a3cc5e25f9e8cad6cde6a7360a10da2400589f10. --- Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs | 2 -- .../Search/DirectoryInfo/DirectoryInfoSearch.cs | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs index bc1fb8e7a..e7b43c555 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs @@ -31,8 +31,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal const string DefaultContentSearchActionKeyword = "doc:"; - internal const char UnixDirectorySeparator = '/'; - internal const char DirectorySeparator = '\\'; internal const string WindowsIndexingOptions = "srchadmin.dll"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs index e3e1c62e6..9fd495f49 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Plugin.SharedCommands; using System; using System.Collections.Generic; @@ -12,9 +12,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo { internal static IEnumerable TopLevelDirectorySearch(Query query, string search, CancellationToken token) { - // if user uses the unix directory separator, we need to convert it to windows directory separator - search = search.Replace(Constants.UnixDirectorySeparator, Constants.DirectorySeparator); - var criteria = ConstructSearchCriteria(search); if (search.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > From 5ee110b3b741b310bfebffc4edbf5b371c0f5db4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 7 Feb 2025 16:42:01 +0800 Subject: [PATCH 138/259] Fix unix directory seperator issue --- Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs | 3 ++- Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs index e7b43c555..4bddfd9b2 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs @@ -22,7 +22,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal const string WindowsIndexErrorImagePath = "Images\\index_error2.png"; internal const string GeneralSearchErrorImagePath = "Images\\robot_error.png"; - internal const string ToolTipOpenDirectory = "Ctrl + Enter to open the directory"; internal const string ToolTipOpenContainingFolder = "Ctrl + Enter to open the containing folder"; @@ -31,6 +30,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal const string DefaultContentSearchActionKeyword = "doc:"; + internal const char UnixDirectorySeparator = '/'; + internal const char DirectorySeparator = '\\'; internal const string WindowsIndexingOptions = "srchadmin.dll"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 8fd167476..12df6c145 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -187,6 +187,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search var needToExpand = EnvironmentVariables.HasEnvironmentVar(querySearch); var path = needToExpand ? Environment.ExpandEnvironmentVariables(querySearch) : querySearch; + // if user uses the unix directory separator, we need to convert it to windows directory separator + path = path.Replace(Constants.UnixDirectorySeparator, Constants.DirectorySeparator); + // Check that actual location exists, otherwise directory search will throw directory not found exception if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path).LocationExists()) return results.ToList(); From 1a39af35e20730667960f7af5422ae877de0d679 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 7 Feb 2025 20:23:53 +0800 Subject: [PATCH 139/259] Fix main window resize boarder thickness issue --- Flow.Launcher.Core/Resource/Theme.cs | 35 +++++++++++++++++++++++++++- Flow.Launcher/MainWindow.xaml | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 1d8409306..2c2feeae1 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -11,6 +11,7 @@ using System.Windows.Media.Effects; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using System.Windows.Shell; namespace Flow.Launcher.Core.Resource { @@ -306,12 +307,15 @@ namespace Flow.Launcher.Core.Resource var marginSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) as Setter; if (marginSetter == null) { + var margin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin); marginSetter = new Setter() { Property = Border.MarginProperty, - Value = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin), + Value = margin, }; windowBorderStyle.Setters.Add(marginSetter); + + SetResizeBoarderThickness(margin); } else { @@ -322,6 +326,8 @@ namespace Flow.Launcher.Core.Resource baseMargin.Right + ShadowExtraMargin, baseMargin.Bottom + ShadowExtraMargin); marginSetter.Value = newMargin; + + SetResizeBoarderThickness(newMargin); } windowBorderStyle.Setters.Add(effectSetter); @@ -352,9 +358,36 @@ namespace Flow.Launcher.Core.Resource marginSetter.Value = newMargin; } + SetResizeBoarderThickness(null); + UpdateResourceDictionary(dict); } + // because adding drop shadow effect will change the margin of the window, + // we need to update the window chrome thickness to correct set the resize border + private static void SetResizeBoarderThickness(Thickness? effectMargin) + { + var window = Application.Current.MainWindow; + if (WindowChrome.GetWindowChrome(window) is WindowChrome windowChrome) + { + Thickness thickness; + if (effectMargin == null) + { + thickness = SystemParameters.WindowResizeBorderThickness; + } + else + { + thickness = new Thickness( + effectMargin.Value.Left + SystemParameters.WindowResizeBorderThickness.Left, + effectMargin.Value.Top + SystemParameters.WindowResizeBorderThickness.Top, + effectMargin.Value.Right + SystemParameters.WindowResizeBorderThickness.Right, + effectMargin.Value.Bottom + SystemParameters.WindowResizeBorderThickness.Bottom); + } + + windowChrome.ResizeBorderThickness = thickness; + } + } + public record ThemeData(string FileNameWithoutExtension, string Name, bool? IsDark = null, bool? HasBlur = null); } } diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index f5fd729d4..4cc887c41 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -37,7 +37,7 @@ mc:Ignorable="d"> - + From 0e4cf57e9e29c401a4ff82052b128f5ebe7865b6 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 8 Feb 2025 11:57:29 +0800 Subject: [PATCH 140/259] Revert blank lines --- .../Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml | 4 ++-- .../Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml index 28196e55f..676c20a73 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml @@ -35,13 +35,13 @@ 插件{0}更新成功。正在重新启动 Flow Launcher,请稍候... 从未知源安装 您正在从未知源安装此插件,它可能包含潜在风险!{0}{0}请确保您了解来源以及安全性。{0}{0}您想要继续吗?{0}{0}(您可以通过设置关闭此警告) - + 成功安装插件{0}。请重新启动 Flow Launcher。 成功卸载插件{0}。请重新启动 Flow Launcher。 成功更新插件{0}。请重新启动 Flow Launcher。 插件 {0} 更新成功。请重新启动 Flow Launcher。 插件 {0} 已被修改。请在进行任何进一步更改之前重新启动Flow。 - + 插件管理 安装,卸载或更新 Flow Launcher 插件 diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml index 96155f440..ae37579dc 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml @@ -35,13 +35,13 @@ Plugin {0} successfully updated. Restarting Flow, please wait... Installing from an unknown source You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings) - + Plugin {0} successfully installed. Please restart Flow. Plugin {0} successfully uninstalled. Please restart Flow. Plugin {0} successfully updated. Please restart Flow. {0} plugins successfully updated. Please restart Flow. Plugin {0} has already been modified. Please restart Flow before making any further changes. - + 擴充功能管理 Management of installing, uninstalling or updating Flow Launcher plugins From f0e74a2aa545a74591c62fcd3e67c45faeff4a75 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 8 Feb 2025 19:12:53 +0800 Subject: [PATCH 141/259] Fix issue that plugin manager will save settings for the uninstalled and settings-removed plugins --- Flow.Launcher.Core/Plugin/PluginManager.cs | 14 ++++++++++---- .../Storage/PluginJsonStorage.cs | 18 ++++++++++++++---- Flow.Launcher/PublicAPIInstance.cs | 17 +++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index fc915bcb3..146718b93 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -14,7 +14,6 @@ using ISavable = Flow.Launcher.Plugin.ISavable; using Flow.Launcher.Plugin.SharedCommands; using System.Text.Json; using Flow.Launcher.Core.Resource; -using Flow.Launcher.Infrastructure.Storage; namespace Flow.Launcher.Core.Plugin { @@ -548,10 +547,17 @@ namespace Flow.Launcher.Core.Plugin var assemblyLoader = new PluginAssemblyLoader(plugin.ExecuteFilePath); var assembly = assemblyLoader.LoadAssemblyAndDependencies(); var assemblyName = assembly.GetName().Name; - var directoryPath = Path.Combine(DataLocation.DataDirectory(), JsonStorage.DirectoryName, Constant.Plugins, assemblyName); - if (Directory.Exists(directoryPath)) + + // if user want to remove the plugin settings, we cannot call save method for the plugin json storage instance of this plugin + // so we need to remove it from the api instance + var method = API.GetType().GetMethod("RemovePluginSettings"); + var pluginJsonStorage = method?.Invoke(API, new object[] { assemblyName }); + + // if there exists a json storage for current plugin, we need to delete the directory path + if (pluginJsonStorage != null) { - Directory.Delete(directoryPath, true); + var deleteMethod = pluginJsonStorage.GetType().GetMethod("DeleteDirectory"); + deleteMethod?.Invoke(pluginJsonStorage, null); } } diff --git a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs index abe3f55b5..bc3900da8 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs @@ -3,14 +3,17 @@ using Flow.Launcher.Infrastructure.UserSettings; namespace Flow.Launcher.Infrastructure.Storage { - public class PluginJsonStorage :JsonStorage where T : new() + public class PluginJsonStorage : JsonStorage where T : new() { + // Use assembly name to check which plugin is using this storage + public readonly string AssemblyName; + public PluginJsonStorage() { // C# related, add python related below var dataType = typeof(T); - var assemblyName = dataType.Assembly.GetName().Name; - DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, assemblyName); + AssemblyName = dataType.Assembly.GetName().Name; + DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, AssemblyName); Helper.ValidateDirectory(DirectoryPath); FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}"); @@ -20,6 +23,13 @@ namespace Flow.Launcher.Infrastructure.Storage { Data = data; } + + public void DeleteDirectory() + { + if (Directory.Exists(DirectoryPath)) + { + Directory.Delete(DirectoryPath, true); + } + } } } - diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index f0295cf24..12c65018c 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -189,6 +189,23 @@ namespace Flow.Launcher private readonly ConcurrentDictionary _pluginJsonStorages = new(); + public object RemovePluginSettings(string assemblyName) + { + foreach (var keyValuePair in _pluginJsonStorages) + { + var key = keyValuePair.Key; + var value = keyValuePair.Value; + var name = value.GetType().GetField("AssemblyName")?.GetValue(value)?.ToString(); + if (name == assemblyName) + { + _pluginJsonStorages.Remove(key, out var pluginJsonStorage); + return pluginJsonStorage; + } + } + + return null; + } + /// /// Save plugin settings. /// From 37837e7002307443e7b50ee7db01c0a5878c468d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 8 Feb 2025 22:59:36 +0800 Subject: [PATCH 142/259] Fix possible exception when deleting local folder --- Flow.Launcher.Core/Plugin/PluginManager.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 146718b93..50150a069 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -521,7 +521,15 @@ namespace Flow.Launcher.Core.Plugin FilesFolders.CopyAll(pluginFolderPath, newPluginPath, MessageBoxEx.Show); - Directory.Delete(tempFolderPluginPath, true); + try + { + if (Directory.Exists(tempFolderPluginPath)) + Directory.Delete(tempFolderPluginPath, true); + } + catch (Exception e) + { + Log.Exception($"|PluginManager.InstallPlugin|Failed to delete temp folder {tempFolderPluginPath}", e); + } if (checkModified) { @@ -557,7 +565,14 @@ namespace Flow.Launcher.Core.Plugin if (pluginJsonStorage != null) { var deleteMethod = pluginJsonStorage.GetType().GetMethod("DeleteDirectory"); - deleteMethod?.Invoke(pluginJsonStorage, null); + try + { + deleteMethod?.Invoke(pluginJsonStorage, null); + } + catch (Exception e) + { + Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {assemblyName}", e); + } } } From 6c081e12a4c97e432dc69d5a262f97d3010f7a14 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Sat, 8 Feb 2025 19:26:36 +0100 Subject: [PATCH 143/259] Revert the translation files --- Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml | 1 - Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml | 1 - 2 files changed, 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml index f3ef0df0a..5ee2c43b4 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml @@ -6,7 +6,6 @@ Press any key to close this window... No cerrar Símbolo del Sistema tras ejecutar el comando Siempre ejecutar como administrador - Ejecutar en la Terminal de Windows Ejecutar como otro usuario Shell Allows to execute system commands from Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml index ee3193b16..a3ee35ef8 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml @@ -6,7 +6,6 @@ Pulsar cualquier tecla para cerrar esta ventana... No cerrar el símbolo del sistema después de la ejecución del comando Ejecutar siempre como administrador - Ejecutar en la Terminal de Windows Ejecutar como usuario diferente Terminal Permite ejecutar comandos del sistema desde Flow Launcher From 54a0f3d16523ecaa32408277dc30800537094e89 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 9 Feb 2025 10:58:09 +0800 Subject: [PATCH 144/259] Add support for delete plugin directory for non-dotnet plugins --- .../Plugin/JsonRPCPluginBase.cs | 14 +++- Flow.Launcher.Core/Plugin/PluginManager.cs | 70 ++++++++++++------- 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs index f6e5e5879..ed8f94bcf 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs @@ -44,8 +44,10 @@ namespace Flow.Launcher.Core.Plugin private string SettingConfigurationPath => Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml"); - private string SettingPath => Path.Combine(DataLocation.PluginSettingsDirectory, - Context.CurrentPluginMetadata.Name, "Settings.json"); + private string SettingDirectory => Path.Combine(DataLocation.PluginSettingsDirectory, + Context.CurrentPluginMetadata.Name); + + private string SettingPath => Path.Combine(SettingDirectory, "Settings.json"); public abstract List LoadContextMenus(Result selectedResult); @@ -159,5 +161,13 @@ namespace Flow.Launcher.Core.Plugin { return Settings.CreateSettingPanel(); } + + public void DeletePluginSettingsDirectory() + { + if (Directory.Exists(SettingDirectory)) + { + Directory.Delete(SettingDirectory, true); + } + } } } diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 50150a069..2bce2ba79 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -544,38 +544,56 @@ namespace Flow.Launcher.Core.Plugin throw new ArgumentException($"Plugin {plugin.Name} has been modified"); } + if (removePluginSettings) + { + if (AllowedLanguage.IsDotNet(plugin.Language)) // for the plugin in .NET, we can use assembly loader + { + var assemblyLoader = new PluginAssemblyLoader(plugin.ExecuteFilePath); + var assembly = assemblyLoader.LoadAssemblyAndDependencies(); + var assemblyName = assembly.GetName().Name; + + // if user want to remove the plugin settings, we cannot call save method for the plugin json storage instance of this plugin + // so we need to remove it from the api instance + var method = API.GetType().GetMethod("RemovePluginSettings"); + var pluginJsonStorage = method?.Invoke(API, new object[] { assemblyName }); + + // if there exists a json storage for current plugin, we need to delete the directory path + if (pluginJsonStorage != null) + { + var deleteMethod = pluginJsonStorage.GetType().GetMethod("DeleteDirectory"); + try + { + deleteMethod?.Invoke(pluginJsonStorage, null); + } + catch (Exception e) + { + Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {plugin.Name}", e); + } + } + } + else // the plugin with json prc interface + { + var pluginPair = AllPlugins.FirstOrDefault(p => p.Metadata.ID == plugin.ID); + if (pluginPair != null && pluginPair.Plugin is JsonRPCPlugin jsonRpcPlugin) + { + try + { + jsonRpcPlugin.DeletePluginSettingsDirectory(); + } + catch (Exception e) + { + Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {plugin.Name}", e); + } + } + } + } + if (removePluginFromSettings) { Settings.Plugins.Remove(plugin.ID); AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID); } - if (removePluginSettings) - { - var assemblyLoader = new PluginAssemblyLoader(plugin.ExecuteFilePath); - var assembly = assemblyLoader.LoadAssemblyAndDependencies(); - var assemblyName = assembly.GetName().Name; - - // if user want to remove the plugin settings, we cannot call save method for the plugin json storage instance of this plugin - // so we need to remove it from the api instance - var method = API.GetType().GetMethod("RemovePluginSettings"); - var pluginJsonStorage = method?.Invoke(API, new object[] { assemblyName }); - - // if there exists a json storage for current plugin, we need to delete the directory path - if (pluginJsonStorage != null) - { - var deleteMethod = pluginJsonStorage.GetType().GetMethod("DeleteDirectory"); - try - { - deleteMethod?.Invoke(pluginJsonStorage, null); - } - catch (Exception e) - { - Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {assemblyName}", e); - } - } - } - // Marked for deletion. Will be deleted on next start up using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")); From 864402704d2fb81ccc69820dbae0a0ee671bd02f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 9 Feb 2025 21:54:02 +0800 Subject: [PATCH 145/259] Fix an issue that user plugins cannot be updated when reupdating the plugins manifest --- Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs index 63f21c1d6..233612f50 100644 --- a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs +++ b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Infrastructure.Logger; using System; using System.Collections.Generic; using System.Threading; @@ -27,7 +27,7 @@ namespace Flow.Launcher.Core.ExternalPlugins { await manifestUpdateLock.WaitAsync(token).ConfigureAwait(false); - if (UserPlugins == null || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout) + if (UserPlugins == null || UserPlugins.Count == 0 || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout) { var results = await mainPluginStore.FetchAsync(token, usePrimaryUrlOnly).ConfigureAwait(false); From d8f32806324872b8977aab5cdc05230b82ee4bb0 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 10 Feb 2025 11:54:09 +0800 Subject: [PATCH 146/259] Fix unneccessary plugin result update --- Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs | 10 +++++++--- .../ViewModels/SettingsPanePluginStoreViewModel.cs | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs index 233612f50..54080e150 100644 --- a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs +++ b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs @@ -27,12 +27,16 @@ namespace Flow.Launcher.Core.ExternalPlugins { await manifestUpdateLock.WaitAsync(token).ConfigureAwait(false); - if (UserPlugins == null || UserPlugins.Count == 0 || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout) + if (UserPlugins == null || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout) { var results = await mainPluginStore.FetchAsync(token, usePrimaryUrlOnly).ConfigureAwait(false); - UserPlugins = results; - lastFetchedAt = DateTime.Now; + // If the results are empty, we shouldn't update the manifest because the results are invalid. + if (results.Count != 0) + { + UserPlugins = results; + lastFetchedAt = DateTime.Now; + } } } catch (Exception e) diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs index e06931011..a6cc3c535 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs @@ -13,8 +13,8 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel { public string FilterText { get; set; } = string.Empty; - public IList ExternalPlugins => PluginsManifest.UserPlugins - .Select(p => new PluginStoreItemViewModel(p)) + public IList ExternalPlugins => + PluginsManifest.UserPlugins?.Select(p => new PluginStoreItemViewModel(p)) .OrderByDescending(p => p.Category == PluginStoreItemViewModel.NewRelease) .ThenByDescending(p => p.Category == PluginStoreItemViewModel.RecentlyUpdated) .ThenByDescending(p => p.Category == PluginStoreItemViewModel.None) From 319f016ced396ee6dd961096140e8b9ca25a1b52 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 10 Feb 2025 12:01:21 +0800 Subject: [PATCH 147/259] Remove unnessary list refresh --- Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs | 6 +++++- .../ViewModels/SettingsPanePluginStoreViewModel.cs | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs index 54080e150..ac8abcdcc 100644 --- a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs +++ b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs @@ -21,7 +21,7 @@ namespace Flow.Launcher.Core.ExternalPlugins public static List UserPlugins { get; private set; } - public static async Task UpdateManifestAsync(CancellationToken token = default, bool usePrimaryUrlOnly = false) + public static async Task UpdateManifestAsync(CancellationToken token = default, bool usePrimaryUrlOnly = false) { try { @@ -36,6 +36,8 @@ namespace Flow.Launcher.Core.ExternalPlugins { UserPlugins = results; lastFetchedAt = DateTime.Now; + + return true; } } } @@ -47,6 +49,8 @@ namespace Flow.Launcher.Core.ExternalPlugins { manifestUpdateLock.Release(); } + + return false; } } } diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs index a6cc3c535..15579a61d 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs @@ -24,8 +24,10 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel [RelayCommand] private async Task RefreshExternalPluginsAsync() { - await PluginsManifest.UpdateManifestAsync(); - OnPropertyChanged(nameof(ExternalPlugins)); + if (await PluginsManifest.UpdateManifestAsync()) + { + OnPropertyChanged(nameof(ExternalPlugins)); + } } public bool SatisfiesFilter(PluginStoreItemViewModel plugin) From 585b7015b6236ea7fdbe156c39d468a3ca579ed5 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 10 Feb 2025 18:20:50 +0800 Subject: [PATCH 148/259] Add uninstallation tooltip for logon task settings item --- Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 8e8c9abef..cd9d0b02a 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -47,6 +47,7 @@ Store all settings and user data in one folder (Useful when used with removable drives or cloud services). Start Flow Launcher on system startup Use logon task instead of startup entry for faster startup experience + After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Scheduler Error setting launch on startup Hide Flow Launcher when focus is lost Do not show new version notifications diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index e52614e74..a80e618e8 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -36,7 +36,7 @@ OnContent="{DynamicResource enable}" /> - + Date: Wed, 12 Feb 2025 10:21:14 +0800 Subject: [PATCH 149/259] Improve explorer path parse when path ends with backslash --- .../FileExplorerHelper.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs index d908b0fde..b97c096c3 100644 --- a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs +++ b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs @@ -15,7 +15,20 @@ namespace Flow.Launcher.Infrastructure { var explorerWindow = GetActiveExplorer(); string locationUrl = explorerWindow?.LocationURL; - return !string.IsNullOrEmpty(locationUrl) ? new Uri(locationUrl).LocalPath + "\\" : null; + return !string.IsNullOrEmpty(locationUrl) ? GetDirectoryPath(new Uri(locationUrl).LocalPath) : null; + } + + /// + /// Get directory path from a file path + /// + private static string GetDirectoryPath(string path) + { + if (!path.EndsWith("\\")) + { + return path + "\\"; + } + + return path; } /// From ddbbd693e8992c8c8f18d21f71f3dff2a01e02d2 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 12 Feb 2025 15:06:15 +0800 Subject: [PATCH 150/259] Make sure back to query results from context menu before changing query --- Flow.Launcher/CustomQueryHotkeySetting.xaml.cs | 1 + Flow.Launcher/CustomShortcutSetting.xaml.cs | 1 + Flow.Launcher/ResultListBox.xaml.cs | 3 +++ Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs | 1 + Flow.Launcher/ViewModel/PluginViewModel.cs | 1 + 5 files changed, 7 insertions(+) diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index 81e7600b8..3db49b381 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -76,6 +76,7 @@ namespace Flow.Launcher private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e) { + App.API.BackToQueryResults(); App.API.ChangeQuery(tbAction.Text); Application.Current.MainWindow.Show(); Application.Current.MainWindow.Opacity = 1; diff --git a/Flow.Launcher/CustomShortcutSetting.xaml.cs b/Flow.Launcher/CustomShortcutSetting.xaml.cs index dec3506eb..10452726d 100644 --- a/Flow.Launcher/CustomShortcutSetting.xaml.cs +++ b/Flow.Launcher/CustomShortcutSetting.xaml.cs @@ -64,6 +64,7 @@ namespace Flow.Launcher private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e) { + App.API.BackToQueryResults(); App.API.ChangeQuery(tbExpand.Text); Application.Current.MainWindow.Show(); Application.Current.MainWindow.Opacity = 1; diff --git a/Flow.Launcher/ResultListBox.xaml.cs b/Flow.Launcher/ResultListBox.xaml.cs index ac51b195c..cc003457f 100644 --- a/Flow.Launcher/ResultListBox.xaml.cs +++ b/Flow.Launcher/ResultListBox.xaml.cs @@ -149,7 +149,10 @@ namespace Flow.Launcher var rawQuery = query; var effect = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy); if (effect == DragDropEffects.Move) + { + App.API.BackToQueryResults(); App.API.ChangeQuery(rawQuery, true); + } } private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { diff --git a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs index 38b5bec65..97c938e78 100644 --- a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs @@ -64,6 +64,7 @@ namespace Flow.Launcher.ViewModel private void ShowCommandQuery(string action) { var actionKeyword = PluginManagerData.Metadata.ActionKeywords.Any() ? PluginManagerData.Metadata.ActionKeywords[0] + " " : String.Empty; + App.API.BackToQueryResults(); App.API.ChangeQuery($"{actionKeyword}{action} {_plugin.Name}"); App.API.ShowMainWindow(); } diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 4ce8bd470..e56e8e9e5 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -146,6 +146,7 @@ namespace Flow.Launcher.ViewModel [RelayCommand] private void OpenDeletePluginWindow() { + PluginManager.API.BackToQueryResults(); PluginManager.API.ChangeQuery($"{PluginManagerActionKeyword} uninstall {PluginPair.Metadata.Name}".Trim(), true); PluginManager.API.ShowMainWindow(); } From 5313229fb918b19e99eddfd5023c41fed9724e66 Mon Sep 17 00:00:00 2001 From: zggsong Date: Fri, 14 Feb 2025 13:22:27 +0800 Subject: [PATCH 151/259] perf: hide main window from alt tab program switcher #2356 --- Flow.Launcher/Helper/WindowsInteropHelper.cs | 75 ++++++++++++++++++++ Flow.Launcher/MainWindow.xaml | 1 + Flow.Launcher/MainWindow.xaml.cs | 5 ++ 3 files changed, 81 insertions(+) diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index caf3f0a7f..eeb24af2e 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -148,4 +148,79 @@ public class WindowsInteropHelper return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY)); } + + #region Alt Tab + + private const int GWL_EXSTYLE = -20; + private const int WS_EX_TOOLWINDOW = 0x00000080; + private const int WS_EX_APPWINDOW = 0x00040000; + + [DllImport("user32.dll")] + private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] + private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] + private static extern int IntSetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + [DllImport("kernel32.dll", EntryPoint = "SetLastError")] + private static extern void SetLastError(int dwErrorCode); + + private static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong) + { + SetLastError(0); // Clear any existing error + + if (IntPtr.Size == 4) return new IntPtr(IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong))); + + return IntSetWindowLongPtr(hWnd, nIndex, dwNewLong); + } + + private static int IntPtrToInt32(IntPtr intPtr) + { + return unchecked((int)intPtr.ToInt64()); + } + + /// + /// Hide windows in the Alt+Tab window list + /// + /// To hide a window + public static void HideFromAltTab(Window window) + { + var helper = new WindowInteropHelper(window); + var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + + // Add TOOLWINDOW style, remove APPWINDOW style + exStyle = (exStyle | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW; + + SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + } + + /// + /// Restore window display in the Alt+Tab window list. + /// + /// To restore the displayed window + public static void ShowInAltTab(Window window) + { + var helper = new WindowInteropHelper(window); + var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + + // Remove the TOOLWINDOW style and add the APPWINDOW style. + exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW; + + SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + } + + /// + /// To obtain the current overridden style of a window. + /// + /// To obtain the style dialog window + /// current extension style value + public static int GetCurrentWindowStyle(Window window) + { + var helper = new WindowInteropHelper(window); + return GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + } + + #endregion } diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index f5fd729d4..da9e1a5b5 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -20,6 +20,7 @@ Closing="OnClosing" Deactivated="OnDeactivated" Icon="Images/app.png" + SourceInitialized="OnSourceInitialized" Initialized="OnInitialized" Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Loaded="OnLoaded" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 8ca153afc..41dc68fd9 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -171,6 +171,11 @@ namespace Flow.Launcher Environment.Exit(0); } + private void OnSourceInitialized(object sender, EventArgs e) + { + WindowsInteropHelper.HideFromAltTab(this); + } + private void OnInitialized(object sender, EventArgs e) { } From 829dbaafe7fae537d487f4b67cfe593c01ac5081 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 14 Feb 2025 16:12:15 +0800 Subject: [PATCH 152/259] Use CSWin32 for code quality --- Flow.Launcher/Helper/WindowsInteropHelper.cs | 44 ++++++-------------- Flow.Launcher/NativeMethods.txt | 5 ++- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index eeb24af2e..4891bf41a 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -151,29 +151,11 @@ public class WindowsInteropHelper #region Alt Tab - private const int GWL_EXSTYLE = -20; - private const int WS_EX_TOOLWINDOW = 0x00000080; - private const int WS_EX_APPWINDOW = 0x00040000; - - [DllImport("user32.dll")] - private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] - private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); - - [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] - private static extern int IntSetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("kernel32.dll", EntryPoint = "SetLastError")] - private static extern void SetLastError(int dwErrorCode); - - private static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong) + private static IntPtr SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong) { - SetLastError(0); // Clear any existing error + PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error - if (IntPtr.Size == 4) return new IntPtr(IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong))); - - return IntSetWindowLongPtr(hWnd, nIndex, dwNewLong); + return PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong); } private static int IntPtrToInt32(IntPtr intPtr) @@ -182,44 +164,44 @@ public class WindowsInteropHelper } /// - /// Hide windows in the Alt+Tab window list + /// Hide windows in the Alt+Tab window list /// /// To hide a window public static void HideFromAltTab(Window window) { var helper = new WindowInteropHelper(window); - var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); // Add TOOLWINDOW style, remove APPWINDOW style - exStyle = (exStyle | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW; + var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// - /// Restore window display in the Alt+Tab window list. + /// Restore window display in the Alt+Tab window list. /// /// To restore the displayed window public static void ShowInAltTab(Window window) { var helper = new WindowInteropHelper(window); - var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); // Remove the TOOLWINDOW style and add the APPWINDOW style. - exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW; + var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// - /// To obtain the current overridden style of a window. + /// To obtain the current overridden style of a window. /// /// To obtain the style dialog window /// current extension style value public static int GetCurrentWindowStyle(Window window) { var helper = new WindowInteropHelper(window); - return GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + return PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); } #endregion diff --git a/Flow.Launcher/NativeMethods.txt b/Flow.Launcher/NativeMethods.txt index 2b147c05f..88eeeca6e 100644 --- a/Flow.Launcher/NativeMethods.txt +++ b/Flow.Launcher/NativeMethods.txt @@ -14,4 +14,7 @@ FindWindowEx WINDOW_STYLE WM_ENTERSIZEMOVE -WM_EXITSIZEMOVE \ No newline at end of file +WM_EXITSIZEMOVE + +SetLastError +WINDOW_EX_STYLE \ No newline at end of file From dc07e762fe0abc147a71ea5e8cd8b156e3ad611e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 14 Feb 2025 16:25:51 +0800 Subject: [PATCH 153/259] Add error handling for Get & SetWindowLong failure & Combine get style function --- Flow.Launcher/Helper/WindowsInteropHelper.cs | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index 4891bf41a..3e57948a5 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -151,16 +151,17 @@ public class WindowsInteropHelper #region Alt Tab - private static IntPtr SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong) + private static int SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong) { PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error - return PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong); - } + var result = PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong); + if (result == 0 && Marshal.GetLastPInvokeError() != 0) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } - private static int IntPtrToInt32(IntPtr intPtr) - { - return unchecked((int)intPtr.ToInt64()); + return result; } /// @@ -169,13 +170,12 @@ public class WindowsInteropHelper /// To hide a window public static void HideFromAltTab(Window window) { - var helper = new WindowInteropHelper(window); - var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + var exStyle = GetCurrentWindowStyle(window); // Add TOOLWINDOW style, remove APPWINDOW style var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); + SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// @@ -184,13 +184,12 @@ public class WindowsInteropHelper /// To restore the displayed window public static void ShowInAltTab(Window window) { - var helper = new WindowInteropHelper(window); - var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + var exStyle = GetCurrentWindowStyle(window); // Remove the TOOLWINDOW style and add the APPWINDOW style. var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); + SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// @@ -198,10 +197,14 @@ public class WindowsInteropHelper /// /// To obtain the style dialog window /// current extension style value - public static int GetCurrentWindowStyle(Window window) + private static int GetCurrentWindowStyle(Window window) { - var helper = new WindowInteropHelper(window); - return PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + var style = PInvoke.GetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + if (style == 0 && Marshal.GetLastPInvokeError() != 0) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } + return style; } #endregion From cc570274ffb4ad678d4fba75914c4c40e515d53a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 16 Feb 2025 22:47:10 +0800 Subject: [PATCH 154/259] Fix get thumbnail exception --- Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs index 2fb8cf363..a8d1d78ed 100644 --- a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs +++ b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs @@ -31,8 +31,6 @@ namespace Flow.Launcher.Infrastructure.Image private static readonly Guid GUID_IShellItem = typeof(IShellItem).GUID; - private static readonly HRESULT S_ExtractionFailed = (HRESULT)0x8004B200; - public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options) { HBITMAP hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options); @@ -79,7 +77,12 @@ namespace Flow.Launcher.Infrastructure.Image { imageFactory.GetImage(size, (SIIGBF)options, &hBitmap); } - catch (COMException ex) when (ex.HResult == S_ExtractionFailed && options == ThumbnailOptions.ThumbnailOnly) + catch (COMException) + { + // Fallback to IconOnly if ThumbnailOnly fails + imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); + } + catch (FileNotFoundException) { // Fallback to IconOnly if ThumbnailOnly fails imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); From 38b285067d1874ce1952db25a2529502a53cbe4f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 16 Feb 2025 22:50:43 +0800 Subject: [PATCH 155/259] Improve documents --- Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs index a8d1d78ed..bd34bdd2a 100644 --- a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs +++ b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs @@ -79,12 +79,12 @@ namespace Flow.Launcher.Infrastructure.Image } catch (COMException) { - // Fallback to IconOnly if ThumbnailOnly fails + // Fallback to IconOnly for COM exceptions imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); } catch (FileNotFoundException) { - // Fallback to IconOnly if ThumbnailOnly fails + // Fallback to IconOnly if files cannot be found imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); } } From d73f3a165b9d3faa8b9cf35f0bd714b286bd5af9 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 17 Feb 2025 00:00:18 +0800 Subject: [PATCH 156/259] Fix custom hotkey preview issue --- Flow.Launcher/CustomQueryHotkeySetting.xaml.cs | 18 ++++++++++-------- Flow.Launcher/CustomShortcutSetting.xaml.cs | 8 +++++--- Flow.Launcher/PublicAPIInstance.cs | 2 +- .../ViewModels/SettingsPaneHotkeyViewModel.cs | 11 +++++++---- .../Views/SettingsPaneHotkey.xaml.cs | 4 ++-- Flow.Launcher/SettingWindow.xaml.cs | 8 +++++--- Flow.Launcher/ViewModel/MainViewModel.cs | 5 +++-- 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index 81e7600b8..db1df0cf2 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -7,20 +7,23 @@ using System.Windows; using System.Windows.Input; using System.Windows.Controls; using Flow.Launcher.Core; +using Flow.Launcher.ViewModel; namespace Flow.Launcher { public partial class CustomQueryHotkeySetting : Window { private SettingWindow _settingWidow; + private readonly Settings _settings; + private readonly MainViewModel _mainViewModel; private bool update; private CustomPluginHotkey updateCustomHotkey; - public Settings Settings { get; } - public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings) + public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings, MainViewModel mainVM) { _settingWidow = settingWidow; - Settings = settings; + _settings = settings; + _mainViewModel = mainVM; InitializeComponent(); } @@ -33,13 +36,13 @@ namespace Flow.Launcher { if (!update) { - Settings.CustomPluginHotkeys ??= new ObservableCollection(); + _settings.CustomPluginHotkeys ??= new ObservableCollection(); var pluginHotkey = new CustomPluginHotkey { Hotkey = HotkeyControl.CurrentHotkey.ToString(), ActionKeyword = tbAction.Text }; - Settings.CustomPluginHotkeys.Add(pluginHotkey); + _settings.CustomPluginHotkeys.Add(pluginHotkey); HotKeyMapper.SetCustomQueryHotkey(pluginHotkey); } @@ -59,7 +62,7 @@ namespace Flow.Launcher public void UpdateItem(CustomPluginHotkey item) { - updateCustomHotkey = Settings.CustomPluginHotkeys.FirstOrDefault(o => + updateCustomHotkey = _settings.CustomPluginHotkeys.FirstOrDefault(o => o.ActionKeyword == item.ActionKeyword && o.Hotkey == item.Hotkey); if (updateCustomHotkey == null) { @@ -77,8 +80,7 @@ namespace Flow.Launcher private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbAction.Text); - Application.Current.MainWindow.Show(); - Application.Current.MainWindow.Opacity = 1; + _mainViewModel.Show(false); Application.Current.MainWindow.Focus(); } diff --git a/Flow.Launcher/CustomShortcutSetting.xaml.cs b/Flow.Launcher/CustomShortcutSetting.xaml.cs index dec3506eb..cb2cfcb29 100644 --- a/Flow.Launcher/CustomShortcutSetting.xaml.cs +++ b/Flow.Launcher/CustomShortcutSetting.xaml.cs @@ -4,21 +4,24 @@ using System.Windows; using System.Windows.Input; using Flow.Launcher.SettingPages.ViewModels; using Flow.Launcher.Core; +using Flow.Launcher.ViewModel; namespace Flow.Launcher { public partial class CustomShortcutSetting : Window { private readonly SettingsPaneHotkeyViewModel _hotkeyVm; + private readonly MainViewModel _mainViewModel; public string Key { get; set; } = String.Empty; public string Value { get; set; } = String.Empty; private string originalKey { get; } = null; private string originalValue { get; } = null; private bool update { get; } = false; - public CustomShortcutSetting(SettingsPaneHotkeyViewModel vm) + public CustomShortcutSetting(SettingsPaneHotkeyViewModel vm, MainViewModel mainVM) { _hotkeyVm = vm; + _mainViewModel = mainVM; InitializeComponent(); } @@ -65,8 +68,7 @@ namespace Flow.Launcher private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbExpand.Text); - Application.Current.MainWindow.Show(); - Application.Current.MainWindow.Opacity = 1; + _mainViewModel.Show(false); Application.Current.MainWindow.Focus(); } } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index f0295cf24..2d8126033 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -105,7 +105,7 @@ namespace Flow.Launcher { Application.Current.Dispatcher.Invoke(() => { - SettingWindow sw = SingletonWindowOpener.Open(this, _settingsVM); + SettingWindow sw = SingletonWindowOpener.Open(this, _settingsVM, _mainVM); }); } diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs index 6d8af9a3f..5aedd3be7 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs @@ -8,12 +8,14 @@ using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Core; +using Flow.Launcher.ViewModel; namespace Flow.Launcher.SettingPages.ViewModels; public partial class SettingsPaneHotkeyViewModel : BaseModel { public Settings Settings { get; } + private MainViewModel MainVM { get; } public CustomPluginHotkey SelectedCustomPluginHotkey { get; set; } public CustomShortcutModel SelectedCustomShortcut { get; set; } @@ -25,9 +27,10 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel $"{KeyConstant.Ctrl}+{KeyConstant.Alt}" }; - public SettingsPaneHotkeyViewModel(Settings settings) + public SettingsPaneHotkeyViewModel(Settings settings, MainViewModel mainVM) { Settings = settings; + MainVM = mainVM; } [RelayCommand] @@ -71,7 +74,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel return; } - var window = new CustomQueryHotkeySetting(null, Settings); + var window = new CustomQueryHotkeySetting(null, Settings, MainVM); window.UpdateItem(item); window.ShowDialog(); } @@ -79,7 +82,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel [RelayCommand] private void CustomHotkeyAdd() { - new CustomQueryHotkeySetting(null, Settings).ShowDialog(); + new CustomQueryHotkeySetting(null, Settings, MainVM).ShowDialog(); } [RelayCommand] @@ -126,7 +129,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel [RelayCommand] private void CustomShortcutAdd() { - var window = new CustomShortcutSetting(this); + var window = new CustomShortcutSetting(this, MainVM); if (window.ShowDialog() is true) { var shortcut = new CustomShortcutModel(window.Key, window.Value); diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs index 061eabf51..26939c9f9 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs @@ -12,9 +12,9 @@ public partial class SettingsPaneHotkey { if (!IsInitialized) { - if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings }) + if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings, MainViewModel: { } mainVM }) throw new ArgumentException("Settings are required for SettingsPaneHotkey."); - _viewModel = new SettingsPaneHotkeyViewModel(settings); + _viewModel = new SettingsPaneHotkeyViewModel(settings, mainVM); DataContext = _viewModel; InitializeComponent(); } diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index d5b303516..ae481b65b 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -20,12 +20,14 @@ public partial class SettingWindow private readonly IPublicAPI _api; private readonly Settings _settings; private readonly SettingWindowViewModel _viewModel; + private readonly MainViewModel _mainVM; - public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel) + public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel, MainViewModel mainVM) { _settings = viewModel.Settings; DataContext = viewModel; _viewModel = viewModel; + _mainVM = mainVM; _api = api; InitializePosition(); InitializeComponent(); @@ -160,7 +162,7 @@ public partial class SettingWindow private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) { - var paneData = new PaneData(_settings, _viewModel.Updater, _viewModel.Portable); + var paneData = new PaneData(_settings, _viewModel.Updater, _viewModel.Portable, _mainVM); if (args.IsSettingsSelected) { ContentFrame.Navigate(typeof(SettingsPaneGeneral), paneData); @@ -206,5 +208,5 @@ public partial class SettingWindow NavView.SelectedItem ??= NavView.MenuItems[0]; /* Set First Page */ } - public record PaneData(Settings Settings, Updater Updater, IPortable Portable); + public record PaneData(Settings Settings, Updater Updater, IPortable Portable, MainViewModel MainViewModel); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 55bc8d1b3..7c2abb078 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1359,7 +1359,7 @@ namespace Flow.Launcher.ViewModel } } - public void Show() + public void Show(bool invokeEvent = true) { Application.Current.Dispatcher.Invoke(() => { @@ -1368,7 +1368,8 @@ namespace Flow.Launcher.ViewModel MainWindowOpacity = 1; MainWindowVisibilityStatus = true; - VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); + if (invokeEvent) + VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); }); } From 0611340d7159d050bc3a8a9dac7d4df852a568f1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 17 Feb 2025 16:10:07 +0800 Subject: [PATCH 157/259] Invoke visibility changed event when previewing --- Flow.Launcher/CustomQueryHotkeySetting.xaml.cs | 2 +- Flow.Launcher/CustomShortcutSetting.xaml.cs | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index db1df0cf2..d33794d61 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -80,7 +80,7 @@ namespace Flow.Launcher private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbAction.Text); - _mainViewModel.Show(false); + _mainViewModel.Show(); Application.Current.MainWindow.Focus(); } diff --git a/Flow.Launcher/CustomShortcutSetting.xaml.cs b/Flow.Launcher/CustomShortcutSetting.xaml.cs index cb2cfcb29..4cc30c8f5 100644 --- a/Flow.Launcher/CustomShortcutSetting.xaml.cs +++ b/Flow.Launcher/CustomShortcutSetting.xaml.cs @@ -68,7 +68,7 @@ namespace Flow.Launcher private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbExpand.Text); - _mainViewModel.Show(false); + _mainViewModel.Show(); Application.Current.MainWindow.Focus(); } } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 7c2abb078..55bc8d1b3 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1359,7 +1359,7 @@ namespace Flow.Launcher.ViewModel } } - public void Show(bool invokeEvent = true) + public void Show() { Application.Current.Dispatcher.Invoke(() => { @@ -1368,8 +1368,7 @@ namespace Flow.Launcher.ViewModel MainWindowOpacity = 1; MainWindowVisibilityStatus = true; - if (invokeEvent) - VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); + VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); }); } From 71f1acd9ec148ea82055644b7498e2c956b6f623 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 17 Feb 2025 19:07:01 +0800 Subject: [PATCH 158/259] Revert com expcetion & Add thumbnail only check --- Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs index bd34bdd2a..b98ea50fe 100644 --- a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs +++ b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs @@ -31,6 +31,8 @@ namespace Flow.Launcher.Infrastructure.Image private static readonly Guid GUID_IShellItem = typeof(IShellItem).GUID; + private static readonly HRESULT S_ExtractionFailed = (HRESULT)0x8004B200; + public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options) { HBITMAP hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options); @@ -77,12 +79,12 @@ namespace Flow.Launcher.Infrastructure.Image { imageFactory.GetImage(size, (SIIGBF)options, &hBitmap); } - catch (COMException) + catch (COMException ex) when (ex.HResult == S_ExtractionFailed && options == ThumbnailOptions.ThumbnailOnly) { - // Fallback to IconOnly for COM exceptions + // Fallback to IconOnly if ThumbnailOnly fails imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); } - catch (FileNotFoundException) + catch (FileNotFoundException) when (options == ThumbnailOptions.ThumbnailOnly) { // Fallback to IconOnly if files cannot be found imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); From 827b6edb38f58c5d7f94a19b0c690a1b9c1ce3f4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 17 Feb 2025 23:12:46 +0800 Subject: [PATCH 159/259] Improve code quality --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 5bfc68ea6..374caa511 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -120,10 +120,9 @@ namespace Flow.Launcher.Plugin.Sys context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_shutdown_computer"), context.API.GetTranslation("flowlauncher_plugin_sys_shutdown_computer"), MessageBoxButton.YesNo, MessageBoxImage.Warning); + if (result == MessageBoxResult.Yes) - { Process.Start("shutdown", "/s /t 0"); - } return true; } @@ -140,10 +139,9 @@ namespace Flow.Launcher.Plugin.Sys context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_restart_computer"), context.API.GetTranslation("flowlauncher_plugin_sys_restart_computer"), MessageBoxButton.YesNo, MessageBoxImage.Warning); + if (result == MessageBoxResult.Yes) - { Process.Start("shutdown", "/r /t 0"); - } return true; } @@ -204,7 +202,11 @@ namespace Flow.Launcher.Plugin.Sys SubTitle = context.API.GetTranslation("flowlauncher_plugin_sys_sleep"), Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xec46"), IcoPath = "Images\\sleep.png", - Action = c => PInvoke.SetSuspendState(false, false, false) + Action = c => + { + PInvoke.SetSuspendState(false, false, false); + return true; + } }, new Result { @@ -231,10 +233,7 @@ namespace Flow.Launcher.Plugin.Sys Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xe773"), Action = c => { - { - System.Diagnostics.Process.Start("control.exe", "srchadmin.dll"); - } - + Process.Start("control.exe", "srchadmin.dll"); return true; } }, @@ -272,10 +271,7 @@ namespace Flow.Launcher.Plugin.Sys CopyText = recycleBinFolder, Action = c => { - { - System.Diagnostics.Process.Start("explorer", recycleBinFolder); - } - + Process.Start("explorer", recycleBinFolder); return true; } }, From ffa303825ef2a1523751f4aedc6a309726796b24 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 17 Feb 2025 23:22:06 +0800 Subject: [PATCH 160/259] Replace process commands with PInvoke --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 374caa511..16c1b7f91 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -122,7 +122,7 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - Process.Start("shutdown", "/s /t 0"); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, SHUTDOWN_REASON.SHTDN_REASON_NONE); return true; } @@ -141,7 +141,7 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - Process.Start("shutdown", "/r /t 0"); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, SHUTDOWN_REASON.SHTDN_REASON_NONE); return true; } @@ -160,7 +160,7 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - Process.Start("shutdown", "/r /o /t 0"); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, SHUTDOWN_REASON.SHTDN_REASON_NONE); return true; } @@ -179,7 +179,7 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, 0); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, SHUTDOWN_REASON.SHTDN_REASON_NONE); return true; } From e93699b37daaa1bedefd5e442413ea79dbe3204e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 17 Feb 2025 23:37:20 +0800 Subject: [PATCH 161/259] Add shutdown reason --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 16c1b7f91..3199f50a2 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -121,8 +121,12 @@ namespace Flow.Launcher.Plugin.Sys context.API.GetTranslation("flowlauncher_plugin_sys_shutdown_computer"), MessageBoxButton.YesNo, MessageBoxImage.Warning); + // SHTDN_REASON_MAJOR_OTHER indicates a generic shutdown reason that isn't categorized under hardware failure, + // software updates, or other predefined reasons. + // SHTDN_REASON_FLAG_PLANNED marks the shutdown as planned rather than an unexpected shutdown or failure if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, SHUTDOWN_REASON.SHTDN_REASON_NONE); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, + SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); return true; } @@ -141,7 +145,8 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, SHUTDOWN_REASON.SHTDN_REASON_NONE); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, + SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); return true; } @@ -160,7 +165,8 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, SHUTDOWN_REASON.SHTDN_REASON_NONE); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, + SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); return true; } @@ -179,7 +185,8 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, SHUTDOWN_REASON.SHTDN_REASON_NONE); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, + SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); return true; } From 18093148429abfaa94db92607984a53d97cde8cf Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 18 Feb 2025 00:08:15 +0800 Subject: [PATCH 162/259] Enable shutdown privilege before calling PInvoke for shutdown and start --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 63 +++++++++++++++++-- .../NativeMethods.txt | 7 ++- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 3199f50a2..7d3f66746 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; using System.Windows; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; @@ -9,6 +10,7 @@ using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.SharedCommands; using Windows.Win32; using Windows.Win32.Foundation; +using Windows.Win32.Security; using Windows.Win32.System.Shutdown; using Application = System.Windows.Application; using Control = System.Windows.Controls.Control; @@ -20,6 +22,8 @@ namespace Flow.Launcher.Plugin.Sys private PluginInitContext context; private Dictionary KeywordTitleMappings = new Dictionary(); + private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; + public Control CreateSettingPanel() { var results = Commands(); @@ -100,6 +104,44 @@ namespace Flow.Launcher.Plugin.Sys }; } + private static unsafe bool EnableShutdownPrivilege() + { + try + { + if (!PInvoke.OpenProcessToken(Process.GetCurrentProcess().SafeHandle, TOKEN_ACCESS_MASK.TOKEN_ADJUST_PRIVILEGES | TOKEN_ACCESS_MASK.TOKEN_QUERY, out var tokenHandle)) + { + return false; + } + + if (!PInvoke.LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, out var luid)) + { + return false; + } + + var privileges = new TOKEN_PRIVILEGES + { + PrivilegeCount = 1, + Privileges = new() { e0 = new LUID_AND_ATTRIBUTES { Luid = luid, Attributes = TOKEN_PRIVILEGES_ATTRIBUTES.SE_PRIVILEGE_ENABLED } } + }; + + if (!PInvoke.AdjustTokenPrivileges(tokenHandle, false, &privileges, 0, null, null)) + { + return false; + } + + if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.NO_ERROR) + { + return false; + } + + return true; + } + catch (Exception) + { + return false; + } + } + private List Commands() { var results = new List(); @@ -125,8 +167,11 @@ namespace Flow.Launcher.Plugin.Sys // software updates, or other predefined reasons. // SHTDN_REASON_FLAG_PLANNED marks the shutdown as planned rather than an unexpected shutdown or failure if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, - SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + if (EnableShutdownPrivilege()) + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, + SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + else + Process.Start("shutdown", "/s /t 0"); return true; } @@ -145,8 +190,11 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, - SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + if (EnableShutdownPrivilege()) + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, + SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + else + Process.Start("shutdown", "/r /t 0"); return true; } @@ -165,8 +213,11 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, - SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + if (EnableShutdownPrivilege()) + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, + SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + else + Process.Start("shutdown", "/r /o /t 0"); return true; } diff --git a/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt b/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt index 8fcb6cae9..6159c725b 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt +++ b/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt @@ -3,4 +3,9 @@ LockWorkStation SHEmptyRecycleBin S_OK E_UNEXPECTED -SetSuspendState \ No newline at end of file +SetSuspendState +OpenProcessToken +WIN32_ERROR +LookupPrivilegeValue +AdjustTokenPrivileges +TOKEN_PRIVILEGES \ No newline at end of file From 648e3f268990c6da85eef377d5d1b5bc97dc438b Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 18 Feb 2025 11:07:18 +0800 Subject: [PATCH 163/259] Improve code quality --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 7d3f66746..f6117aab9 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -23,6 +23,9 @@ namespace Flow.Launcher.Plugin.Sys private Dictionary KeywordTitleMappings = new Dictionary(); private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; + // SHTDN_REASON_MAJOR_OTHER indicates a generic shutdown reason that isn't categorized under hardware failure, software updates, or other predefined reasons. + // SHTDN_REASON_FLAG_PLANNED marks the shutdown as planned rather than an unexpected shutdown or failure + private const SHUTDOWN_REASON REASON = SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED; public Control CreateSettingPanel() { @@ -163,13 +166,9 @@ namespace Flow.Launcher.Plugin.Sys context.API.GetTranslation("flowlauncher_plugin_sys_shutdown_computer"), MessageBoxButton.YesNo, MessageBoxImage.Warning); - // SHTDN_REASON_MAJOR_OTHER indicates a generic shutdown reason that isn't categorized under hardware failure, - // software updates, or other predefined reasons. - // SHTDN_REASON_FLAG_PLANNED marks the shutdown as planned rather than an unexpected shutdown or failure if (result == MessageBoxResult.Yes) if (EnableShutdownPrivilege()) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, - SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, REASON); else Process.Start("shutdown", "/s /t 0"); @@ -191,8 +190,7 @@ namespace Flow.Launcher.Plugin.Sys if (result == MessageBoxResult.Yes) if (EnableShutdownPrivilege()) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, - SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, REASON); else Process.Start("shutdown", "/r /t 0"); @@ -214,8 +212,7 @@ namespace Flow.Launcher.Plugin.Sys if (result == MessageBoxResult.Yes) if (EnableShutdownPrivilege()) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, - SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT | EXIT_WINDOWS_FLAGS.EWX_BOOTOPTIONS, REASON); else Process.Start("shutdown", "/r /o /t 0"); @@ -236,8 +233,7 @@ namespace Flow.Launcher.Plugin.Sys MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) - PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, - SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED); + PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, REASON); return true; } From a065179d53aee2146e633e0bf2db2ad3ccd066f6 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 18 Feb 2025 11:12:33 +0800 Subject: [PATCH 164/259] Use PInvoke for const --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 3 +-- Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index f6117aab9..3bda99e71 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -22,7 +22,6 @@ namespace Flow.Launcher.Plugin.Sys private PluginInitContext context; private Dictionary KeywordTitleMappings = new Dictionary(); - private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; // SHTDN_REASON_MAJOR_OTHER indicates a generic shutdown reason that isn't categorized under hardware failure, software updates, or other predefined reasons. // SHTDN_REASON_FLAG_PLANNED marks the shutdown as planned rather than an unexpected shutdown or failure private const SHUTDOWN_REASON REASON = SHUTDOWN_REASON.SHTDN_REASON_MAJOR_OTHER | SHUTDOWN_REASON.SHTDN_REASON_FLAG_PLANNED; @@ -116,7 +115,7 @@ namespace Flow.Launcher.Plugin.Sys return false; } - if (!PInvoke.LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, out var luid)) + if (!PInvoke.LookupPrivilegeValue(null, PInvoke.SE_SHUTDOWN_NAME, out var luid)) { return false; } diff --git a/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt b/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt index 6159c725b..4567e46a3 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt +++ b/Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt @@ -8,4 +8,5 @@ OpenProcessToken WIN32_ERROR LookupPrivilegeValue AdjustTokenPrivileges -TOKEN_PRIVILEGES \ No newline at end of file +TOKEN_PRIVILEGES +SE_SHUTDOWN_NAME \ No newline at end of file From 3bd4ca4105840ab4a679a21817148ade91660263 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 18 Feb 2025 11:17:45 +0800 Subject: [PATCH 165/259] Replace hiberate with PInvoke --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 3bda99e71..e81d70c52 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -269,12 +269,7 @@ namespace Flow.Launcher.Plugin.Sys IcoPath = "Images\\hibernate.png", Action= c => { - var info = ShellCommand.SetProcessStartInfo("shutdown", arguments:"/h"); - info.WindowStyle = ProcessWindowStyle.Hidden; - info.UseShellExecute = true; - - ShellCommand.Execute(info); - + PInvoke.SetSuspendState(true, false, false); return true; } }, From 6b032b33520a272f8d9a239253272aa0fa234f68 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 18 Feb 2025 11:32:47 +0800 Subject: [PATCH 166/259] Revert changes and use api function instead --- Flow.Launcher/CustomQueryHotkeySetting.xaml.cs | 7 ++----- Flow.Launcher/CustomShortcutSetting.xaml.cs | 7 ++----- Flow.Launcher/PublicAPIInstance.cs | 2 +- .../ViewModels/SettingsPaneHotkeyViewModel.cs | 11 ++++------- .../SettingPages/Views/SettingsPaneHotkey.xaml.cs | 4 ++-- Flow.Launcher/SettingWindow.xaml.cs | 8 +++----- 6 files changed, 14 insertions(+), 25 deletions(-) diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index d33794d61..1bd6ee95b 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -7,7 +7,6 @@ using System.Windows; using System.Windows.Input; using System.Windows.Controls; using Flow.Launcher.Core; -using Flow.Launcher.ViewModel; namespace Flow.Launcher { @@ -15,15 +14,13 @@ namespace Flow.Launcher { private SettingWindow _settingWidow; private readonly Settings _settings; - private readonly MainViewModel _mainViewModel; private bool update; private CustomPluginHotkey updateCustomHotkey; - public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings, MainViewModel mainVM) + public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings) { _settingWidow = settingWidow; _settings = settings; - _mainViewModel = mainVM; InitializeComponent(); } @@ -80,7 +77,7 @@ namespace Flow.Launcher private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbAction.Text); - _mainViewModel.Show(); + App.API.ShowMainWindow(); Application.Current.MainWindow.Focus(); } diff --git a/Flow.Launcher/CustomShortcutSetting.xaml.cs b/Flow.Launcher/CustomShortcutSetting.xaml.cs index 4cc30c8f5..05d4d3d83 100644 --- a/Flow.Launcher/CustomShortcutSetting.xaml.cs +++ b/Flow.Launcher/CustomShortcutSetting.xaml.cs @@ -4,24 +4,21 @@ using System.Windows; using System.Windows.Input; using Flow.Launcher.SettingPages.ViewModels; using Flow.Launcher.Core; -using Flow.Launcher.ViewModel; namespace Flow.Launcher { public partial class CustomShortcutSetting : Window { private readonly SettingsPaneHotkeyViewModel _hotkeyVm; - private readonly MainViewModel _mainViewModel; public string Key { get; set; } = String.Empty; public string Value { get; set; } = String.Empty; private string originalKey { get; } = null; private string originalValue { get; } = null; private bool update { get; } = false; - public CustomShortcutSetting(SettingsPaneHotkeyViewModel vm, MainViewModel mainVM) + public CustomShortcutSetting(SettingsPaneHotkeyViewModel vm) { _hotkeyVm = vm; - _mainViewModel = mainVM; InitializeComponent(); } @@ -68,7 +65,7 @@ namespace Flow.Launcher private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbExpand.Text); - _mainViewModel.Show(); + App.API.ShowMainWindow(); Application.Current.MainWindow.Focus(); } } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 2d8126033..f0295cf24 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -105,7 +105,7 @@ namespace Flow.Launcher { Application.Current.Dispatcher.Invoke(() => { - SettingWindow sw = SingletonWindowOpener.Open(this, _settingsVM, _mainVM); + SettingWindow sw = SingletonWindowOpener.Open(this, _settingsVM); }); } diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs index 5aedd3be7..6d8af9a3f 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs @@ -8,14 +8,12 @@ using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Core; -using Flow.Launcher.ViewModel; namespace Flow.Launcher.SettingPages.ViewModels; public partial class SettingsPaneHotkeyViewModel : BaseModel { public Settings Settings { get; } - private MainViewModel MainVM { get; } public CustomPluginHotkey SelectedCustomPluginHotkey { get; set; } public CustomShortcutModel SelectedCustomShortcut { get; set; } @@ -27,10 +25,9 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel $"{KeyConstant.Ctrl}+{KeyConstant.Alt}" }; - public SettingsPaneHotkeyViewModel(Settings settings, MainViewModel mainVM) + public SettingsPaneHotkeyViewModel(Settings settings) { Settings = settings; - MainVM = mainVM; } [RelayCommand] @@ -74,7 +71,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel return; } - var window = new CustomQueryHotkeySetting(null, Settings, MainVM); + var window = new CustomQueryHotkeySetting(null, Settings); window.UpdateItem(item); window.ShowDialog(); } @@ -82,7 +79,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel [RelayCommand] private void CustomHotkeyAdd() { - new CustomQueryHotkeySetting(null, Settings, MainVM).ShowDialog(); + new CustomQueryHotkeySetting(null, Settings).ShowDialog(); } [RelayCommand] @@ -129,7 +126,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel [RelayCommand] private void CustomShortcutAdd() { - var window = new CustomShortcutSetting(this, MainVM); + var window = new CustomShortcutSetting(this); if (window.ShowDialog() is true) { var shortcut = new CustomShortcutModel(window.Key, window.Value); diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs index 26939c9f9..061eabf51 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs @@ -12,9 +12,9 @@ public partial class SettingsPaneHotkey { if (!IsInitialized) { - if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings, MainViewModel: { } mainVM }) + if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings }) throw new ArgumentException("Settings are required for SettingsPaneHotkey."); - _viewModel = new SettingsPaneHotkeyViewModel(settings, mainVM); + _viewModel = new SettingsPaneHotkeyViewModel(settings); DataContext = _viewModel; InitializeComponent(); } diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index ae481b65b..d5b303516 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -20,14 +20,12 @@ public partial class SettingWindow private readonly IPublicAPI _api; private readonly Settings _settings; private readonly SettingWindowViewModel _viewModel; - private readonly MainViewModel _mainVM; - public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel, MainViewModel mainVM) + public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel) { _settings = viewModel.Settings; DataContext = viewModel; _viewModel = viewModel; - _mainVM = mainVM; _api = api; InitializePosition(); InitializeComponent(); @@ -162,7 +160,7 @@ public partial class SettingWindow private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) { - var paneData = new PaneData(_settings, _viewModel.Updater, _viewModel.Portable, _mainVM); + var paneData = new PaneData(_settings, _viewModel.Updater, _viewModel.Portable); if (args.IsSettingsSelected) { ContentFrame.Navigate(typeof(SettingsPaneGeneral), paneData); @@ -208,5 +206,5 @@ public partial class SettingWindow NavView.SelectedItem ??= NavView.MenuItems[0]; /* Set First Page */ } - public record PaneData(Settings Settings, Updater Updater, IPortable Portable, MainViewModel MainViewModel); + public record PaneData(Settings Settings, Updater Updater, IPortable Portable); } From 9284c559f68cc8418af9cea727c8954b01153e6c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 18 Feb 2025 11:41:26 +0800 Subject: [PATCH 167/259] Use api function to hide window --- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 8 ++++---- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 671489846..c1ed904b3 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -534,7 +534,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return false; } - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); _ = InstallOrUpdateAsync(plugin); return ShouldHideWindow; @@ -572,7 +572,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return false; } - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); _ = InstallOrUpdateAsync(plugin); return ShouldHideWindow; @@ -626,7 +626,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return ShouldHideWindow; } - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); _ = InstallOrUpdateAsync(x); // No need to wait return ShouldHideWindow; }, @@ -703,7 +703,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) { - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); Uninstall(x.Metadata); if (Settings.AutoRestartAfterChanging) { diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 5bfc68ea6..edf9c82e4 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -333,7 +333,7 @@ namespace Flow.Launcher.Plugin.Sys Action = c => { // Hide the window first then show msg after done because sometimes the reload could take a while, so not to make user think it's frozen. - Application.Current.MainWindow.Hide(); + context.API.HideMainWindow(); _ = context.API.ReloadAllPluginData().ContinueWith(_ => context.API.ShowMsg( @@ -352,7 +352,7 @@ namespace Flow.Launcher.Plugin.Sys IcoPath = "Images\\checkupdate.png", Action = c => { - Application.Current.MainWindow.Hide(); + context.API.HideMainWindow(); context.API.CheckForNewUpdate(); return true; } From 3dade8bbfcf5c556e5b08caab23b38aabc55f9b1 Mon Sep 17 00:00:00 2001 From: Kevin Zhang <45326534+taooceros@users.noreply.github.com> Date: Wed, 19 Feb 2025 00:03:46 -0800 Subject: [PATCH 168/259] Don't restart the jsonrpc process when reloading data. --- Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs index f95266c7f..19d7edb31 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs @@ -135,10 +135,9 @@ namespace Flow.Launcher.Core.Plugin public virtual async Task ReloadDataAsync() { - SetupJsonRPC(); try { - await RPC.InvokeAsync("reload", Context); + await RPC.InvokeAsync("reload_data", Context); } catch (RemoteMethodNotFoundException e) { From 2843236214981585fb2316ea25e675cf56bc21f3 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 19 Feb 2025 17:09:09 +0800 Subject: [PATCH 169/259] Improve documents & Improve code quality --- Flow.Launcher/CustomQueryHotkeySetting.xaml.cs | 1 + Flow.Launcher/CustomShortcutSetting.xaml.cs | 1 + Flow.Launcher/ResultListBox.xaml.cs | 1 + Flow.Launcher/ViewModel/MainViewModel.cs | 2 ++ Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs | 1 + Flow.Launcher/ViewModel/PluginViewModel.cs | 1 + Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs | 1 - Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 5 +++-- 8 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index 3db49b381..fd829afe2 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -76,6 +76,7 @@ namespace Flow.Launcher private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e) { + // if user happens to open context menu, we need to return back to query results before changing query App.API.BackToQueryResults(); App.API.ChangeQuery(tbAction.Text); Application.Current.MainWindow.Show(); diff --git a/Flow.Launcher/CustomShortcutSetting.xaml.cs b/Flow.Launcher/CustomShortcutSetting.xaml.cs index 10452726d..d05a5c15c 100644 --- a/Flow.Launcher/CustomShortcutSetting.xaml.cs +++ b/Flow.Launcher/CustomShortcutSetting.xaml.cs @@ -64,6 +64,7 @@ namespace Flow.Launcher private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e) { + // if user happens to open context menu, we need to return back to query results before changing query App.API.BackToQueryResults(); App.API.ChangeQuery(tbExpand.Text); Application.Current.MainWindow.Show(); diff --git a/Flow.Launcher/ResultListBox.xaml.cs b/Flow.Launcher/ResultListBox.xaml.cs index cc003457f..834692536 100644 --- a/Flow.Launcher/ResultListBox.xaml.cs +++ b/Flow.Launcher/ResultListBox.xaml.cs @@ -150,6 +150,7 @@ namespace Flow.Launcher var effect = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy); if (effect == DragDropEffects.Move) { + // if user happens to open context menu, we need to return back to query results before changing query App.API.BackToQueryResults(); App.API.ChangeQuery(rawQuery, true); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 5c3251bfc..4af93daf9 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1266,6 +1266,7 @@ namespace Flow.Launcher.ViewModel { _topMostRecord.Remove(result); App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success")); + // if user happens to open context menu, we need to return back to query results before changing query App.API.BackToQueryResults(); App.API.ReQuery(); return false; @@ -1284,6 +1285,7 @@ namespace Flow.Launcher.ViewModel { _topMostRecord.AddOrUpdate(result); App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success")); + // if user happens to open context menu, we need to return back to query results before changing query App.API.BackToQueryResults(); App.API.ReQuery(); return false; diff --git a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs index 97c938e78..7675ecb16 100644 --- a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs @@ -64,6 +64,7 @@ namespace Flow.Launcher.ViewModel private void ShowCommandQuery(string action) { var actionKeyword = PluginManagerData.Metadata.ActionKeywords.Any() ? PluginManagerData.Metadata.ActionKeywords[0] + " " : String.Empty; + // if user happens to open context menu, we need to return back to query results before changing query App.API.BackToQueryResults(); App.API.ChangeQuery($"{actionKeyword}{action} {_plugin.Name}"); App.API.ShowMainWindow(); diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index e56e8e9e5..c8601c431 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -146,6 +146,7 @@ namespace Flow.Launcher.ViewModel [RelayCommand] private void OpenDeletePluginWindow() { + // if user happens to open context menu, we need to return back to query results before changing query PluginManager.API.BackToQueryResults(); PluginManager.API.ChangeQuery($"{PluginManagerActionKeyword} uninstall {PluginPair.Metadata.Name}".Trim(), true); PluginManager.API.ShowMainWindow(); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs index 17e9fe2bc..482e821dc 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs @@ -59,7 +59,6 @@ namespace Flow.Launcher.Plugin.PluginsManager var link = pluginManifestInfo.UrlSourceCode.StartsWith("https://github.com") ? Regex.Replace(pluginManifestInfo.UrlSourceCode, @"\/tree\/\w+$", "") + "/issues" : pluginManifestInfo.UrlSourceCode; - Context.API.OpenUrl(link); return true; } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index 7f1f4bd4d..86808cfbc 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; -using System.Windows; using WindowsInput; using WindowsInput.Native; using Flow.Launcher.Infrastructure.Hotkey; @@ -379,9 +378,11 @@ namespace Flow.Launcher.Plugin.Shell private void OnWinRPressed() { // show the main window and set focus to the query box - Task.Run(() => + _ = Task.Run(() => { context.API.ShowMainWindow(); + // if user happens to open context menu, we need to return back to query results before changing query + context.API.BackToQueryResults(); context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}"); }); From ccf8d876ae2f96b556926f9d7df5c91347552adf Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 20 Feb 2025 14:59:16 +0800 Subject: [PATCH 170/259] Add support for hiding dulplicated windows apps --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 28 +++++++++++++++++++ .../Flow.Launcher.Plugin.Program/Settings.cs | 1 + 2 files changed, 29 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 6ba7047f2..00fb1d344 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -72,6 +72,8 @@ namespace Flow.Launcher.Plugin.Program private const string ExeUninstallerSuffix = ".exe"; private const string InkUninstallerSuffix = ".lnk"; + private const string WindowsAppPath = "c:\\program files\\windowsapps"; + static Main() { } @@ -90,11 +92,20 @@ namespace Flow.Launcher.Plugin.Program { try { + // Collect all UWP Windows app directories + var uwpsDirectories = _settings.HideDulplicatedWindowsApp ? _uwps + .Where(uwp => !string.IsNullOrEmpty(uwp.Location)) // Exclude invalid paths + .Where(uwp => uwp.Location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) // Keep system apps + .Select(uwp => uwp.Location.TrimEnd('\\')) // Remove trailing slash + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToArray() : null; + return _win32s.Cast() .Concat(_uwps) .AsParallel() .WithCancellation(token) .Where(HideUninstallersFilter) + .Where(p => HideDulplicatedWindowsAppFilter(p, uwpsDirectories)) .Where(p => p.Enabled) .Select(p => p.Result(query.Search, Context.API)) .Where(r => r?.Score > 0) @@ -152,6 +163,23 @@ namespace Flow.Launcher.Plugin.Program return true; } + private static bool HideDulplicatedWindowsAppFilter(IProgram program, string[] uwpsDirectories) + { + if (uwpsDirectories == null || uwpsDirectories.Length == 0) return true; + if (program is UWPApp) return true; + + var location = program.Location.TrimEnd('\\'); // Ensure trailing slash + if (string.IsNullOrEmpty(location)) + return true; // Keep if location is invalid + + if (!location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) + return true; // Keep if not a Windows app + + // Check if the any Win32 executable directory contains UWP Windows app location matches + return !uwpsDirectories.Any(uwpDirectory => + location.StartsWith(uwpDirectory, StringComparison.OrdinalIgnoreCase)); + } + public async Task InitAsync(PluginInitContext context) { Context = context; diff --git a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs index fb24f64d7..664277e02 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs @@ -121,6 +121,7 @@ namespace Flow.Launcher.Plugin.Program public bool EnableRegistrySource { get; set; } = true; public bool EnablePathSource { get; set; } = false; public bool EnableUWP { get; set; } = true; + public bool HideDulplicatedWindowsApp { get; set; } = true; internal const char SuffixSeparator = ';'; } From b4bffb1cf54bb0a050ea2277ffa1893b1df05c39 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 20 Feb 2025 17:17:53 +0800 Subject: [PATCH 171/259] Use null as default value for record key --- Flow.Launcher.Plugin/Result.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index bb005752e..9b16cc1cb 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -266,8 +266,9 @@ namespace Flow.Launcher.Plugin /// The key to identify the record. This is used when FL checks whether the result is the topmost record. Or FL calculates the hashcode of the result for user selected records. /// This can be useful when your plugin will change the Title or SubTitle of the result dynamically. /// If the plugin does not specific this, FL just uses Title and SubTitle to identify this result. + /// Note: Because old data does not have this key, we should use null as the default value for consistency. /// - public string RecordKey { get; set; } = string.Empty; + public string RecordKey { get; set; } = null; /// /// Info of the preview section of a From 4f41be67ac5135158d22d6f99859cda1a2f84f57 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 20 Feb 2025 18:02:59 +0800 Subject: [PATCH 172/259] Improve code quality --- Flow.Launcher.Core/Plugin/PluginManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 5c4eaa1da..8f2d78d76 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -281,7 +281,7 @@ namespace Flow.Launcher.Core.Plugin return results; } - public static void UpdatePluginMetadata(List results, PluginMetadata metadata, Query query) + public static void UpdatePluginMetadata(IReadOnlyList results, PluginMetadata metadata, Query query) { foreach (var r in results) { From 2ffe170407b0ca012b267051569e29de43c77c46 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 20 Feb 2025 18:06:15 +0800 Subject: [PATCH 173/259] Use deep clone for result updating --- Flow.Launcher/ViewModel/MainViewModel.cs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 5c3251bfc..b498f4001 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -231,8 +231,8 @@ namespace Flow.Launcher.ViewModel var token = e.Token == default ? _updateToken : e.Token; - // make a copy of results to avoid plugin change the result when updating view model - var resultsCopy = e.Results.ToList(); + // make a clone to avoid possible issue that plugin will also change the list and items when updating view model + var resultsCopy = DeepCloneResults(e.Results, token); PluginManager.UpdatePluginMetadata(resultsCopy, pair.Metadata, e.Query); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query, @@ -414,6 +414,22 @@ namespace Flow.Launcher.ViewModel } } + private static IReadOnlyList DeepCloneResults(IReadOnlyList results, CancellationToken token = default) + { + var resultsCopy = new List(); + foreach (var result in results.ToList()) + { + if (token.IsCancellationRequested) + { + break; + } + + var resultCopy = result.Clone(); + resultsCopy.Add(resultCopy); + } + return resultsCopy; + } + #endregion #region BasicCommands @@ -1469,9 +1485,9 @@ namespace Flow.Launcher.ViewModel { if (_topMostRecord.IsTopMost(result)) { - result.Score = Result.MaxScore; + result.Score = 100000; //Result.MaxScore; } - else if (result.Score != Result.MaxScore) + else { var priorityScore = metaResults.Metadata.Priority * 150; result.Score += result.AddSelectedCount ? From 9850e9d3eb6af9c78003738e23dd819336446ba4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 20 Feb 2025 18:17:29 +0800 Subject: [PATCH 174/259] Fix issue that plugin will cannot cache records --- Flow.Launcher/ViewModel/MainViewModel.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index b498f4001..e030d8eae 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1196,9 +1196,18 @@ namespace Flow.Launcher.ViewModel currentCancellationToken.ThrowIfCancellationRequested(); - results ??= _emptyResult; + IReadOnlyList resultsCopy; + if (results == null) + { + resultsCopy = _emptyResult; + } + else + { + // make a copy of results to avoid possible issue that FL changes some properties of the records, like score, etc. + resultsCopy = DeepCloneResults(results); + } - if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query, + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query, currentCancellationToken, reSelect))) { Log.Error("MainViewModel", "Unable to add item to Result Update Queue"); From 7ccfbcae7f2cef218357abd1aa842592e88a4b9f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 20 Feb 2025 23:15:12 +0800 Subject: [PATCH 175/259] Add hide dulplicated windows apps into settings panel --- .../Languages/en.xaml | 2 + .../Flow.Launcher.Plugin.Program/Settings.cs | 2 +- .../Views/ProgramSetting.xaml | 53 ++++++++++--------- .../Views/ProgramSetting.xaml.cs | 10 ++++ 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml index 7ed711e17..640b082e7 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml @@ -36,6 +36,8 @@ Hides programs with common uninstaller names, such as unins000.exe Search in Program Description Flow will search program's description + Hide dulplicated apps + Hide dulplicated Win32 programs that are already in the UWP list Suffixes Max Depth diff --git a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs index 664277e02..53cb1755d 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs @@ -121,7 +121,7 @@ namespace Flow.Launcher.Plugin.Program public bool EnableRegistrySource { get; set; } = true; public bool EnablePathSource { get; set; } = false; public bool EnableUWP { get; set; } = true; - public bool HideDulplicatedWindowsApp { get; set; } = true; + public bool HideDulplicatedWindowsApp { get; set; } = false; internal const char SuffixSeparator = ';'; } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml index e5ca6967e..0482099ad 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml @@ -8,7 +8,7 @@ DataContext="{Binding RelativeSource={RelativeSource Self}}" mc:Ignorable="d"> - + @@ -18,40 +18,40 @@ + ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}" + Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}" /> @@ -67,21 +67,20 @@ BorderBrush="{DynamicResource Color03B}" BorderThickness="1" /> @@ -91,11 +90,15 @@ IsChecked="{Binding HideUninstallers}" ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" /> + + + + diff --git a/Flow.Launcher/ReportWindow.xaml.cs b/Flow.Launcher/ReportWindow.xaml.cs index a535dfb3e..12ffe3ffc 100644 --- a/Flow.Launcher/ReportWindow.xaml.cs +++ b/Flow.Launcher/ReportWindow.xaml.cs @@ -6,10 +6,10 @@ using System.Text; using System.Linq; using System.Windows; using System.Windows.Documents; -using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Plugin.SharedCommands; +using Flow.Launcher.Infrastructure.Exception; namespace Flow.Launcher { @@ -43,32 +43,36 @@ namespace Flow.Launcher var log = directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First(); var websiteUrl = exception switch - { - FlowPluginException pluginException =>GetIssuesUrl(pluginException.Metadata.Website), - _ => Constant.IssuesUrl - }; - + { + FlowPluginException pluginException =>GetIssuesUrl(pluginException.Metadata.Website), + _ => Constant.IssuesUrl + }; - var paragraph = Hyperlink("Please open new issue in: ", websiteUrl); - paragraph.Inlines.Add($"1. upload log file: {log.FullName}\n"); - paragraph.Inlines.Add($"2. copy below exception message"); + var paragraph = Hyperlink(App.API.GetTranslation("reportWindow_please_open_issue"), websiteUrl); + paragraph.Inlines.Add(string.Format(App.API.GetTranslation("reportWindow_upload_log"), log.FullName)); + paragraph.Inlines.Add("\n"); + paragraph.Inlines.Add(App.API.GetTranslation("reportWindow_copy_below")); ErrorTextbox.Document.Blocks.Add(paragraph); StringBuilder content = new StringBuilder(); - content.AppendLine(ErrorReporting.RuntimeInfo()); - content.AppendLine(ErrorReporting.DependenciesInfo()); - content.AppendLine($"Date: {DateTime.Now.ToString(CultureInfo.InvariantCulture)}"); - content.AppendLine("Exception:"); + content.AppendLine(RuntimeInfo()); + content.AppendLine(); + content.AppendLine(DependenciesInfo()); + content.AppendLine(); + content.AppendLine(string.Format(App.API.GetTranslation("reportWindow_date"), DateTime.Now.ToString(CultureInfo.InvariantCulture))); + content.AppendLine(App.API.GetTranslation("reportWindow_exception")); content.AppendLine(exception.ToString()); paragraph = new Paragraph(); paragraph.Inlines.Add(content.ToString()); ErrorTextbox.Document.Blocks.Add(paragraph); } - private Paragraph Hyperlink(string textBeforeUrl, string url) + private static Paragraph Hyperlink(string textBeforeUrl, string url) { - var paragraph = new Paragraph(); - paragraph.Margin = new Thickness(0); + var paragraph = new Paragraph + { + Margin = new Thickness(0) + }; var link = new Hyperlink { @@ -79,10 +83,38 @@ namespace Flow.Launcher link.Click += (s, e) => SearchWeb.OpenInBrowserTab(url); paragraph.Inlines.Add(textBeforeUrl); + paragraph.Inlines.Add(" "); paragraph.Inlines.Add(link); paragraph.Inlines.Add("\n"); return paragraph; } + + private void BtnCancel_OnClick(object sender, RoutedEventArgs e) + { + Close(); + } + + private static string RuntimeInfo() + { + var info = + $""" + Flow Launcher {App.API.GetTranslation("reportWindow_version")}: {Constant.Version} + OS {App.API.GetTranslation("reportWindow_version")}: {ExceptionFormatter.GetWindowsFullVersionFromRegistry()} + IntPtr {App.API.GetTranslation("reportWindow_length")}: {IntPtr.Size} + x64: {Environment.Is64BitOperatingSystem} + """; + return info; + } + + private static string DependenciesInfo() + { + var info = + $""" + {App.API.GetTranslation("pythonFilePath")}: {Constant.PythonPath} + {App.API.GetTranslation("nodeFilePath")}: {Constant.NodePath} + """; + return info; + } } } From 2b9716aa379c3878bd5ef42bb355e4af6f9a5577 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 22 Feb 2025 13:16:09 +0800 Subject: [PATCH 183/259] Fix message box window topmost issue when disabling hide FL when loss focus --- Flow.Launcher.Core/MessageBoxEx.xaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Flow.Launcher.Core/MessageBoxEx.xaml b/Flow.Launcher.Core/MessageBoxEx.xaml index fff107a68..28cc02283 100644 --- a/Flow.Launcher.Core/MessageBoxEx.xaml +++ b/Flow.Launcher.Core/MessageBoxEx.xaml @@ -12,6 +12,7 @@ Foreground="{DynamicResource PopupTextColor}" ResizeMode="NoResize" SizeToContent="Height" + Topmost="True" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> From dd73e4b4b3962f46ada29f5a273fa5a21c17cc65 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 22 Feb 2025 15:51:36 +0800 Subject: [PATCH 184/259] Fix topmost score issue --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index e030d8eae..9bab4a3a1 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1494,7 +1494,7 @@ namespace Flow.Launcher.ViewModel { if (_topMostRecord.IsTopMost(result)) { - result.Score = 100000; //Result.MaxScore; + result.Score = Result.MaxScore; } else { From b46922885c2480b1b6dac5185c658e9e7c8c8aea Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 22 Feb 2025 15:59:38 +0800 Subject: [PATCH 185/259] Add max value check --- Flow.Launcher/ViewModel/MainViewModel.cs | 25 +++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 9bab4a3a1..a9809a49a 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1499,9 +1499,28 @@ namespace Flow.Launcher.ViewModel else { var priorityScore = metaResults.Metadata.Priority * 150; - result.Score += result.AddSelectedCount ? - _userSelectedRecord.GetSelectedCount(result) + priorityScore : - priorityScore; + if (result.AddSelectedCount) + { + if ((long)result.Score + _userSelectedRecord.GetSelectedCount(result) + priorityScore > Result.MaxScore) + { + result.Score = Result.MaxScore; + } + else + { + result.Score += _userSelectedRecord.GetSelectedCount(result) + priorityScore; + } + } + else + { + if ((long)result.Score + priorityScore > Result.MaxScore) + { + result.Score = Result.MaxScore; + } + else + { + result.Score += priorityScore; + } + } } } } From 156668e1098287328c691ed2fcb76dcc62490d10 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 22 Feb 2025 16:12:41 +0800 Subject: [PATCH 186/259] Add minimize & background option for progress box ex --- Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/ProgressBoxEx.xaml | 31 ++++++++++++++++++++++++++++- Flow.Launcher/ProgressBoxEx.xaml.cs | 11 +++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 4c465d61f..d36fd2e90 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -367,6 +367,7 @@ OK Yes No + Background Version diff --git a/Flow.Launcher/ProgressBoxEx.xaml b/Flow.Launcher/ProgressBoxEx.xaml index 3102cfb72..32b0f64b4 100644 --- a/Flow.Launcher/ProgressBoxEx.xaml +++ b/Flow.Launcher/ProgressBoxEx.xaml @@ -35,9 +35,32 @@ + + - internal abstract class JsonRPCPluginBase : IAsyncPlugin, IContextMenu, ISettingProvider, ISavable + public abstract class JsonRPCPluginBase : IAsyncPlugin, IContextMenu, ISettingProvider, ISavable { protected PluginInitContext Context; public const string JsonRPC = "JsonRPC"; @@ -157,6 +157,11 @@ namespace Flow.Launcher.Core.Plugin Settings?.Save(); } + public bool NeedCreateSettingPanel() + { + return Settings.NeedCreateSettingPanel(); + } + public Control CreateSettingPanel() { return Settings.CreateSettingPanel(); diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs index 2a4b22bf3..8412ba7e8 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs @@ -109,10 +109,15 @@ namespace Flow.Launcher.Core.Plugin _storage.Save(); } + public bool NeedCreateSettingPanel() + { + // If there are no settings or the settings configuration is empty, return null + return Settings != null && Configuration != null && Configuration.Body.Count != 0; + } + public Control CreateSettingPanel() { - if (Settings == null || Settings.Count == 0) - return null; + // No need to check if NeedCreateSettingPanel is true because CreateSettingPanel will only be called if it's true var settingWindow = new UserControl(); var mainPanel = new Grid { Margin = settingPanelMargin, VerticalAlignment = VerticalAlignment.Center }; diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 46f8e00a2..209a81395 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -90,13 +90,13 @@ namespace Flow.Launcher.ViewModel private Control _bottomPart2; public Control BottomPart2 => IsExpanded ? _bottomPart2 ??= new InstalledPluginDisplayBottomData() : null; - public bool HasSettingControl => PluginPair.Plugin is ISettingProvider settingProvider && settingProvider.CreateSettingPanel() != null; + public bool HasSettingControl => PluginPair.Plugin is ISettingProvider && (PluginPair.Plugin is not JsonRPCPluginBase jsonRPCPluginBase || jsonRPCPluginBase.NeedCreateSettingPanel()); public Control SettingControl => IsExpanded ? _settingControl - ??= PluginPair.Plugin is not ISettingProvider settingProvider - ? null - : settingProvider.CreateSettingPanel() + ??= HasSettingControl + ? ((ISettingProvider)PluginPair.Plugin).CreateSettingPanel() + : null : null; private ImageSource _image = ImageLoader.MissingImage; From 889f4cbfeb4959477c3c3db8bdaf66c527cb902e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 4 Mar 2025 11:08:09 +0800 Subject: [PATCH 231/259] Fix null reference exception when checking source --- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index f4c8a66da..4ceadec56 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -593,7 +593,10 @@ namespace Flow.Launcher.Plugin.PluginsManager var constructedUrlPart = string.Format("{0}/{1}/", acceptedSource, author); return url.StartsWith(acceptedSource) && - Context.API.GetAllPlugins().Any(x => x.Metadata.Website.StartsWith(constructedUrlPart)); + Context.API.GetAllPlugins().Any(x => + !string.IsNullOrEmpty(x.Metadata.Website) && + x.Metadata.Website.StartsWith(constructedUrlPart) + ); } internal async ValueTask> RequestInstallOrUpdateAsync(string search, CancellationToken token, From 719d30ebf0a09e54a46948a786caa6069303ca0e Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Thu, 6 Mar 2025 07:41:22 +0800 Subject: [PATCH 232/259] Use official Task Scheduler --- Flow.Launcher/Flow.Launcher.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 33d13614f..8f6e47bbb 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -104,7 +104,7 @@ - + From 69b7aeadeb09cebd6e576c4817e01fe324522af4 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Thu, 6 Mar 2025 20:07:01 +0800 Subject: [PATCH 233/259] Update dependabot.yml --- .github/dependabot.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d9b39eb89..da4231f74 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,7 +8,8 @@ updates: - package-ecosystem: "nuget" # See documentation for possible values directory: "/" # Location of package manifests schedule: - interval: "weekly" + interval: "daily" + open-pull-requests-limit: 3 ignore: - dependency-name: "squirrel-windows" reviewers: From f2c30347a762f3a29b176d6730081be3d64e3e14 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 8 Mar 2025 12:24:47 +0600 Subject: [PATCH 234/259] Add new sponsor to README --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02ffc7932..6611f55dc 100644 --- a/README.md +++ b/README.md @@ -334,11 +334,14 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea Coderabbit Logo -
-
+
+
+ + +

From 8ca734ae065813062c119f78b8b8f2fb2d99f211 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Mar 2025 03:18:48 +0000 Subject: [PATCH 235/259] Bump FSharp.Core from 9.0.101 to 9.0.201 Bumps [FSharp.Core](https://github.com/dotnet/fsharp) from 9.0.101 to 9.0.201. - [Release notes](https://github.com/dotnet/fsharp/releases) - [Changelog](https://github.com/dotnet/fsharp/blob/main/release-notes.md) - [Commits](https://github.com/dotnet/fsharp/commits) --- updated-dependencies: - dependency-name: FSharp.Core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index df2f4d2cb..5201d051a 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -54,7 +54,7 @@ - + From 66457b1dfb729a9ebed6e933f26ef9a3ecaa2709 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Mar 2025 03:19:20 +0000 Subject: [PATCH 236/259] Bump MemoryPack from 1.21.3 to 1.21.4 Bumps [MemoryPack](https://github.com/Cysharp/MemoryPack) from 1.21.3 to 1.21.4. - [Release notes](https://github.com/Cysharp/MemoryPack/releases) - [Commits](https://github.com/Cysharp/MemoryPack/compare/1.21.3...1.21.4) --- updated-dependencies: - dependency-name: MemoryPack dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Flow.Launcher.Infrastructure.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 5d8b26425..b91da7114 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -59,7 +59,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all From c1a80158e609a2573b484793ea1baa499c699404 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Mar 2025 07:24:13 +0000 Subject: [PATCH 237/259] Bump StreamJsonRpc from 2.20.20 to 2.21.10 Bumps [StreamJsonRpc](https://github.com/microsoft/vs-streamjsonrpc) from 2.20.20 to 2.21.10. - [Release notes](https://github.com/microsoft/vs-streamjsonrpc/releases) - [Commits](https://github.com/microsoft/vs-streamjsonrpc/commits) --- updated-dependencies: - dependency-name: StreamJsonRpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index 5201d051a..e9f199d00 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -58,7 +58,7 @@ - + From 65d42bf7c06aa26bb5e10c54e6cfb59e1519bc92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Mar 2025 07:25:00 +0000 Subject: [PATCH 238/259] Bump Microsoft.Data.Sqlite from 9.0.1 to 9.0.2 Bumps [Microsoft.Data.Sqlite](https://github.com/dotnet/efcore) from 9.0.1 to 9.0.2. - [Release notes](https://github.com/dotnet/efcore/releases) - [Commits](https://github.com/dotnet/efcore/compare/v9.0.1...v9.0.2) --- updated-dependencies: - dependency-name: Microsoft.Data.Sqlite dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Flow.Launcher.Plugin.BrowserBookmark.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index d7a626e1d..df534cb3f 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -95,7 +95,7 @@ - + From 8408a3cc544957d90033c34159f5a7391cbf135f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Mar 2025 07:57:00 +0000 Subject: [PATCH 239/259] Bump System.Data.OleDb from 8.0.1 to 9.0.2 Bumps [System.Data.OleDb](https://github.com/dotnet/runtime) from 8.0.1 to 9.0.2. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v8.0.1...v9.0.2) --- updated-dependencies: - dependency-name: System.Data.OleDb dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .../Flow.Launcher.Plugin.Explorer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj index 29925aeef..f5691cb73 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -45,7 +45,7 @@ - + From 869fe5f94ac512603a923b1dc282eadc26553538 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Mon, 10 Mar 2025 09:41:17 +0800 Subject: [PATCH 240/259] Revert "Bump System.Data.OleDb from 8.0.1 to 9.0.2" --- .../Flow.Launcher.Plugin.Explorer.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj index f5691cb73..549217027 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -45,7 +45,8 @@ - + + From e870dd27eb2016f7d8101660d4e4d5449f82b995 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 29 May 2024 23:48:04 +0800 Subject: [PATCH 241/259] Allow log level selection --- Flow.Launcher.Infrastructure/Logger/Log.cs | 22 +++++++++++++++---- .../UserSettings/Settings.cs | 2 ++ Flow.Launcher/App.xaml.cs | 14 ++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index d4bd473ac..cce62a1ac 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -48,17 +48,31 @@ namespace Flow.Launcher.Infrastructure.Logger configuration.AddTarget("file", fileTargetASyncWrapper); configuration.AddTarget("debug", debugTarget); + var fileRule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper) + { + RuleName = "file" + }; #if DEBUG - var fileRule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper); - var debugRule = new LoggingRule("*", LogLevel.Debug, debugTarget); + var debugRule = new LoggingRule("*", LogLevel.Debug, debugTarget) + { + RuleName = "debug" + }; configuration.LoggingRules.Add(debugRule); -#else - var fileRule = new LoggingRule("*", LogLevel.Info, fileTargetASyncWrapper); #endif configuration.LoggingRules.Add(fileRule); LogManager.Configuration = configuration; } + public static void UseDebugLogLevel() + { + LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Debug, LogLevel.Fatal); + } + + public static void UseInfoLogLevel() + { + LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Info, LogLevel.Fatal); + } + private static void LogFaultyFormat(string message) { var logger = LogManager.GetLogger("FaultyLogger"); diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 0fb6e2b3c..25beb8bf6 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -199,6 +199,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings } }; + public string LogLevel = "info"; + ///

/// when false Alphabet static service will always return empty results /// diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 447eca792..6ec0424b8 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -122,6 +122,20 @@ namespace Flow.Launcher var imageLoadertask = ImageLoader.InitializeAsync(); + switch (_settings.LogLevel) + { + case "debug": + Log.UseDebugLogLevel(); + break; + case "info": + Log.UseInfoLogLevel(); + break; + default: + Log.Error(nameof(Flow.Launcher.App), "Unrecognized log level"); + Log.UseDebugLogLevel(); + break; + } + AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings); // TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future From 44a90e53a918d3b580edb686b040d0c7cced8233 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 11 Mar 2025 23:53:33 +0800 Subject: [PATCH 242/259] Write log level in log --- Flow.Launcher.Infrastructure/Logger/Log.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index cce62a1ac..3eb53e0a3 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -66,11 +66,13 @@ namespace Flow.Launcher.Infrastructure.Logger public static void UseDebugLogLevel() { LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Debug, LogLevel.Fatal); + Info(nameof(Logger), "Using DEBUG log level."); } public static void UseInfoLogLevel() { LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Info, LogLevel.Fatal); + Info(nameof(Logger), "Using INFO log level."); } private static void LogFaultyFormat(string message) From 1dfa15d325e9f43336dcbd6eac1ee934e15f9de7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 22:13:52 +0000 Subject: [PATCH 243/259] Bump Microsoft.Data.Sqlite from 9.0.2 to 9.0.3 Bumps [Microsoft.Data.Sqlite](https://github.com/dotnet/efcore) from 9.0.2 to 9.0.3. - [Release notes](https://github.com/dotnet/efcore/releases) - [Commits](https://github.com/dotnet/efcore/compare/v9.0.2...v9.0.3) --- updated-dependencies: - dependency-name: Microsoft.Data.Sqlite dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Flow.Launcher.Plugin.BrowserBookmark.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index df534cb3f..b4e42fbcd 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -95,7 +95,7 @@ - + From 8d3fd756dd2ef5ed79113e9d4d4568b45820dbdf Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 12 Mar 2025 08:57:03 +0800 Subject: [PATCH 244/259] Add getter and setter --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 25beb8bf6..0a9d99777 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -199,7 +199,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings } }; - public string LogLevel = "info"; + public string LogLevel { get; set; } = "info"; /// /// when false Alphabet static service will always return empty results From 11acca6215a9234c0ee055d6fef816d1bde933f8 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 12:01:39 +0800 Subject: [PATCH 245/259] Move log level to enum & Use info level as default --- Flow.Launcher.Infrastructure/Logger/Log.cs | 10 ++++++++-- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 4 +++- Flow.Launcher/App.xaml.cs | 8 ++------ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 3eb53e0a3..2f368ac0c 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -66,13 +66,13 @@ namespace Flow.Launcher.Infrastructure.Logger public static void UseDebugLogLevel() { LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Debug, LogLevel.Fatal); - Info(nameof(Logger), "Using DEBUG log level."); + Info(nameof(Logger), "Using log level: DEBUG."); } public static void UseInfoLogLevel() { LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Info, LogLevel.Fatal); - Info(nameof(Logger), "Using INFO log level."); + Info(nameof(Logger), "Using log level: INFO."); } private static void LogFaultyFormat(string message) @@ -222,4 +222,10 @@ namespace Flow.Launcher.Infrastructure.Logger LogInternal(message, LogLevel.Warn); } } + + public enum LOGLEVEL + { + DEBUG, + INFO + } } diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 0a9d99777..93f6db111 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -5,6 +5,7 @@ using System.Text.Json.Serialization; using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Infrastructure.Hotkey; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedModels; @@ -199,7 +200,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings } }; - public string LogLevel { get; set; } = "info"; + [JsonConverter(typeof(JsonStringEnumConverter))] + public LOGLEVEL LogLevel { get; set; } = LOGLEVEL.INFO; /// /// when false Alphabet static service will always return empty results diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 6ec0424b8..ec4bb8dc6 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -124,15 +124,11 @@ namespace Flow.Launcher switch (_settings.LogLevel) { - case "debug": + case LOGLEVEL.DEBUG: Log.UseDebugLogLevel(); break; - case "info": - Log.UseInfoLogLevel(); - break; default: - Log.Error(nameof(Flow.Launcher.App), "Unrecognized log level"); - Log.UseDebugLogLevel(); + Log.UseInfoLogLevel(); break; } From 05ff797613c952aedde47a1cfc55efe924ab6682 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 12:26:29 +0800 Subject: [PATCH 246/259] Use one function to set log level --- Flow.Launcher.Infrastructure/Logger/Log.cs | 22 +++++++++++++++++----- Flow.Launcher/App.xaml.cs | 12 ++---------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 2f368ac0c..7f847e287 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -63,16 +63,28 @@ namespace Flow.Launcher.Infrastructure.Logger LogManager.Configuration = configuration; } - public static void UseDebugLogLevel() + public static void SetLogLevel(LOGLEVEL level) { - LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Debug, LogLevel.Fatal); - Info(nameof(Logger), "Using log level: DEBUG."); + switch (level) + { + case LOGLEVEL.DEBUG: + UseDebugLogLevel(); + break; + default: + UseInfoLogLevel(); + break; + } + Info(nameof(Logger), $"Using log level: {level}."); } - public static void UseInfoLogLevel() + private static void UseDebugLogLevel() + { + LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Debug, LogLevel.Fatal); + } + + private static void UseInfoLogLevel() { LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Info, LogLevel.Fatal); - Info(nameof(Logger), "Using log level: INFO."); } private static void LogFaultyFormat(string message) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index ec4bb8dc6..ab68cf426 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -112,6 +112,8 @@ namespace Flow.Launcher { await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { + Log.SetLogLevel(_settings.LogLevel); + Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate(); Log.Info("|App.OnStartup|Begin Flow Launcher startup ----------------------------------------------------"); @@ -122,16 +124,6 @@ namespace Flow.Launcher var imageLoadertask = ImageLoader.InitializeAsync(); - switch (_settings.LogLevel) - { - case LOGLEVEL.DEBUG: - Log.UseDebugLogLevel(); - break; - default: - Log.UseInfoLogLevel(); - break; - } - AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings); // TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future From 66bf04642a6d9857dd2c91e23a0c5385b4ccddcc Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 12:33:26 +0800 Subject: [PATCH 247/259] Add log level change to general settings page --- Flow.Launcher/Languages/en.xaml | 3 +++ .../SettingsPaneGeneralViewModel.cs | 22 +++++++++++++++++++ .../Views/SettingsPaneGeneral.xaml | 8 +++++++ 3 files changed, 33 insertions(+) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 058a51ae3..2ead21cf5 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -104,6 +104,9 @@ Always Preview Always open preview panel when Flow activates. Press {0} to toggle preview. Shadow effect is not allowed while current theme has blur effect enabled + Log level + Debug + Info Search Plugin diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs index dddaa99d4..e4f88432a 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs @@ -7,6 +7,7 @@ using Flow.Launcher.Core; using Flow.Launcher.Core.Configuration; using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedModels; @@ -31,6 +32,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel public class SearchWindowAlignData : DropdownDataGeneric { } public class SearchPrecisionData : DropdownDataGeneric { } public class LastQueryModeData : DropdownDataGeneric { } + public class LogLevelData : DropdownDataGeneric { } public bool StartFlowLauncherOnSystemStartup { @@ -143,12 +145,16 @@ public partial class SettingsPaneGeneralViewModel : BaseModel public List LastQueryModes { get; } = DropdownDataGeneric.GetValues("LastQuery"); + public List LogLevels { get; } = + DropdownDataGeneric.GetValues("LogLevel"); + private void UpdateEnumDropdownLocalizations() { DropdownDataGeneric.UpdateLabels(SearchWindowScreens); DropdownDataGeneric.UpdateLabels(SearchWindowAligns); DropdownDataGeneric.UpdateLabels(SearchPrecisionScores); DropdownDataGeneric.UpdateLabels(LastQueryModes); + DropdownDataGeneric.UpdateLabels(LogLevels); } public string Language @@ -216,6 +222,22 @@ public partial class SettingsPaneGeneralViewModel : BaseModel } } + public LOGLEVEL LogLevel + { + get => Settings.LogLevel; + set + { + if (Settings.LogLevel != value) + { + Settings.LogLevel = value; + + Log.SetLogLevel(value); + + UpdateEnumDropdownLocalizations(); + } + } + } + [RelayCommand] private void SelectPython() { diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index a80e618e8..814eda16b 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -278,6 +278,14 @@ SelectedValue="{Binding Language}" SelectedValuePath="LanguageCode" /> + + + + From b2dc128699fa0365dde4275312d0862bdcf00e24 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 18:39:14 +0800 Subject: [PATCH 248/259] Use dependency injection to fix issue --- .../Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 3ea90197d..453959ac3 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.Resource; +using Flow.Launcher.Infrastructure.UserSettings; namespace Flow.Launcher.Plugin.Sys { @@ -10,15 +11,25 @@ namespace Flow.Launcher.Plugin.Sys { public const string Keyword = "fltheme"; - private readonly PluginInitContext context; + private readonly Settings _settings; + private readonly Theme _theme; + private readonly PluginInitContext _context; + private IEnumerable themes; public ThemeSelector(PluginInitContext context) { - this.context = context; + _context = context; + _theme = Ioc.Default.GetRequiredService(); + _settings = Ioc.Default.GetRequiredService(); context.API.VisibilityChanged += OnVisibilityChanged; } + ~ThemeSelector() + { + Dispose(false); + } + public List Query(Query query) { if (query.IsReQuery) @@ -31,34 +42,34 @@ namespace Flow.Launcher.Plugin.Sys if (string.IsNullOrWhiteSpace(search)) { return themes.Select(CreateThemeResult) - .OrderBy(x => x.Title) - .ToList(); + .OrderBy(x => x.Title) + .ToList(); } - return themes.Select(theme => (theme, matchResult: context.API.FuzzySearch(search, theme))) - .Where(x => x.matchResult.IsSearchPrecisionScoreMet()) - .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData)) - .OrderBy(x => x.Title) - .ToList(); + return themes.Select(theme => (theme, matchResult: _context.API.FuzzySearch(search, theme))) + .Where(x => x.matchResult.IsSearchPrecisionScoreMet()) + .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData)) + .OrderBy(x => x.Title) + .ToList(); } private void OnVisibilityChanged(object sender, VisibilityChangedEventArgs args) { - if (args.IsVisible && !context.CurrentPluginMetadata.Disabled) + if (args.IsVisible && !_context.CurrentPluginMetadata.Disabled) { LoadThemes(); } } private void LoadThemes() - => themes = ThemeManager.Instance.LoadAvailableThemes().Select(x => x.FileNameWithoutExtension); + => themes = _theme.LoadAvailableThemes().Select(x => x.FileNameWithoutExtension); - private static Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); + private Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); - private static Result CreateThemeResult(string theme, int score, IList highlightData) + private Result CreateThemeResult(string theme, int score, IList highlightData) { string title; - if (theme == ThemeManager.Instance.Settings.Theme) + if (theme == _settings.Theme) { title = $"{theme} ★"; score = 2000; @@ -76,7 +87,7 @@ namespace Flow.Launcher.Plugin.Sys Score = score, Action = c => { - ThemeManager.Instance.ChangeTheme(theme); + _theme.ChangeTheme(theme); return true; } }; @@ -90,19 +101,16 @@ namespace Flow.Launcher.Plugin.Sys if (disposing) { // Dispose managed resources - if (context?.API != null) + if (_context?.API != null) { - context.API.VisibilityChanged -= OnVisibilityChanged; + _context.API.VisibilityChanged -= OnVisibilityChanged; } } // Free unmanaged resources disposed = true; } } - ~ThemeSelector() - { - Dispose(false); - } + public void Dispose() { Dispose(true); From 59fbef1d7866b1cfa56871f9718ba53eb81eb44a Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 18:45:57 +0800 Subject: [PATCH 249/259] Use public current theme --- Flow.Launcher.Core/Resource/Theme.cs | 3 ++- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 4deea1f66..cda125a39 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -12,7 +12,6 @@ using System.Windows.Shell; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; -using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Plugin; namespace Flow.Launcher.Core.Resource @@ -35,6 +34,8 @@ namespace Flow.Launcher.Core.Resource private string DirectoryPath => Path.Combine(Constant.ProgramDirectory, Folder); private string UserDirectoryPath => Path.Combine(DataLocation.DataDirectory(), Folder); + public string CurrentTheme => _settings.Theme; + public bool BlurEnabled { get; set; } private double mainWindowWidth; diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 453959ac3..82c06c280 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.Resource; -using Flow.Launcher.Infrastructure.UserSettings; namespace Flow.Launcher.Plugin.Sys { @@ -11,7 +10,6 @@ namespace Flow.Launcher.Plugin.Sys { public const string Keyword = "fltheme"; - private readonly Settings _settings; private readonly Theme _theme; private readonly PluginInitContext _context; @@ -21,7 +19,6 @@ namespace Flow.Launcher.Plugin.Sys { _context = context; _theme = Ioc.Default.GetRequiredService(); - _settings = Ioc.Default.GetRequiredService(); context.API.VisibilityChanged += OnVisibilityChanged; } @@ -69,7 +66,7 @@ namespace Flow.Launcher.Plugin.Sys private Result CreateThemeResult(string theme, int score, IList highlightData) { string title; - if (theme == _settings.Theme) + if (theme == _theme.CurrentTheme) { title = $"{theme} ★"; score = 2000; From 9395b89a54b143768528a3f522fed75b3e06d6c3 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 18:53:00 +0800 Subject: [PATCH 250/259] Make default score larger --- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 82c06c280..9cf6a0dd3 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -74,6 +74,8 @@ namespace Flow.Launcher.Plugin.Sys else { title = theme; + // Set them to 1000 so that they are higher than other non-theme records + score = 1000; } return new Result From 468c0b23c053c6d0320c8d066a808f268dd83232 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 18:54:43 +0800 Subject: [PATCH 251/259] Change ico & glyph --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 4 ++-- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 4aa7c5438..c41e159dc 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -464,8 +464,8 @@ namespace Flow.Launcher.Plugin.Sys { Title = "Set Flow Launcher Theme", SubTitle = context.API.GetTranslation("flowlauncher_plugin_sys_theme_selector"), - IcoPath = "Images\\theme_selector.png", - Glyph = new GlyphInfo("/Resources/#Segoe Fluent Icons", "\ue790"), + IcoPath = "Images\\app.png", + Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\ue7fc"), Action = c => { context.API.ChangeQuery($"{ThemeSelector.Keyword} "); diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 9cf6a0dd3..658c3b0a8 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -82,6 +82,7 @@ namespace Flow.Launcher.Plugin.Sys { Title = title, TitleHighlightData = highlightData, + IcoPath = "Images\\theme_selector.png", Glyph = new GlyphInfo("/Resources/#Segoe Fluent Icons", "\ue790"), Score = score, Action = c => From bad304b38f25aeddbb20a2c57a8d13704e99230f Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 21:50:39 +0800 Subject: [PATCH 252/259] Query themes every time --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 8 +-- .../Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 54 ++----------------- 2 files changed, 5 insertions(+), 57 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index c41e159dc..28747cc7c 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -7,7 +7,6 @@ using System.Windows; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; -using Flow.Launcher.Plugin.SharedCommands; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Security; @@ -17,7 +16,7 @@ using Control = System.Windows.Controls.Control; namespace Flow.Launcher.Plugin.Sys { - public class Main : IPlugin, ISettingProvider, IPluginI18n, IDisposable + public class Main : IPlugin, ISettingProvider, IPluginI18n { private PluginInitContext context; private ThemeSelector themeSelector; @@ -486,10 +485,5 @@ namespace Flow.Launcher.Plugin.Sys { return context.API.GetTranslation("flowlauncher_plugin_sys_plugin_description"); } - - public void Dispose() - { - themeSelector.Dispose(); - } } } diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 658c3b0a8..bbc45c180 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -1,38 +1,26 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.Resource; namespace Flow.Launcher.Plugin.Sys { - public class ThemeSelector : IDisposable + public class ThemeSelector { public const string Keyword = "fltheme"; private readonly Theme _theme; private readonly PluginInitContext _context; - private IEnumerable themes; - public ThemeSelector(PluginInitContext context) { _context = context; _theme = Ioc.Default.GetRequiredService(); - context.API.VisibilityChanged += OnVisibilityChanged; - } - - ~ThemeSelector() - { - Dispose(false); } public List Query(Query query) { - if (query.IsReQuery) - { - LoadThemes(); - } + var themes = _theme.LoadAvailableThemes().Select(x => x.FileNameWithoutExtension); string search = query.SecondToEndSearch; @@ -50,17 +38,6 @@ namespace Flow.Launcher.Plugin.Sys .ToList(); } - private void OnVisibilityChanged(object sender, VisibilityChangedEventArgs args) - { - if (args.IsVisible && !_context.CurrentPluginMetadata.Disabled) - { - LoadThemes(); - } - } - - private void LoadThemes() - => themes = _theme.LoadAvailableThemes().Select(x => x.FileNameWithoutExtension); - private Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); private Result CreateThemeResult(string theme, int score, IList highlightData) @@ -69,6 +46,7 @@ namespace Flow.Launcher.Plugin.Sys if (theme == _theme.CurrentTheme) { title = $"{theme} ★"; + // Set current theme to the top score = 2000; } else @@ -92,29 +70,5 @@ namespace Flow.Launcher.Plugin.Sys } }; } - - private bool disposed; - protected virtual void Dispose(bool disposing) - { - if (!disposed) - { - if (disposing) - { - // Dispose managed resources - if (_context?.API != null) - { - _context.API.VisibilityChanged -= OnVisibilityChanged; - } - } - // Free unmanaged resources - disposed = true; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } } } From 94774b25589f491114679ea60c4297dd265acb82 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 21:59:04 +0800 Subject: [PATCH 253/259] Requery and do not close window --- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index bbc45c180..70aa74d77 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -66,7 +66,8 @@ namespace Flow.Launcher.Plugin.Sys Action = c => { _theme.ChangeTheme(theme); - return true; + _context.API.ReQuery(); + return false; } }; } From d099a392c5cbf91157587791fac2e37b2139f26e Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Wed, 12 Mar 2025 22:23:52 +0800 Subject: [PATCH 254/259] Fix theme change drop shadow effect issue & Add theme description --- .../Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 86 ++++++++++++++++--- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 70aa74d77..066f62c4e 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -2,6 +2,7 @@ using System.Linq; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.Resource; +using Flow.Launcher.Infrastructure.UserSettings; namespace Flow.Launcher.Plugin.Sys { @@ -9,9 +10,56 @@ namespace Flow.Launcher.Plugin.Sys { public const string Keyword = "fltheme"; + private readonly Settings _settings; private readonly Theme _theme; private readonly PluginInitContext _context; + #region Theme Selection + + // Theme select codes from SettingsPaneThemeViewModel.cs + + private Theme.ThemeData _selectedTheme; + private Theme.ThemeData SelectedTheme + { + get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.CurrentTheme); + set + { + _selectedTheme = value; + _theme.ChangeTheme(value.FileNameWithoutExtension); + + if (_theme.BlurEnabled && _settings.UseDropShadowEffect) + DropShadowEffect = false; + } + } + + private List Themes => _theme.LoadAvailableThemes(); + + private bool DropShadowEffect + { + get => _settings.UseDropShadowEffect; + set + { + if (_theme.BlurEnabled && value) + { + _context.API.ShowMsgBox(_context.API.GetTranslation("shadowEffectNotAllowed")); + return; + } + + if (value) + { + _theme.AddDropShadowEffectToCurrentTheme(); + } + else + { + _theme.RemoveDropShadowEffectFromCurrentTheme(); + } + + _settings.UseDropShadowEffect = value; + } + } + + #endregion + public ThemeSelector(PluginInitContext context) { _context = context; @@ -20,52 +68,66 @@ namespace Flow.Launcher.Plugin.Sys public List Query(Query query) { - var themes = _theme.LoadAvailableThemes().Select(x => x.FileNameWithoutExtension); - - string search = query.SecondToEndSearch; - + var search = query.SecondToEndSearch; if (string.IsNullOrWhiteSpace(search)) { - return themes.Select(CreateThemeResult) + return Themes.Select(CreateThemeResult) .OrderBy(x => x.Title) .ToList(); } - return themes.Select(theme => (theme, matchResult: _context.API.FuzzySearch(search, theme))) + return Themes.Select(theme => (theme, matchResult: _context.API.FuzzySearch(search, theme.Name))) .Where(x => x.matchResult.IsSearchPrecisionScoreMet()) .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData)) .OrderBy(x => x.Title) .ToList(); } - private Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null); + private Result CreateThemeResult(Theme.ThemeData theme) => CreateThemeResult(theme, 0, null); - private Result CreateThemeResult(string theme, int score, IList highlightData) + private Result CreateThemeResult(Theme.ThemeData theme, int score, IList highlightData) { + string themeName = theme.Name; string title; - if (theme == _theme.CurrentTheme) + if (theme == SelectedTheme) { - title = $"{theme} ★"; + title = $"{theme.Name} ★"; // Set current theme to the top score = 2000; } else { - title = theme; + title = theme.Name; // Set them to 1000 so that they are higher than other non-theme records score = 1000; } + string description = string.Empty; + if (theme.IsDark == true) + { + description += _context.API.GetTranslation("TypeIsDarkToolTip"); + if (theme.HasBlur == true) + { + description += ""; + description += _context.API.GetTranslation("TypeHasBlurToolTip"); + } + } + else if (theme.HasBlur == true) + { + description += _context.API.GetTranslation("TypeHasBlurToolTip"); + } + return new Result { Title = title, TitleHighlightData = highlightData, + SubTitle = description, IcoPath = "Images\\theme_selector.png", Glyph = new GlyphInfo("/Resources/#Segoe Fluent Icons", "\ue790"), Score = score, Action = c => { - _theme.ChangeTheme(theme); + SelectedTheme = theme; _context.API.ReQuery(); return false; } From b2f8ad9fb9bd6b25f94b029856e39f66ca2b2147 Mon Sep 17 00:00:00 2001 From: Odotocodot <48138990+Odotocodot@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:02:42 +0000 Subject: [PATCH 255/259] Fix null exception --- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 066f62c4e..24eff0017 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -64,6 +64,7 @@ namespace Flow.Launcher.Plugin.Sys { _context = context; _theme = Ioc.Default.GetRequiredService(); + _settings = Ioc.Default.GetRequiredService(); } public List Query(Query query) From 84cd1a84ac00dd301eb638f9c2293906efe30076 Mon Sep 17 00:00:00 2001 From: Odotocodot <48138990+Odotocodot@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:05:50 +0000 Subject: [PATCH 256/259] Remove extra code --- .../Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 41 ++++--------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 24eff0017..38619cbbc 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -16,7 +16,7 @@ namespace Flow.Launcher.Plugin.Sys #region Theme Selection - // Theme select codes from SettingsPaneThemeViewModel.cs + // Theme select codes simplified from SettingsPaneThemeViewModel.cs private Theme.ThemeData _selectedTheme; private Theme.ThemeData SelectedTheme @@ -28,36 +28,15 @@ namespace Flow.Launcher.Plugin.Sys _theme.ChangeTheme(value.FileNameWithoutExtension); if (_theme.BlurEnabled && _settings.UseDropShadowEffect) - DropShadowEffect = false; + { + _theme.RemoveDropShadowEffectFromCurrentTheme(); + _settings.UseDropShadowEffect = false; + } } } private List Themes => _theme.LoadAvailableThemes(); - private bool DropShadowEffect - { - get => _settings.UseDropShadowEffect; - set - { - if (_theme.BlurEnabled && value) - { - _context.API.ShowMsgBox(_context.API.GetTranslation("shadowEffectNotAllowed")); - return; - } - - if (value) - { - _theme.AddDropShadowEffectToCurrentTheme(); - } - else - { - _theme.RemoveDropShadowEffectFromCurrentTheme(); - } - - _settings.UseDropShadowEffect = value; - } - } - #endregion public ThemeSelector(PluginInitContext context) @@ -107,14 +86,12 @@ namespace Flow.Launcher.Plugin.Sys if (theme.IsDark == true) { description += _context.API.GetTranslation("TypeIsDarkToolTip"); - if (theme.HasBlur == true) - { - description += ""; - description += _context.API.GetTranslation("TypeHasBlurToolTip"); - } } - else if (theme.HasBlur == true) + + if (theme.HasBlur == true) { + if (!string.IsNullOrEmpty(description)) + description += " "; description += _context.API.GetTranslation("TypeHasBlurToolTip"); } From e8be131221a55d84a4d60fd5680c4006ab5f096f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 13 Mar 2025 12:53:26 +0800 Subject: [PATCH 257/259] Move log level to about page --- .../ViewModels/SettingsPaneAboutViewModel.cs | 27 ++++++++++++++++++- .../SettingsPaneGeneralViewModel.cs | 23 ---------------- .../SettingPages/Views/SettingsPaneAbout.xaml | 8 ++++++ .../Views/SettingsPaneGeneral.xaml | 8 ------ 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs index ade650284..6b44be7c1 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs @@ -8,6 +8,7 @@ using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core; using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -45,10 +46,35 @@ public partial class SettingsPaneAboutViewModel : BaseModel _settings.ActivateTimes ); + public class LogLevelData : DropdownDataGeneric { } + + public List LogLevels { get; } = + DropdownDataGeneric.GetValues("LogLevel"); + + public LOGLEVEL LogLevel + { + get => _settings.LogLevel; + set + { + if (_settings.LogLevel != value) + { + _settings.LogLevel = value; + + Log.SetLogLevel(value); + } + } + } + public SettingsPaneAboutViewModel(Settings settings, Updater updater) { _settings = settings; _updater = updater; + UpdateEnumDropdownLocalizations(); + } + + private void UpdateEnumDropdownLocalizations() + { + DropdownDataGeneric.UpdateLabels(LogLevels); } [RelayCommand] @@ -138,5 +164,4 @@ public partial class SettingsPaneAboutViewModel : BaseModel return "0 B"; } - } diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs index e4f88432a..de4f158ad 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Windows.Forms; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core; using Flow.Launcher.Core.Configuration; using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; -using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedModels; @@ -32,7 +30,6 @@ public partial class SettingsPaneGeneralViewModel : BaseModel public class SearchWindowAlignData : DropdownDataGeneric { } public class SearchPrecisionData : DropdownDataGeneric { } public class LastQueryModeData : DropdownDataGeneric { } - public class LogLevelData : DropdownDataGeneric { } public bool StartFlowLauncherOnSystemStartup { @@ -145,16 +142,12 @@ public partial class SettingsPaneGeneralViewModel : BaseModel public List LastQueryModes { get; } = DropdownDataGeneric.GetValues("LastQuery"); - public List LogLevels { get; } = - DropdownDataGeneric.GetValues("LogLevel"); - private void UpdateEnumDropdownLocalizations() { DropdownDataGeneric.UpdateLabels(SearchWindowScreens); DropdownDataGeneric.UpdateLabels(SearchWindowAligns); DropdownDataGeneric.UpdateLabels(SearchPrecisionScores); DropdownDataGeneric.UpdateLabels(LastQueryModes); - DropdownDataGeneric.UpdateLabels(LogLevels); } public string Language @@ -222,22 +215,6 @@ public partial class SettingsPaneGeneralViewModel : BaseModel } } - public LOGLEVEL LogLevel - { - get => Settings.LogLevel; - set - { - if (Settings.LogLevel != value) - { - Settings.LogLevel = value; - - Log.SetLogLevel(value); - - UpdateEnumDropdownLocalizations(); - } - } - } - [RelayCommand] private void SelectPython() { diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml index e33fee02b..3ca8e163a 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml @@ -123,6 +123,14 @@ + + + + - - - - From f24d64afec925923a81b1e2735f06be761e6d5de Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 13 Mar 2025 13:06:25 +0800 Subject: [PATCH 258/259] Add log level glyph --- Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml index 3ca8e163a..75c513411 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml @@ -123,7 +123,7 @@ - + Date: Thu, 13 Mar 2025 13:13:14 +0800 Subject: [PATCH 259/259] Fix strings --- Flow.Launcher/Languages/en.xaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 2ead21cf5..a3f87cd30 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -104,9 +104,6 @@ Always Preview Always open preview panel when Flow activates. Press {0} to toggle preview. Shadow effect is not allowed while current theme has blur effect enabled - Log level - Debug - Info Search Plugin @@ -303,6 +300,9 @@ User Data Location User settings and installed plugins are saved in the user data folder. This location may vary depending on whether it's in portable mode or not. Open Folder + Log Level + Debug + Info Select File Manager