From ecd1c9badcfa8d91840aa9cc7fc688656e53d815 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:23:50 -0400 Subject: [PATCH 01/20] chore(linux): new hidden at launch strategy Needed due to changes in the new version of Flutter. Without the change it fails to build. --- linux/my_application.cc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/linux/my_application.cc b/linux/my_application.cc index b53f8381..8f53e409 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -48,17 +48,10 @@ static void my_application_activate(GApplication* application) { } gtk_window_set_default_size(window, 530, 600); - - /* --------------------------------- Custom --------------------------------- */ - /// Hide window by default so we can manipulate size, frame, etc and - /// then show the window when we are ready. - /// - /// `gtk_widget_realize` will create the window without showing it, - /// then the Dart code can call `window_size.setWindowVisibility(visible: true);`. - // gtk_widget_show(GTK_WIDGET(window)); <-- Previous implementation. - gtk_widget_realize(GTK_WIDGET(window)); + gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); @@ -67,6 +60,10 @@ static void my_application_activate(GApplication* application) { fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + // Immediately hide the window once it has been initialized. + // This allows the Dart code to show the window when it is ready. + gtk_widget_hide(GTK_WIDGET(window)); + gtk_widget_grab_focus(GTK_WIDGET(view)); } From c70127def42f3014e713d0c1330329c9f9aef847 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:25:17 -0400 Subject: [PATCH 02/20] fix(linux): missing window icons in Wayland The icon in window decorations and task switchers was missing when running on Wayland. This was due to GTK code not setting the mapping between the application ID and the name of the desktop file. --- linux/CMakeLists.txt | 2 +- linux/my_application.cc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index cff06dcf..93b5a63e 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10) project(runner LANGUAGES CXX) set(BINARY_NAME "nyrna") -set(APPLICATION_ID "codes.merritt.nyrna") +set(APPLICATION_ID "codes.merritt.Nyrna") cmake_policy(SET CMP0063 NEW) diff --git a/linux/my_application.cc b/linux/my_application.cc index 8f53e409..e68f360d 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -102,6 +102,10 @@ static void my_application_class_init(MyApplicationClass* klass) { static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { + // Set the application ID for Wayland. This is required for mapping the + // running application to the metadata in the desktop file. + g_set_prgname(APPLICATION_ID); + return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, "flags", G_APPLICATION_NON_UNIQUE, From 8c42f0ab1e7302a4a5b1353dc8328f950e0324b7 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:31:30 -0400 Subject: [PATCH 03/20] ci: check line length in tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 38b67bcf..23bf27ea 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,7 +33,7 @@ jobs: flutter pub get - name: Verify formatting - run: dart format -o none --set-exit-if-changed . + run: dart format -o none --set-exit-if-changed --line-length=90 . - name: Run code generation run: flutter pub run build_runner build --delete-conflicting-outputs From abcac91ab55529b090946bb13eaaaee2c4d1ab28 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:46:07 -0400 Subject: [PATCH 04/20] fix: adhere to store guidelines for icon layout Resolves the errors for the icon on Flathub: https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/quality-guidelines#app-icon --- assets/icons/codes.merritt.Nyrna.ico | Bin 6773 -> 7425 bytes assets/icons/codes.merritt.Nyrna.png | Bin 6988 -> 16901 bytes assets/icons/codes.merritt.Nyrna.svg | 19 +-- .../icons/src/codes.merritt.Nyrna.Source.svg | 159 ++++++++++++++++++ 4 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 assets/icons/src/codes.merritt.Nyrna.Source.svg diff --git a/assets/icons/codes.merritt.Nyrna.ico b/assets/icons/codes.merritt.Nyrna.ico index 603b46e2fba09ac1774539e4af5551f594c6ee04..dbe30dfa7498243ee59a59f437b6641139374827 100644 GIT binary patch literal 7425 zcmb_>i$BwE`2Kq{EOJ<8qa3F)sZ??Z*{ZGR;8;<~D5X>mIcsbqho+EDP9cQq!=xO_ zVRK4__^8NvRv&b&U-vTzLV$np3jygs-!&iz z2Y$ciV7E^}ZnYfvRl(MV;spN{{;wtt0#2G_}ZI#);-JD{Pykb&GWfzQxs$%<1NJ2>dEafTzZ){H?3=tG5$^TugM% zt-(0nwefN+yLQ2FbF-R4x?29^!bE*W7vWG~XUWUi`pKNXMIE7b_a{qU9tqB~q5SV( z@kyeyo=rzmKN|c)Qk`vjqdAB~^LEY$c<5HR_ue{=Fw1Zy#>pN@`wQOR!P% z!8ho}Qygpc4rb!0BJ8<~*YgTg{y70Yte71}V5g4y&-5MIS=nJa*5f14_)+2VKA^9h z$Ue*^erEig$heS4)RNJT`t;YGogCY$ zm6(^VP&VK@HuuP7!SaVPRb=7%^pr7jI8FI_%n4sd6opc7qlJX~#pObgA5_LVXOnn) zZGD-J`IS}^xK>?Z8*KxUKyVrq_yx2#@EgVkouCYbM|{?J@)Lf~2~`9JV{lnCp6u5! z{dH_8I&5vNa5s-XRdp(fHQ?(ER^PZpP-QHcuefVuHhUK-R9p}xQ`MLY0b2$mL$Nzo zUaTpZOH4TICNiVl#FvErZTj|cETD*%a zv~KKkne~i|N}+?J-&Yd|5ABv>F27Mu+o~tEm@@DjP?)C}f&ktu;(Hj**&C()KSdJ^KGQDMN127!K2Gk}5(c zBzTpJjYFT%5TC44rTBk(4|qURtp;0yzqQ)mV<#lEaG=A{{}VG;3E{g#v^wl(#VU=i zg{J6}qxJJxI12c)h&1Rz?_D7eMij?IcF7=KH$36Upy_IK@dJVm!Rc~KPK>$TgW^4Z z;*btr2-g*Ong%t1CT`O14!@vdn|JQ46n)G%=~=?-LN-YYWnyCRPw!mSzs$DH&JbH4 znrt%UV6BBO5&oY%9S;XuYJ_>PwKbf;fwrAoFt+6N*5jxZH~ibT%8^AV54r88IBQ}5 zM}P6CwuIq?XAR_*+F_J2Z;p$`9ig{}q2C`Am{N)k%SmMHMGz~Y>6m*oMddI(jezD? z67Km#ayR1ayNiFz`7;BSN|a`SQsuBI!|&{A07wC)TfsfTfXC#->Lm|OOGrk@^FM8K z0hTS=mEv2v!jGKFJSB^!fA`6XEh}T=WXAWjSwd5zEqJK~)E2G3(|y;u`C9c$f3Rly z{VUFPfKxOJj6y_)km_cL%}lUiu^EUDJ$LQEJLgyMY{EukA(c}|jo`xrlG6UoWs)WM zp%-{AGG*192I0aK0;w$K%ukJ8K#wBKG2|1DsfhNmN_*&0#yEkK^t08dncKq)3rIiM3wc; zNBqP4J`Eh9>Sc1qq(;2hHlkzoxQqPn5u458Jfs@R~d8nuvCxj?U^v&K{#I53*?TL$oU%@un ztl?2qn2d*x27~@}EVUBd+}e0L*<=$@)6&A8T7GcJnJ*%zS@sJ20<}#hb)ALujM>_o z3Q{?!wtMkgOB-SikaAw07tVFY512SE$598zLB@!mf8OX?Muy*NjxcY@I;UUs|5oFoJlBK*Lp@cFaogt z@9;wKeb13d!wZ^6Ahx>r-?E_dOy2j=f?FH5bk?G`b3-4a6K?m+4b<1cx`cki5`MXb z$VQ~0^>f@_ym(iQv!2~SB^MO1xmsHEE|9Yg>x5%@M6o^e(f_T%SY{>qi?rWg>$0}Z zN%1fd5|Alu^xA>ldtwMWr$i?f);JAF{rw}K5;}EZpnUXN*8(=YK}uVpDBGug&9-NV zm!bCdsNbD*BJz}|$bZSi&-CasXl8gosmAkT0BiF)Ga>HfjB3Qz}xSKeD?9q z7o|@Y7O#P7Cbj%ej2&f@vtmw$23r+aC6XRR$7_{?9L$ZYc54L&>AC>Q!a-O6t(R-{miDvcq8#7)%t&MqtMnwi1r6ZD(Kv*{gF?QYdSUch&>+#LdVZu9X{OW6MExI)R7q(z!u)&t<}<|AjiC_UOQOTSrbA zKSP8JY+5e6p_eue|N=Br7pez&i;d01^P$~&w*`Swv z^_Y0y^(`aqS*|OBzG406#}8@FgWe3I4f^Xi1r;@w39(30diyds1mPP(%Hf9WD;8RJ zUS%yl*b_g^Cc(bv9N=#ETF9)SNh!W><-}lMhuIWC`JCm%A+4guXPq06sxAu;dNPmV z7^%E_^2Mk8Ft3#r znmxAx$!3BC0aQ9b^2#0^UARZbM0J}E86py6&%6mU+FT-4c4pp5?2 zd?X+r76IPB*W+jjTH^|{9IriyPoOKx3027YYCHSshBwj`x}Ki?OW;=xZ;EnU-m!aQ zD!Jy+%YhT&H|{BgvXLoBTiLW7#yn&eFBYG{X-WO1`jFtUTnZO|DDo~jxZuwk=O%96 zM(fKx=M>>*WrQ@5_n55HR7#{_p=$z-wYE&2OJfT@ljC&&C5RIKZo6ZMd_>CkTwWuA zkc)O*Ajpx~Yj-4khN|3*mzS@5`!nt)tS;!^q$Kbfg*$Ocn;)bt^JY;c+ zf>1YCi62kePCLJNzj)^7dpt{hif>4JDjsUK#WMH1hRNbZ~ReAiK1~s!W`swKom$wH{K7MhFGi`RFqKY-AFK@Au)V3G_)&QM& zO7+lbzn{5VqzQ4j+1cQfd4O%PCmdQE7iVQ%x5PC(yqCeb`rzg2kWadi7@Ihr3)e@K z2t>@3;T{k>$0l^G#=PDy(mzr*p8ZZ6Aif8>>~K=kW7jeC=U3^Rf&{F^bOrjk^J8&B|qS2#!=HhC*0w^IHGS3<%{fWUSM@QzS7nr<){ zXwT$TMdvIu)7PD#PnYoleeUfR^)zMr?RC7YV>MUMVg#c^_&SI|SK#;dB*D0M6NC-^ zvqK1E&dSfNnH(ZW252v~sez-VHL&JY4s0GAbA{h@*op+2a>pfub9+LQMZV&-OsxAIA*;qh7*K^jCbX4WAvF zM(L;n4Y$y8Iy>I$W4<7S#yh~YwtXaT1$mpydb{m31EoSK%SjEYD8ltQQ7RO=ESwo| zJZz@5^qHgqFvl`02QR0~RE?BE3AZUCLnI8!F+9^;w%6@+{V5UN8RerCBU!L-wFfND zH9@At&=xnen{{&Pdgv_z7Ze4{JeaB>RW*d;>obS_hl0lpaf}VE+D$o2AD#;}gHk>l z0+tGGL!qM$B~=?Br_q)Xb)3=WraI_dG)c09y*z4~59dKP7?h5$Y%k3ZYzqvk9C^L% ztAZc$T*Nt&tuzsv#NE;J_=q;+1?T1J%D(md`0C@~`*dXL zMGE8bMCgtIG|*ra^#HO-e>aJ;2!3lP^0RSAMb{+_?8g)jDAms$8V7X)B z#hhd_mjwd<%2W702k_5Z)S5V&?%k*=iGway9Kp5(`+vUi^%~hqz5dUp@f;#_W>=Z? zI$6?u`W(AOn}W*d**TgRbZ|Y)ll_nYzF7c02$*)zi-}MlmKox|_y>WcNmmW~)Psgj z+fPvb5uJO7-~ijrKr6U9&ar5rCz&}=MyQbrXop4(!4Kq0Yn?DD1X{`%ziUrZ?VZYy zlDW#2wOXZhM-j@2v~qo9fMWgp$<|%K2JQ#@YAk$n89VW7kc4>|WXlng{+{ws3>o?; zLRZ=yj1zr!R%U4|{PbhPx{s1y$hd$+Su6N*hv;qfV*Q5S|KYd<2MvtP<6H(~c}cmz zM8A~>v(!9TrO`A=KYh~@QX4k)&&1BOVptw27-i|)=TeL{rS-?*fcpIrTTxL9pRr?2 zPU88I{NfNWsMLPW1*(v~idnsLFd%;JIB>L}nF3|(Se7(t^nzUVl-(5Qn@jBD_PECC z06@R2n1&clSRTv_MBG#FEtZ@Z&fRF`?YY>x>k(df1CoT33gFQ)8{ zoY32W|MjwsexOj?+rU=EaZ$&;qh#*Uvh&bZvU}pp71OyoKanGIcFgcHFf?}1Ppoz+ zo{f-g8Vb#XcSt1Y$dOH@bw143$}w9cwypV|U!4-Uf?iF~>9C+S-#SBg8+Xova3q~A zq)6>gXYj3iGA7Y${YPUB>aD94?X3O{aDX=aL9Lu#^6i%YRo6>@=D$1mCup1m;UhnV z4^6iEI~3)}4~G!wKf}I?kDqk(0$WA}cmn=Q0SK(%;H!VMxHll=>iPHWy#l-ezcxpfB;F-A6$vhCJm1e6zO!fxK!@zg z;8k%o$zK$iy)-l0ax_%ntFh4ejIMj`tN9dl`PmUaz-1d=-PS{Cuty^Du5Cg4__SAjU^8agx?Vi{tb4|Z zXvQmcG_c-iE*Ga1s)1$xgX@$PHfhV4BXHzPC4g`Q^;InTR{XqY!v?jjjUX|=@Z}Zz zLO<$jz%~beb0!Uta!iWjZ8zwi+bSKQM)T7--+#oP9fi~H!2vhmttT7Py$gxRPTuRA z0K$|?4CiX1k>WFThtxE`qimA940o{v4&AFdd3{q=y{gV6>|e$Pwh1-df*gUri+O1Q z7*5^)`EB5*vT2IWyM`Cz7K)&^c>w!P`1()$_tERdPFU7n@$f7x1_@(VMq?3CfnOnG zZ@6M?zOuf5v%Xnrl>?(!OEUD8d*^hz&9|IR;4Z(3@FA)nc6Y4;qfa6*>x0Sc&4<5zDshUyyfd8?tUk=7OL_is zOXNDVREozY#V@#~-IZ>l;)5n)q@#vdWO_Mdf=&za9^F(PC>%}$DQ zwm$^eJvMX_9!Y{(@%?5sU~(@DN+i8&$S?tBiHMXVzZiZg_na2uB(1d53&u;8&N5L> zB3ZKq4~4VbBH?x3t}SP;gF{_xKb*-mR~1O%{``TDM|h*Gww=fpw2dy#I*0A`0JMAp zW_~ai07DPiMByJt%SNeKEtIv42+ZYi8_z}5B%^*p=E^I>LXq_+^8*%KPwVSFBV^5!g%Z8GZbOEtxEZ4MGRR*%J~S{5{KM(~S$D zLhP6;K0wLV$0;}8G`L@R=(+%3_Z(Xw&3v$q0NgY`6zkRjXq@9)L>*fbW zoLt9;j>R_H3lzRlOvlCMJR9N7v(xyvHvIWykl7 zEr+q+*i4;HQjH9hNGhhlyIS>ksRP zeYr_|TpHII)f0fj^nH=`eCwz1h1RrL%$N-c`@X5QO8O1OeC`WY#^S@%aQto#$V&ew z`ML+8lh{dgm@F9q<^YOQtzJsZ9;HoE0CCf8yg&Zkwr~XWm*DoQiM9j`i$cYBezVG^ zC=AFBEr>NqFG5jy-jH?rmmO-`3Z~g3@$(dl(<&C#|Fy0oHbLRF)R%?1VE>JniLuyp~*?7A{zUQzNe2V>dz97Yul6PI22x$*JDHD{8!f!UfTdr+i z&di~Cbyg@pnGs}Ft`E5bYTh;pP+a=X%_F+6n5_M*$^5ah9bBB6!wGtO7^sYW;mlbz z^Rfh~n=ya?7M`A;88ad{oyRVgEH94nnWw^gesL}imsYf{Mu(z$K<@`%+kEA{v)t!M z-%%^62W3JyvmQCwaNA(4)=}`#zjJ4-ycK)}_xmUS^LcqZa;IL3#F}-nod-`)hopqx zo}6%4i1c`;0mo4(OyVVv+B5p2t@{HQt-gx9!XOmRGiv6C&ZEu)7UvPlx>8Heg`j|+3MtNLDPn5|)!RI>BJ;!PK)Ysa(4))D?sUa8b2?I2whr?+3y!y)jprP@(ScY8$tKfqrz1^@s6 literal 6773 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 JIwQ}-{{w_^X*U1> diff --git a/assets/icons/codes.merritt.Nyrna.svg b/assets/icons/codes.merritt.Nyrna.svg index a68664bd..6350ac37 100644 --- a/assets/icons/codes.merritt.Nyrna.svg +++ b/assets/icons/codes.merritt.Nyrna.svg @@ -6,16 +6,11 @@ height="512" viewBox="0 0 512 512" version="1.1" - id="svg5" + id="svg1" + xml:space="preserve" xmlns="http://www.w3.org/2000/svg" - xmlns:svg="http://www.w3.org/2000/svg"> - - - - - + xmlns:svg="http://www.w3.org/2000/svg"> diff --git a/assets/icons/src/codes.merritt.Nyrna.Source.svg b/assets/icons/src/codes.merritt.Nyrna.Source.svg new file mode 100644 index 00000000..923964f8 --- /dev/null +++ b/assets/icons/src/codes.merritt.Nyrna.Source.svg @@ -0,0 +1,159 @@ + + + + From 51898f1cf4d9ddb80cb70cec60fbbf420a4b269b Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:52:36 -0400 Subject: [PATCH 05/20] ci: remove Flutter version limitation Bug resolved with new version of Flutter. --- .github/workflows/build-linux.yml | 6 +----- .github/workflows/build-windows.yml | 6 +----- .github/workflows/tests.yml | 6 +----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 251079b6..7c937e8f 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -37,11 +37,7 @@ jobs: run: echo "prerelease=true" >> $GITHUB_ENV - name: Setup Flutter - uses: subosito/flutter-action@v2.10.0 - # Specify the Flutter version to work around bug in new version: - # https://github.com/flutter/flutter/issues/144873 - with: - flutter-version: '3.19.6' + uses: subosito/flutter-action@v2 - name: Checkout code uses: actions/checkout@v3 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 7334eec6..4e8735f5 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -30,11 +30,7 @@ jobs: run: echo "prerelease=true" >> $GITHUB_ENV - name: Setup Flutter - uses: subosito/flutter-action@v2.10.0 - # Specify the Flutter version to work around bug in new version: - # https://github.com/flutter/flutter/issues/144873 - with: - flutter-version: '3.19.6' + uses: subosito/flutter-action@v2 - name: Checkout code uses: actions/checkout@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 23bf27ea..670349dc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,11 +15,7 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v3 - - uses: subosito/flutter-action@v2.10.0 - # Specify the Flutter version to work around bug in new version: - # https://github.com/flutter/flutter/issues/144873 - with: - flutter-version: '3.19.6' + - uses: subosito/flutter-action@v2 - name: Get Linux dependencies if: runner.os == 'Linux' From e0912874b1b79192b057c41a93070e03f75a7d04 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:08:06 -0400 Subject: [PATCH 06/20] feat: make favorite icon a heart A yellow star has poor contrast on Light theme, and the heart for favorite is common in other apps. --- lib/apps_list/widgets/window_tile.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/apps_list/widgets/window_tile.dart b/lib/apps_list/widgets/window_tile.dart index 3e31aeb1..2877a408 100644 --- a/lib/apps_list/widgets/window_tile.dart +++ b/lib/apps_list/widgets/window_tile.dart @@ -124,8 +124,8 @@ class _FavoriteButton extends StatelessWidget { return IconButton( icon: Icon( - (isFavorite) ? Icons.star : Icons.star_border, - color: (isFavorite) ? Colors.yellow : null, + (isFavorite) ? Icons.favorite : Icons.favorite_border, + color: (isFavorite) ? Colors.red : null, ), onPressed: () => appsListCubit.setFavorite(window, !isFavorite), tooltip: (isFavorite) From 02fe3cb50cb07263bf696cbf98121b2e4baf599a Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:23:27 -0400 Subject: [PATCH 07/20] feat: add new screenshots for linux --- assets/screenshots/linux/screenshot1-dark.png | Bin 0 -> 38182 bytes assets/screenshots/linux/screenshot1-light.png | Bin 0 -> 40248 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/screenshots/linux/screenshot1-dark.png create mode 100644 assets/screenshots/linux/screenshot1-light.png diff --git a/assets/screenshots/linux/screenshot1-dark.png b/assets/screenshots/linux/screenshot1-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..71586c9d448bd114fc0368cf8589b5f57ff5bd10 GIT binary patch literal 38182 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 literal 0 HcmV?d00001 From d4a771b9aed3f19f1accf42e0bc2015d9ab08b42 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:36:25 -0400 Subject: [PATCH 08/20] docs: improve wayland warning message --- lib/app/cubit/app_cubit.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/app/cubit/app_cubit.dart b/lib/app/cubit/app_cubit.dart index 310feccb..4d23b686 100644 --- a/lib/app/cubit/app_cubit.dart +++ b/lib/app/cubit/app_cubit.dart @@ -98,6 +98,12 @@ If you need Nyrna to work with a specific app, you can try running it with XWayl env XDG_SESSION_TYPE=x11 ``` +or + +``` +env QT_QPA_PLATFORM=xcb +``` + Otherwise, [consider signing in using X11 instead](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/).'''; switch (sessionType) { From a0c458c2bc4e87c81c4341baf27c49c6540bc6d5 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:36:46 -0400 Subject: [PATCH 09/20] chore: upgrade dependency minor versions --- pubspec.lock | 269 ++++++++++++++++++++++++++------------------------- 1 file changed, 137 insertions(+), 132 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 42647f0e..5902671d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,34 +5,39 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.7.0" archive: dependency: transitive description: name: archive - sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "3.4.10" + version: "3.6.1" args: dependency: "direct main" description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: transitive description: @@ -45,10 +50,10 @@ packages: dependency: transitive description: name: bloc - sha256: f53a110e3b48dcd78136c10daa5d51512443cea5e1348c9d80a320095fa2db9e + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.1.4" boolean_selector: dependency: transitive description: @@ -77,10 +82,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" build_resolvers: dependency: transitive description: @@ -93,18 +98,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04 url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.12" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.3.2" built_collection: dependency: transitive description: @@ -117,10 +122,10 @@ packages: dependency: transitive description: name: built_value - sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.1" + version: "8.9.2" characters: dependency: transitive description: @@ -189,26 +194,26 @@ packages: dependency: transitive description: name: coverage - sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + sha256: c1fb2dce3c0085f39dc72668e85f8e0210ec7de05345821ff58530567df345a5 url: "https://pub.dev" source: hosted - version: "1.7.2" + version: "1.9.2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" dart_style: dependency: transitive description: name: dart_style - sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.6" dbus: dependency: transitive description: @@ -229,10 +234,10 @@ packages: dependency: "direct main" description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" file: dependency: transitive description: @@ -267,10 +272,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1" + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a url: "https://pub.dev" source: hosted - version: "8.1.4" + version: "8.1.6" flutter_driver: dependency: transitive description: flutter @@ -328,10 +333,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" flutter_localizations: dependency: "direct main" description: flutter @@ -367,26 +372,26 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "57247f692f35f068cae297549a46a9a097100685c6780fe67177503eea5ed4e5" + sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" url: "https://pub.dev" source: hosted - version: "2.4.7" + version: "2.5.7" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.4" frontend_server_client: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -396,10 +401,10 @@ packages: dependency: transitive description: name: get_it - sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 url: "https://pub.dev" source: hosted - version: "7.6.7" + version: "7.7.0" glob: dependency: transitive description: @@ -412,10 +417,10 @@ packages: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" helpers: dependency: "direct main" description: @@ -478,10 +483,10 @@ packages: dependency: transitive description: name: image - sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" url: "https://pub.dev" source: hosted - version: "4.1.7" + version: "4.2.0" integration_test: dependency: "direct dev" description: flutter @@ -491,10 +496,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -507,26 +512,26 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.1" json_annotation: dependency: "direct main" description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" json_serializable: dependency: "direct dev" description: name: json_serializable - sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b url: "https://pub.dev" source: hosted - version: "6.7.1" + version: "6.8.0" launch_at_startup: dependency: "direct main" description: @@ -539,26 +544,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" lints: dependency: transitive description: @@ -571,10 +576,10 @@ packages: dependency: "direct main" description: name: logger - sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac" + sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" url: "https://pub.dev" source: hosted - version: "2.0.2+1" + version: "2.4.0" logging: dependency: transitive description: @@ -583,14 +588,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" markdown: dependency: transitive description: name: markdown - sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90" + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 url: "https://pub.dev" source: hosted - version: "7.2.1" + version: "7.2.2" matcher: dependency: transitive description: @@ -603,10 +616,10 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" menu_base: dependency: transitive description: @@ -619,18 +632,18 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" mockito: dependency: "direct dev" description: @@ -643,10 +656,10 @@ packages: dependency: "direct dev" description: name: msix - sha256: "519b183d15dc9f9c594f247e2d2339d855cf0eaacc30e19b128e14f3ecc62047" + sha256: c50d6bd1aafe0d071a3c1e5a5ccb056404502935cb0a549e3178c4aae16caf33 url: "https://pub.dev" source: hosted - version: "3.16.7" + version: "3.16.8" nested: dependency: transitive description: @@ -699,26 +712,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.10" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -739,10 +752,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -755,10 +768,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -771,18 +784,18 @@ packages: dependency: transitive description: name: pointer_interceptor - sha256: bd18321519718678d5fa98ad3a3359cbc7a31f018554eab80b73d08a7f0c165a + sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523" url: "https://pub.dev" source: hosted - version: "0.10.1" + version: "0.10.1+2" pointer_interceptor_ios: dependency: transitive description: name: pointer_interceptor_ios - sha256: "2e73c39452830adc4695757130676a39412a3b7f3c34e3f752791b5384770877" + sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917 url: "https://pub.dev" source: hosted - version: "0.10.0+2" + version: "0.10.1" pointer_interceptor_platform_interface: dependency: transitive description: @@ -799,14 +812,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.1+2" - pointycastle: - dependency: transitive - description: - name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" - url: "https://pub.dev" - source: hosted - version: "3.7.4" pool: dependency: transitive description: @@ -827,10 +832,10 @@ packages: dependency: transitive description: name: provider - sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.2" pub_semver: dependency: "direct main" description: @@ -843,10 +848,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.3.0" screen_retriever: dependency: transitive description: @@ -883,10 +888,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" shortid: dependency: transitive description: @@ -920,10 +925,10 @@ packages: dependency: transitive description: name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" source_maps: dependency: transitive description: @@ -992,26 +997,26 @@ packages: dependency: "direct dev" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.7" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.4" timing: dependency: transitive description: @@ -1024,10 +1029,10 @@ packages: dependency: "direct main" description: name: tray_manager - sha256: e0ac9a88b2700f366b8629b97e8663b6ef450a2f169560a685dc167bfe9c9c29 + sha256: c9a63fd88bd3546287a7eb8ccc978d707eef82c775397af17dda3a4f4c039e64 url: "https://pub.dev" source: hosted - version: "0.2.2" + version: "0.2.3" typed_data: dependency: transitive description: @@ -1040,42 +1045,42 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.0" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 + sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.10" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.0" url_launcher_platform_interface: dependency: transitive description: @@ -1096,10 +1101,10 @@ packages: dependency: transitive description: name: url_launcher_windows - sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" uuid: dependency: transitive description: @@ -1120,10 +1125,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.5" watcher: dependency: transitive description: @@ -1136,18 +1141,18 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.4.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.3" webdriver: dependency: transitive description: @@ -1168,18 +1173,18 @@ packages: dependency: "direct main" description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.5.4" win32_registry: dependency: transitive description: name: win32_registry - sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a" + sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.4" win32_suspend_process: dependency: "direct main" description: @@ -1192,10 +1197,10 @@ packages: dependency: "direct main" description: name: window_manager - sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 + sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf" url: "https://pub.dev" source: hosted - version: "0.3.8" + version: "0.3.9" window_size: dependency: "direct main" description: @@ -1238,5 +1243,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" From f9b3410d6c36dd9f59bb61b6ac9fef1b51a9895b Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:57:28 -0400 Subject: [PATCH 10/20] chore: update formatting to line length 90 --- .vscode/settings.json | 10 ++++++++-- lib/app/cubit/app_cubit.dart | 3 +-- lib/apps_list/apps_list_page.dart | 2 +- lib/apps_list/widgets/custom_app_bar.dart | 3 +-- lib/core/constants.dart | 3 +-- lib/core/widgets/input_dialog.dart | 4 +--- lib/hotkey/global/hotkey_service.dart | 3 +-- lib/logs/log_file_service.dart | 12 +++++------- lib/native_platform/src/linux/linux.dart | 4 ++-- .../repository/src/win32_process_repository.dart | 3 +-- lib/native_platform/src/win32/ffi/user32.dart | 3 +-- lib/native_platform/src/win32/win32.dart | 4 +++- lib/settings/cubit/settings_cubit.dart | 12 +++++------- lib/settings/widgets/behaviour_section.dart | 3 +-- lib/settings/widgets/integration_section.dart | 11 ++++++----- test/active_window/src/active_window_test.dart | 16 ++++++---------- test/app/cubit/app_cubit_test.dart | 3 +-- test/apps_list/widgets/window_tile_test.dart | 3 +-- test/theme/cubit/theme_cubit_test.dart | 6 ++---- 19 files changed, 48 insertions(+), 60 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3e476dfd..3dba4022 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,11 @@ "git.ignoredRepositories": [ "packaging/linux/flatpak/shared-modules" ], - "git.detectSubmodules": false -} \ No newline at end of file + "git.detectSubmodules": false, + "dart.lineLength": 90, + "[dart]": { + "editor.rulers": [ + 90 + ] + } +} diff --git a/lib/app/cubit/app_cubit.dart b/lib/app/cubit/app_cubit.dart index 4d23b686..360d8029 100644 --- a/lib/app/cubit/app_cubit.dart +++ b/lib/app/cubit/app_cubit.dart @@ -126,8 +126,7 @@ Otherwise, [consider signing in using X11 instead](https://docs.fedoraproject.or runningVersion: versionInfo.currentVersion, updateVersion: versionInfo.latestVersion, updateAvailable: versionInfo.updateAvailable, - showUpdateButton: - (defaultTargetPlatform.isDesktop && versionInfo.updateAvailable), + showUpdateButton: (defaultTargetPlatform.isDesktop && versionInfo.updateAvailable), )); } diff --git a/lib/apps_list/apps_list_page.dart b/lib/apps_list/apps_list_page.dart index 5b333252..53894136 100644 --- a/lib/apps_list/apps_list_page.dart +++ b/lib/apps_list/apps_list_page.dart @@ -180,7 +180,7 @@ class _FloatingActionButton extends StatelessWidget { ? BlocBuilder( builder: (context, state) { return FloatingActionButton( - backgroundColor: (state.appTheme == AppTheme.pitchBlack) + backgroundColor: (state.appTheme == AppTheme.pitchBlack) // ? Colors.black : null, onPressed: () { diff --git a/lib/apps_list/widgets/custom_app_bar.dart b/lib/apps_list/widgets/custom_app_bar.dart index bf6a8254..d832c31e 100644 --- a/lib/apps_list/widgets/custom_app_bar.dart +++ b/lib/apps_list/widgets/custom_app_bar.dart @@ -167,8 +167,7 @@ class _WaylandWarningButton extends StatelessWidget { return IconButton( icon: const Icon(Icons.warning), - onPressed: () => - _showWarningDialog(context, state.linuxSessionMessage!), + onPressed: () => _showWarningDialog(context, state.linuxSessionMessage!), ); }, ); diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 8fa49545..c34a13fd 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -15,5 +15,4 @@ const String websiteUrl = 'https://nyrna.merritt.codes/'; /// /// This is distinct from the package name the Microsoft Store uses, and is /// required for some things like creating shortcuts. -const String kWindowsAppPackageName = - '33694MerrittCodes.Nyrna_9kjrd3yy77d9e!nyrna'; +const String kWindowsAppPackageName = '33694MerrittCodes.Nyrna_9kjrd3yy77d9e!nyrna'; diff --git a/lib/core/widgets/input_dialog.dart b/lib/core/widgets/input_dialog.dart index 1690c3de..87614a78 100644 --- a/lib/core/widgets/input_dialog.dart +++ b/lib/core/widgets/input_dialog.dart @@ -29,9 +29,7 @@ Future showInputDialog({ keyboardType = TextInputType.number; break; case InputDialogs.onlyDouble: - formatter = [ - FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?\.?\d{0,2}')) - ]; + formatter = [FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?\.?\d{0,2}'))]; keyboardType = TextInputType.number; break; case InputDialogs.multiLine: diff --git a/lib/hotkey/global/hotkey_service.dart b/lib/hotkey/global/hotkey_service.dart index ceb77f9e..5ee1689b 100644 --- a/lib/hotkey/global/hotkey_service.dart +++ b/lib/hotkey/global/hotkey_service.dart @@ -12,8 +12,7 @@ class HotkeyService { /// Stream that fires when a hotkey is triggered. /// /// Allows dependent services to react when a hotkey is triggered. - Stream get hotkeyTriggeredStream => - _hotkeyTriggeredStreamController.stream; + Stream get hotkeyTriggeredStream => _hotkeyTriggeredStreamController.stream; /// Controller for the hotkey triggered stream. final _hotkeyTriggeredStreamController = StreamController.broadcast(); diff --git a/lib/logs/log_file_service.dart b/lib/logs/log_file_service.dart index 98dd08cc..5618fc85 100644 --- a/lib/logs/log_file_service.dart +++ b/lib/logs/log_file_service.dart @@ -84,7 +84,7 @@ class LogFileService { final List files = _logDir.listSync(); - final List logFiles = files + final List logFiles = files // .whereType() .where((file) => file.path.endsWith('.txt')) .toList(); @@ -135,8 +135,7 @@ $currentTime Future _deleteOldLogFiles() async { final List logFiles = await getAllLogFiles() // Remove any numbered log files. - ..removeWhere( - (file) => file.path.split(Platform.pathSeparator).last.contains('_')); + ..removeWhere((file) => file.path.split(Platform.pathSeparator).last.contains('_')); if (logFiles.length <= 7) { return; @@ -160,8 +159,8 @@ $currentTime } // Remove any log files that are not numbered. - todayLogFiles.removeWhere((file) => - file.path.split(Platform.pathSeparator).last.contains('_') == false); + todayLogFiles.removeWhere( + (file) => file.path.split(Platform.pathSeparator).last.contains('_') == false); final int highestNumber = todayLogFiles .map((file) => int.parse(file.path.split('_').last.split('.').first)) @@ -195,8 +194,7 @@ $currentTime final int highestNumber = _getHighestNumber(todayLogFiles); final String newFileName = '${_today}_${highestNumber + 1}.txt'; - final File newLogFile = - File('${_logDir.path}${Platform.pathSeparator}$newFileName'); + final File newLogFile = File('${_logDir.path}${Platform.pathSeparator}$newFileName'); await newLogFile.create(); diff --git a/lib/native_platform/src/linux/linux.dart b/lib/native_platform/src/linux/linux.dart index f63744ee..61c24965 100644 --- a/lib/native_platform/src/linux/linux.dart +++ b/lib/native_platform/src/linux/linux.dart @@ -67,8 +67,8 @@ class Linux implements NativePlatform { // Which virtual desktop this window is on. final windowDesktop = int.tryParse(parts[1]); - final windowOnCurrentDesktop = (windowDesktop == _desktop || - windowDesktop == _kStickyWindowIdentifier); + final windowOnCurrentDesktop = + (windowDesktop == _desktop || windowDesktop == _kStickyWindowIdentifier); if (!windowOnCurrentDesktop && !showHidden) return null; final pid = int.tryParse(parts[2]); diff --git a/lib/native_platform/src/process/repository/src/win32_process_repository.dart b/lib/native_platform/src/process/repository/src/win32_process_repository.dart index a887883f..b123d51e 100644 --- a/lib/native_platform/src/process/repository/src/win32_process_repository.dart +++ b/lib/native_platform/src/process/repository/src/win32_process_repository.dart @@ -19,8 +19,7 @@ class Win32ProcessRepository extends ProcessRepository { /// Load the native library. final String nativeLibraryPath; if (kReleaseMode) { - nativeLibraryPath = - r'data\flutter_assets\assets\lib\windows\NativeLibrary.dll'; + nativeLibraryPath = r'data\flutter_assets\assets\lib\windows\NativeLibrary.dll'; } else { nativeLibraryPath = r'assets\lib\windows\NativeLibrary.dll'; } diff --git a/lib/native_platform/src/win32/ffi/user32.dart b/lib/native_platform/src/win32/ffi/user32.dart index 9017e40b..09ad697b 100644 --- a/lib/native_platform/src/win32/ffi/user32.dart +++ b/lib/native_platform/src/win32/ffi/user32.dart @@ -21,7 +21,6 @@ final _user32 = DynamicLibrary.open('user32.dll'); int GetWindowThreadProcessId(int hWnd, Pointer lpdwProcessId) { final _GetWindowThreadProcessId = _user32.lookupFunction< Uint32 Function(Int32 hWnd, Pointer lpdwProcessId), - int Function( - int hWnd, Pointer lwpdProcessId)>('GetWindowThreadProcessId'); + int Function(int hWnd, Pointer lwpdProcessId)>('GetWindowThreadProcessId'); return _GetWindowThreadProcessId(hWnd, lpdwProcessId); } diff --git a/lib/native_platform/src/win32/win32.dart b/lib/native_platform/src/win32/win32.dart index 82ab05c5..a58a2cd0 100644 --- a/lib/native_platform/src/win32/win32.dart +++ b/lib/native_platform/src/win32/win32.dart @@ -188,7 +188,9 @@ class WindowBuilder { /// duration of the current isolate's lifetime." /// https://api.flutter.dev/flutter/dart-ffi/Pointer/fromFunction.html static final _callback = Pointer.fromFunction( - WindowBuilder.enumWindowsCallback, 0); + WindowBuilder.enumWindowsCallback, + 0, + ); /// Callback for each window found by `EnumWindows()`. /// diff --git a/lib/settings/cubit/settings_cubit.dart b/lib/settings/cubit/settings_cubit.dart index c7906550..c283f45d 100644 --- a/lib/settings/cubit/settings_cubit.dart +++ b/lib/settings/cubit/settings_cubit.dart @@ -61,15 +61,12 @@ class SettingsCubit extends Cubit { hotkey = defaultHotkey; } - final bool minimizeWindows = - await storage.getValue('minimizeWindows') ?? true; + final bool minimizeWindows = await storage.getValue('minimizeWindows') ?? true; final bool pinSuspendedWindows = await storage.getValue('pinSuspendedWindows') ?? false; final int refreshInterval = await storage.getValue('refreshInterval') ?? 5; - final bool showHiddenWindows = - await storage.getValue('showHiddenWindows') ?? false; - final bool startHiddenInTray = - await storage.getValue('startHiddenInTray') ?? false; + final bool showHiddenWindows = await storage.getValue('showHiddenWindows') ?? false; + final bool startHiddenInTray = await storage.getValue('startHiddenInTray') ?? false; return SettingsCubit._( autostartService, @@ -165,7 +162,8 @@ class SettingsCubit extends Cubit { final AppSpecificHotkey appSpecificHotkey = state.appSpecificHotKeys.firstWhere((e) => e.executable == executable); - final List appSpecificHotkeys = state.appSpecificHotKeys + final List appSpecificHotkeys = state // + .appSpecificHotKeys .where((e) => e.executable != executable) .toList(); diff --git a/lib/settings/widgets/behaviour_section.dart b/lib/settings/widgets/behaviour_section.dart index 044146c3..9b0fc9dc 100644 --- a/lib/settings/widgets/behaviour_section.dart +++ b/lib/settings/widgets/behaviour_section.dart @@ -111,8 +111,7 @@ class _PinSuspendedWindowsTile extends StatelessWidget { ), WidgetSpan( child: Tooltip( - message: - AppLocalizations.of(context)!.pinSuspendedWindowsTooltip, + message: AppLocalizations.of(context)!.pinSuspendedWindowsTooltip, child: const Icon( Icons.help_outline, size: 18, diff --git a/lib/settings/widgets/integration_section.dart b/lib/settings/widgets/integration_section.dart index 928cfcbd..8c3fc14e 100644 --- a/lib/settings/widgets/integration_section.dart +++ b/lib/settings/widgets/integration_section.dart @@ -262,8 +262,9 @@ class _AppSpecificHotkeys extends StatelessWidget { backgroundColor: Colors.grey.shade700, padding: const EdgeInsets.all(10), ), - onPressed: () => settingsCubit - .removeAppSpecificHotkey(hotkey.executable), + onPressed: () => settingsCubit.removeAppSpecificHotkey( + hotkey.executable, + ), child: const Icon(Icons.delete), ), ), @@ -299,7 +300,8 @@ class _AddAppSpecificHotkeyDialog extends StatelessWidget { return AlertDialog( content: BlocBuilder( builder: (context, state) { - final executables = state.windows + final executables = state // + .windows .map((window) => window.process.executable) .toSet() .toList(); @@ -354,8 +356,7 @@ class _RecordAppSpecificHotkeyDialog extends StatefulWidget { _RecordAppSpecificHotkeyDialogState(); } -class _RecordAppSpecificHotkeyDialogState - extends State<_RecordAppSpecificHotkeyDialog> { +class _RecordAppSpecificHotkeyDialogState extends State<_RecordAppSpecificHotkeyDialog> { HotKey? _hotKey; @override diff --git a/test/active_window/src/active_window_test.dart b/test/active_window/src/active_window_test.dart index b95ce1ee..aa4e753f 100644 --- a/test/active_window/src/active_window_test.dart +++ b/test/active_window/src/active_window_test.dart @@ -101,10 +101,9 @@ void main() { test('explorer.exe executable aborts on Win32', () async { debugDefaultTargetPlatformOverride = TargetPlatform.windows; - when(nativePlatform.activeWindow()) - .thenAnswer((_) async => testWindow.copyWith( - process: testProcess.copyWith(executable: 'explorer.exe'), - )); + when(nativePlatform.activeWindow()).thenAnswer((_) async => testWindow.copyWith( + process: testProcess.copyWith(executable: 'explorer.exe'), + )); final successful = await activeWindow.toggle(); expect(successful, false); verifyNever(processRepository.suspend(any)); @@ -135,18 +134,15 @@ void main() { verifyNever(nativePlatform.minimizeWindow(any)); }); - test('no-minimize flag received & no preference does not minimize', - () async { + test('no-minimize flag received & no preference does not minimize', () async { when(argParser.minimize).thenReturn(false); final successful = await activeWindow.toggle(); expect(successful, true); verifyNever(nativePlatform.minimizeWindow(any)); }); - test('no-minimize flag received & preference=true does not minimize', - () async { - when(storageRepository.getValue('minimizeWindows')) - .thenAnswer((_) async => true); + test('no-minimize flag received & preference=true does not minimize', () async { + when(storageRepository.getValue('minimizeWindows')).thenAnswer((_) async => true); when(argParser.minimize).thenReturn(false); final successful = await activeWindow.toggle(); expect(successful, true); diff --git a/test/app/cubit/app_cubit_test.dart b/test/app/cubit/app_cubit_test.dart index 57884fcf..679282cc 100644 --- a/test/app/cubit/app_cubit_test.dart +++ b/test/app/cubit/app_cubit_test.dart @@ -43,8 +43,7 @@ void main() { reset(mockSystemTrayManager); reset(mockUpdateService); - when(mockUpdateService.getVersionInfo()) - .thenAnswer((_) async => VersionInfo.empty()); + when(mockUpdateService.getVersionInfo()).thenAnswer((_) async => VersionInfo.empty()); cubit = AppCubit( mockAppWindow, diff --git a/test/apps_list/widgets/window_tile_test.dart b/test/apps_list/widgets/window_tile_test.dart index 6d06313f..1b4589b7 100644 --- a/test/apps_list/widgets/window_tile_test.dart +++ b/test/apps_list/widgets/window_tile_test.dart @@ -54,8 +54,7 @@ void main() { when(mockSettingsCubit.state).thenReturn(SettingsState.initial()); }); - testWidgets('Clicking more actions button shows context menu', - (tester) async { + testWidgets('Clicking more actions button shows context menu', (tester) async { final appsListCubit = AppsListCubit( appVersion: mockAppVersion, hotkeyService: mockHotkeyService, diff --git a/test/theme/cubit/theme_cubit_test.dart b/test/theme/cubit/theme_cubit_test.dart index 5b4a5930..eaa2fff0 100644 --- a/test/theme/cubit/theme_cubit_test.dart +++ b/test/theme/cubit/theme_cubit_test.dart @@ -45,14 +45,12 @@ void main() { }); test('saved dark theme preference loads dark theme', () async { - when(mockStorageRepo.getValue('appTheme')) - .thenAnswer((_) async => 'AppTheme.dark'); + when(mockStorageRepo.getValue('appTheme')).thenAnswer((_) async => 'AppTheme.dark'); cubit = await ThemeCubit.init(mockStorageRepo); expect(state.appTheme, AppTheme.dark); }); - test('saved pitch black theme preference loads pitch black theme', - () async { + test('saved pitch black theme preference loads pitch black theme', () async { when(mockStorageRepo.getValue('appTheme')) .thenAnswer((_) async => 'AppTheme.pitchBlack'); cubit = await ThemeCubit.init(mockStorageRepo); From 39ce63845e9fd5ed05532908e86fce62e72b5fc3 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:17:06 -0400 Subject: [PATCH 11/20] chore: apply depreciations for new Flutter version --- lib/apps_list/widgets/custom_app_bar.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/apps_list/widgets/custom_app_bar.dart b/lib/apps_list/widgets/custom_app_bar.dart index d832c31e..6777e354 100644 --- a/lib/apps_list/widgets/custom_app_bar.dart +++ b/lib/apps_list/widgets/custom_app_bar.dart @@ -130,7 +130,7 @@ class _SearchBar extends StatelessWidget { controller: controller, focusNode: focusNode, hintText: AppLocalizations.of(context)!.filterWindows, - elevation: MaterialStateProperty.all(2), + elevation: WidgetStateProperty.all(2), trailing: [ clearButton, ], From 9c203ef5cdeeb72d608f438a97c1ea7aed519fd3 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:17:24 -0400 Subject: [PATCH 12/20] chore: apply depreciations for new win32 version --- .../repository/src/win32_process_repository.dart | 16 +++++++++++++--- lib/native_platform/src/win32/win32.dart | 8 ++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/native_platform/src/process/repository/src/win32_process_repository.dart b/lib/native_platform/src/process/repository/src/win32_process_repository.dart index b123d51e..82b93453 100644 --- a/lib/native_platform/src/process/repository/src/win32_process_repository.dart +++ b/lib/native_platform/src/process/repository/src/win32_process_repository.dart @@ -50,7 +50,7 @@ class Win32ProcessRepository extends ProcessRepository { Future _getExecutableName(int pid) async { final processHandle = OpenProcess( - PROCESS_QUERY_LIMITED_INFORMATION, + PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid, ); @@ -91,7 +91,12 @@ class Win32ProcessRepository extends ProcessRepository { @override Future resume(int pid) async { - final processHandle = OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, pid); + final processHandle = OpenProcess( + PROCESS_ACCESS_RIGHTS.PROCESS_SUSPEND_RESUME, + FALSE, + pid, + ); + final result = NtResumeProcess(processHandle); final successful = (result == 0); log.i('Resuming $pid was successful: $successful'); @@ -101,7 +106,12 @@ class Win32ProcessRepository extends ProcessRepository { @override Future suspend(int pid) async { - final processHandle = OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, pid); + final processHandle = OpenProcess( + PROCESS_ACCESS_RIGHTS.PROCESS_SUSPEND_RESUME, + FALSE, + pid, + ); + final result = NtSuspendProcess(processHandle); final successful = (result == 0); log.i('Suspending $pid was successful: $successful'); diff --git a/lib/native_platform/src/win32/win32.dart b/lib/native_platform/src/win32/win32.dart index a58a2cd0..0f2f51e8 100644 --- a/lib/native_platform/src/win32/win32.dart +++ b/lib/native_platform/src/win32/win32.dart @@ -102,20 +102,20 @@ class Win32 implements NativePlatform { @override Future minimizeWindow(int windowId) async { log.i('Minimizing window with id $windowId'); - ShowWindow(windowId, SW_FORCEMINIMIZE); + ShowWindow(windowId, SHOW_WINDOW_CMD.SW_FORCEMINIMIZE); return true; // [ShowWindow] return value doesn't confirm success. } @override Future restoreWindow(int windowId) async { log.i('Restoring window with id $windowId'); - ShowWindow(windowId, SW_RESTORE); + ShowWindow(windowId, SHOW_WINDOW_CMD.SW_RESTORE); return true; // [ShowWindow] return value doesn't confirm success. } Future getExecutableName(int pid) async { final processHandle = OpenProcess( - PROCESS_QUERY_LIMITED_INFORMATION, + PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid, ); @@ -187,7 +187,7 @@ class WindowBuilder { /// "The pointer returned will remain alive for the /// duration of the current isolate's lifetime." /// https://api.flutter.dev/flutter/dart-ffi/Pointer/fromFunction.html - static final _callback = Pointer.fromFunction( + static final _callback = Pointer.fromFunction( WindowBuilder.enumWindowsCallback, 0, ); From d0f19fd5ec5bc47744cb7a7a1c2e3e1889b6776f Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:39:15 -0400 Subject: [PATCH 13/20] ci: skip problematic test on Wayland --- test/native_platform/src/native_platform_test.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/native_platform/src/native_platform_test.dart b/test/native_platform/src/native_platform_test.dart index 3f429788..f8f6fe80 100644 --- a/test/native_platform/src/native_platform_test.dart +++ b/test/native_platform/src/native_platform_test.dart @@ -1,3 +1,5 @@ +import 'dart:io' as io; + import 'package:nyrna/native_platform/native_platform.dart'; import 'package:test/test.dart'; @@ -15,6 +17,13 @@ void main() { }); test('activeWindow returns a window', () async { + // If system is Wayland, skip this test since it will fail. + // Might be able to revisit once Wayland support is added. + final sessionType = io.Platform.environment['XDG_SESSION_TYPE']; + if (sessionType == 'wayland') { + return; + } + final activeWindow = await platform.activeWindow(); expect(activeWindow.id, isPositive); expect(activeWindow.process.pid, isPositive); From 5950eb250af44d7dd5fa324ac65b0ee840d6283d Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:55:18 -0400 Subject: [PATCH 14/20] fix: unreadable buttons in settings Why are we setting a custom style here at all? Regardless, the hard-coded color makes it unreadable in light mode. --- lib/settings/widgets/integration_section.dart | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/settings/widgets/integration_section.dart b/lib/settings/widgets/integration_section.dart index 8c3fc14e..039a2e86 100644 --- a/lib/settings/widgets/integration_section.dart +++ b/lib/settings/widgets/integration_section.dart @@ -125,7 +125,6 @@ class _HotkeyConfigWidget extends StatelessWidget { title: const Text('Hotkey'), leading: const Icon(Icons.keyboard), trailing: ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.grey.shade700), onPressed: () => showDialog( context: context, builder: (context) => _RecordHotKeyDialog( @@ -258,10 +257,6 @@ class _AppSpecificHotkeys extends StatelessWidget { leading: Text(hotkey.hotkey.toStringHelper()), title: Text(hotkey.executable), trailing: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.grey.shade700, - padding: const EdgeInsets.all(10), - ), onPressed: () => settingsCubit.removeAppSpecificHotkey( hotkey.executable, ), @@ -271,10 +266,6 @@ class _AppSpecificHotkeys extends StatelessWidget { ), ), ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.grey.shade700, - padding: const EdgeInsets.all(10), - ), onPressed: () { showDialog( context: context, From 8c3eb5b99109eb31e2c066ab4f964013c5f6611e Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:16:24 -0400 Subject: [PATCH 15/20] fix: hotkey getting Nyrna for active window --- lib/active_window/src/active_window.dart | 89 +++++++++++-------- lib/apps_list/cubit/apps_list_cubit.dart | 7 +- lib/main.dart | 8 +- .../active_window/src/active_window_test.dart | 38 ++++++++ .../apps_list/cubit/apps_list_cubit_test.dart | 4 + test/apps_list/widgets/window_tile_test.dart | 4 + test/helpers.dart | 12 +++ 7 files changed, 120 insertions(+), 42 deletions(-) create mode 100644 test/helpers.dart diff --git a/lib/active_window/src/active_window.dart b/lib/active_window/src/active_window.dart index 2a2a9079..22abdf3c 100644 --- a/lib/active_window/src/active_window.dart +++ b/lib/active_window/src/active_window.dart @@ -4,22 +4,28 @@ import '../../argument_parser/argument_parser.dart'; import '../../logs/logs.dart'; import '../../native_platform/native_platform.dart'; import '../../storage/storage_repository.dart'; +import '../../window/app_window.dart'; /// Manage the active window. /// /// We use extra logging here in order to debug issues since this has /// no user interface. class ActiveWindow { + final AppWindow _appWindow; final NativePlatform _nativePlatform; final ProcessRepository _processRepository; final StorageRepository _storageRepository; const ActiveWindow( + this._appWindow, this._nativePlatform, this._processRepository, this._storageRepository, ); + /// Maximum number of retries to suspend the active window. + static const int _maxRetries = 3; + /// Toggle suspend / resume for the active, foreground window. Future toggle() async { log.i('Toggling active window.'); @@ -79,53 +85,60 @@ class ActiveWindow { Future _suspend() async { log.i('Suspending'); - final window = await _nativePlatform.activeWindow(); + for (int attempt = 0; attempt < _maxRetries; attempt++) { + final window = await _nativePlatform.activeWindow(); + final String executable = window.process.executable; - final String executable = window.process.executable; - if (executable == 'nyrna' || executable == 'nyrna.exe') { - log.w('Active window is Nyrna, not suspending.'); - return false; - } + if (executable == 'nyrna' || executable == 'nyrna.exe') { + log.w('Active window is Nyrna, hiding and retrying.'); + await _appWindow.hide(); + await Future.delayed(const Duration(milliseconds: 500)); + continue; + } - log.i('Active window: $window'); + log.i('Active window: $window'); - if (defaultTargetPlatform == TargetPlatform.windows) { - // Once in a blue moon on Windows we get "explorer.exe" as the active - // window, even when no file explorer windows are open / the desktop - // is not the active element, etc. So we filter it just in case. - if (window.process.executable == 'explorer.exe') { - log.e('Only got explorer as active window!'); - return false; + if (defaultTargetPlatform == TargetPlatform.windows) { + // Once in a blue moon on Windows we get "explorer.exe" as the active + // window, even when no file explorer windows are open / the desktop + // is not the active element, etc. So we filter it just in case. + if (window.process.executable == 'explorer.exe') { + log.e('Only got explorer as active window!'); + return false; + } } - } - await _minimize(window.id); + await _minimize(window.id); - // Small delay on Windows to ensure the window actually minimizes. - // Doesn't seem to be necessary on Linux. - if (defaultTargetPlatform == TargetPlatform.windows) { - await Future.delayed(const Duration(milliseconds: 500)); - } + // Small delay on Windows to ensure the window actually minimizes. + // Doesn't seem to be necessary on Linux. + if (defaultTargetPlatform == TargetPlatform.windows) { + await Future.delayed(const Duration(milliseconds: 500)); + } - final suspended = await _processRepository.suspend(window.process.pid); - if (!suspended) { - log.e('Failed to suspend active window.'); - return false; - } + final suspended = await _processRepository.suspend(window.process.pid); + if (!suspended) { + log.e('Failed to suspend active window.'); + return false; + } - await _storageRepository.saveValue( - key: 'pid', - value: window.process.pid, - storageArea: 'activeWindow', - ); - await _storageRepository.saveValue( - key: 'windowId', - value: window.id, - storageArea: 'activeWindow', - ); - log.i('Suspended ${window.process.pid} successfully'); + await _storageRepository.saveValue( + key: 'pid', + value: window.process.pid, + storageArea: 'activeWindow', + ); + await _storageRepository.saveValue( + key: 'windowId', + value: window.id, + storageArea: 'activeWindow', + ); + log.i('Suspended ${window.process.pid} successfully'); + + return true; + } - return true; + log.e('Failed to suspend after $_maxRetries attempts.'); + return false; } Future _minimize(int windowId) async { diff --git a/lib/apps_list/cubit/apps_list_cubit.dart b/lib/apps_list/cubit/apps_list_cubit.dart index 9af1ee9c..f4c83e69 100644 --- a/lib/apps_list/cubit/apps_list_cubit.dart +++ b/lib/apps_list/cubit/apps_list_cubit.dart @@ -13,12 +13,14 @@ import '../../logs/logs.dart'; import '../../native_platform/native_platform.dart'; import '../../storage/storage_repository.dart'; import '../../system_tray/system_tray.dart'; +import '../../window/app_window.dart'; import '../apps_list.dart'; part 'apps_list_state.dart'; part 'apps_list_cubit.freezed.dart'; class AppsListCubit extends Cubit { + final AppWindow _appWindow; final HotkeyService _hotkeyService; final NativePlatform _nativePlatform; final ProcessRepository _processRepository; @@ -28,6 +30,7 @@ class AppsListCubit extends Cubit { final AppVersion _appVersion; AppsListCubit({ + required AppWindow appWindow, required HotkeyService hotkeyService, required NativePlatform nativePlatform, required ProcessRepository processRepository, @@ -36,7 +39,8 @@ class AppsListCubit extends Cubit { required SystemTrayManager systemTrayManager, required AppVersion appVersion, bool testing = false, - }) : _hotkeyService = hotkeyService, + }) : _appWindow = appWindow, + _hotkeyService = hotkeyService, _nativePlatform = nativePlatform, _settingsCubit = settingsCubit, _processRepository = processRepository, @@ -216,6 +220,7 @@ class AppsListCubit extends Cubit { Future toggleActiveWindow() async { final activeWindow = ActiveWindow( + _appWindow, _nativePlatform, _processRepository, _storage, diff --git a/lib/main.dart b/lib/main.dart index 5e73e03d..3988a2d4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -54,7 +54,11 @@ Future main(List args) async { final processRepository = ProcessRepository.init(); + final appWindow = AppWindow(storage); + appWindow.initialize(); + final activeWindow = ActiveWindow( + appWindow, nativePlatform, processRepository, storage, @@ -81,9 +85,6 @@ Future main(List args) async { final hotkeyService = HotkeyService(); - final appWindow = AppWindow(storage); - appWindow.initialize(); - final settingsCubit = await SettingsCubit.init( autostartService: AutostartService(), hotkeyService: hotkeyService, @@ -108,6 +109,7 @@ Future main(List args) async { ); final appsListCubit = AppsListCubit( + appWindow: appWindow, hotkeyService: hotkeyService, nativePlatform: nativePlatform, settingsCubit: settingsCubit, diff --git a/test/active_window/src/active_window_test.dart b/test/active_window/src/active_window_test.dart index aa4e753f..4047ef4b 100644 --- a/test/active_window/src/active_window_test.dart +++ b/test/active_window/src/active_window_test.dart @@ -6,9 +6,12 @@ import 'package:nyrna/argument_parser/argument_parser.dart'; import 'package:nyrna/logs/logs.dart'; import 'package:nyrna/native_platform/native_platform.dart'; import 'package:nyrna/storage/storage_repository.dart'; +import 'package:nyrna/window/app_window.dart'; import 'package:test/test.dart'; +import '../../helpers.dart'; @GenerateNiceMocks([ + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -30,6 +33,7 @@ const testWindow = Window( title: 'Untitled-2 - Visual Studio Code - Insiders', ); +MockAppWindow appWindow = MockAppWindow(); MockArgumentParser argParser = MockArgumentParser(); MockNativePlatform nativePlatform = MockNativePlatform(); MockProcessRepository processRepository = MockProcessRepository(); @@ -51,6 +55,9 @@ void main() { // Setup initial dummy responses for mocks. + // AppWindow + when(appWindow.hide()).thenAnswer((_) async => true); + // NativePlatform when(nativePlatform.activeWindow()).thenAnswer((_) async => testWindow); when(nativePlatform.minimizeWindow(any)).thenAnswer((_) async => true); @@ -76,6 +83,7 @@ void main() { when(storageRepository.close()).thenAnswer((_) async {}); activeWindow = ActiveWindow( + appWindow, nativePlatform, processRepository, storageRepository, @@ -117,6 +125,36 @@ void main() { expect(successful, false); }); + test('active window being Nyrna calls hide on window and tries again (Linux)', + () async { + final nyrnaWindow = testWindow.copyWith( + process: testProcess.copyWith(executable: 'nyrna'), + ); + when(nativePlatform.activeWindow()).thenAnswerInOrder([ + Future.value(nyrnaWindow), + Future.value(testWindow), + ]); + final successful = await activeWindow.toggle(); + expect(successful, true); + verify(nativePlatform.activeWindow()).called(2); + verify(appWindow.hide()).called(1); + }); + + test('active window being Nyrna calls hide on window and tries again (Windows)', + () async { + final nyrnaWindow = testWindow.copyWith( + process: testProcess.copyWith(executable: 'nyrna.exe'), + ); + when(nativePlatform.activeWindow()).thenAnswerInOrder([ + Future.value(nyrnaWindow), + Future.value(testWindow), + ]); + final successful = await activeWindow.toggle(); + expect(successful, true); + verify(nativePlatform.activeWindow()).called(2); + verify(appWindow.hide()).called(1); + }); + group('minimizing & restoring:', () { test('no flag or preference defaults to minimizing', () async { expect(argParser.minimize, null); diff --git a/test/apps_list/cubit/apps_list_cubit_test.dart b/test/apps_list/cubit/apps_list_cubit_test.dart index 0901c680..d31dd90d 100644 --- a/test/apps_list/cubit/apps_list_cubit_test.dart +++ b/test/apps_list/cubit/apps_list_cubit_test.dart @@ -10,9 +10,11 @@ import 'package:nyrna/native_platform/native_platform.dart'; import 'package:nyrna/settings/settings.dart'; import 'package:nyrna/storage/storage_repository.dart'; import 'package:nyrna/system_tray/system_tray_manager.dart'; +import 'package:nyrna/window/app_window.dart'; import 'package:test/test.dart'; @GenerateNiceMocks([ + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -70,6 +72,7 @@ Window get mpvWindow2State => state // .windows .singleWhere((element) => element.id == mpvWindow2.id); +final appWindow = MockAppWindow(); final hotkeyService = MockHotkeyService(); final nativePlatform = MockNativePlatform(); final settingsCubit = MockSettingsCubit(); @@ -128,6 +131,7 @@ void main() { when(storage.getValue('minimizeWindows')).thenAnswer((_) async => true); cubit = AppsListCubit( + appWindow: appWindow, hotkeyService: hotkeyService, nativePlatform: nativePlatform, settingsCubit: settingsCubit, diff --git a/test/apps_list/widgets/window_tile_test.dart b/test/apps_list/widgets/window_tile_test.dart index 1b4589b7..cf1a193a 100644 --- a/test/apps_list/widgets/window_tile_test.dart +++ b/test/apps_list/widgets/window_tile_test.dart @@ -11,9 +11,11 @@ import 'package:nyrna/native_platform/native_platform.dart'; import 'package:nyrna/settings/settings.dart'; import 'package:nyrna/storage/storage_repository.dart'; import 'package:nyrna/system_tray/system_tray_manager.dart'; +import 'package:nyrna/window/app_window.dart'; @GenerateNiceMocks([ MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -24,6 +26,7 @@ import 'package:nyrna/system_tray/system_tray_manager.dart'; import 'window_tile_test.mocks.dart'; final mockAppVersion = MockAppVersion(); +final mockAppWindow = MockAppWindow(); final mockHotkeyService = MockHotkeyService(); final mockNativePlatform = MockNativePlatform(); final mockProcessRepository = MockProcessRepository(); @@ -57,6 +60,7 @@ void main() { testWidgets('Clicking more actions button shows context menu', (tester) async { final appsListCubit = AppsListCubit( appVersion: mockAppVersion, + appWindow: mockAppWindow, hotkeyService: mockHotkeyService, nativePlatform: mockNativePlatform, processRepository: mockProcessRepository, diff --git a/test/helpers.dart b/test/helpers.dart new file mode 100644 index 00000000..fc3815f1 --- /dev/null +++ b/test/helpers.dart @@ -0,0 +1,12 @@ +import 'package:mockito/mockito.dart'; + +/// Extension to allow `thenAnswerInOrder` (different values for multiple async calls). +/// +/// From: https://github.com/dart-lang/mockito/issues/221#issuecomment-2034267995 +/// Open issue: https://github.com/dart-lang/mockito/issues/704 +extension When on PostExpectation { + void thenAnswerInOrder(List values) { + int callCount = 0; + thenAnswer((_) => values[callCount++]); + } +} From 2cc45982a82d7a123599f9331960175296f61142 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:22:44 -0400 Subject: [PATCH 16/20] chore(linux): update metadata Updated the metadata to follow the guilelines laid out by Flathub: https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/ --- packaging/linux/codes.merritt.Nyrna.desktop | 2 +- .../linux/codes.merritt.Nyrna.metainfo.xml | 31 ++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packaging/linux/codes.merritt.Nyrna.desktop b/packaging/linux/codes.merritt.Nyrna.desktop index 3ec0abd4..bd49473a 100644 --- a/packaging/linux/codes.merritt.Nyrna.desktop +++ b/packaging/linux/codes.merritt.Nyrna.desktop @@ -6,6 +6,6 @@ Exec=nyrna Icon=codes.merritt.Nyrna Terminal=false StartupNotify=false -Categories=Utility; +Categories=Utility;Game; Keywords=sleep;suspend;pause;games;resources; StartupWMClass=Nyrna diff --git a/packaging/linux/codes.merritt.Nyrna.metainfo.xml b/packaging/linux/codes.merritt.Nyrna.metainfo.xml index 03d3c857..8de77799 100644 --- a/packaging/linux/codes.merritt.Nyrna.metainfo.xml +++ b/packaging/linux/codes.merritt.Nyrna.metainfo.xml @@ -7,13 +7,15 @@ https://www.freedesktop.org/software/appstream/metainfocreator/#/ codes.merritt.Nyrna Nyrna Suspend games and applications - Merritt Codes - https://github.com/Merrit/nyrna/issues/ - https://merritt.codes/contact/ - https://nyrna.merritt.codes/ - https://merritt.codes/support/ + + Merritt Codes + + https://github.com/Merrit/nyrna/issues + https://merritt.codes/contact + https://nyrna.merritt.codes + https://merritt.codes/support - https://github.com/Merrit/nyrna/ + https://github.com/Merrit/nyrna MIT GPL-3.0-or-later @@ -21,13 +23,6 @@ https://www.freedesktop.org/software/appstream/metainfocreator/#/ keyboard touch - - sleep - suspend - pause - games - resources -

Similar to the incredibly useful sleep/suspend function found in consoles like the Nintendo Switch and Sony PlayStation; suspend your game (and its resource usage) at any time, and resume whenever you wish - at the push of a button.

Suspend Games

@@ -49,12 +44,18 @@ https://www.freedesktop.org/software/appstream/metainfocreator/#/ codes.merritt.Nyrna.desktop - https://github.com/Merrit/nyrna/raw/main/assets/images/promo/promo.jpg + https://raw.githubusercontent.com/Merrit/nyrna/02fe3cb50cb07263bf696cbf98121b2e4baf599a/assets/screenshots/linux/screenshot1-dark.png + Example usage shows multiple open applications, one suspended and favorited - dark theme - https://nyrna.merritt.codes/assets/images/nyrna-window.png + https://raw.githubusercontent.com/Merrit/nyrna/02fe3cb50cb07263bf696cbf98121b2e4baf599a/assets/screenshots/linux/screenshot1-light.png + Example usage shows multiple open applications, one suspended and favorited - light theme + + #00618b + #005173 + From 343a473c31f045bd926c8bcd0ad39296a2517926 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:07:35 -0400 Subject: [PATCH 17/20] feat: show errors in banner to make them more visible --- lib/apps_list/apps_list_page.dart | 63 +++++++- lib/apps_list/cubit/apps_list_cubit.dart | 7 + lib/apps_list/widgets/custom_app_bar.dart | 5 +- .../widgets/nyrna_error_message.dart | 81 ++++++++++ lib/apps_list/widgets/widgets.dart | 1 + lib/apps_list/widgets/window_tile.dart | 144 ++++-------------- 6 files changed, 183 insertions(+), 118 deletions(-) create mode 100644 lib/apps_list/widgets/nyrna_error_message.dart diff --git a/lib/apps_list/apps_list_page.dart b/lib/apps_list/apps_list_page.dart index 53894136..10125c24 100644 --- a/lib/apps_list/apps_list_page.dart +++ b/lib/apps_list/apps_list_page.dart @@ -55,7 +55,11 @@ class _AppsListPageState extends State { } }); - return BlocBuilder( + return BlocConsumer( + listenWhen: (previous, current) { + return current.interactionErrors.isNotEmpty; + }, + listener: (context, state) => showErrorBanner(context, state), builder: (context, state) { List windows = state.windows; windows = _filterWindows(windows, state.windowFilter); @@ -94,6 +98,63 @@ class _AppsListPageState extends State { ); } + // Show a MaterialBanner with the error message. + void showErrorBanner(BuildContext context, AppsListState state) { + ScaffoldMessenger.of(context).showMaterialBanner( + MaterialBanner( + leading: const Icon(Icons.error, color: Colors.red), + content: const Text('There was an error...'), + actions: [ + TextButton( + onPressed: () async { + final scaffoldMessenger = ScaffoldMessenger.of(context); + final appsListCubit = context.read(); + + // Show a dialog with the error message. + await showDialog( + context: context, + builder: (context) { + return AlertDialog( + actionsPadding: const EdgeInsets.all(8), + title: const Text('Error'), + icon: const Icon(Icons.error, color: Colors.red), + scrollable: true, + content: NyrnaErrorMessage(state.interactionErrors.first), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Close'), + ), + TextButton( + onPressed: () { + context.read().clearInteractionErrors(); + Navigator.pop(context); + }, + child: const Text('Dismiss'), + ), + ], + ); + }, + ); + + if (appsListCubit.state.interactionErrors.isEmpty) { + scaffoldMessenger.clearMaterialBanners(); + } + }, + child: const Text('OPEN'), + ), + TextButton( + onPressed: () { + context.read().clearInteractionErrors(); + ScaffoldMessenger.of(context).clearMaterialBanners(); + }, + child: const Text('DISMISS'), + ), + ], + ), + ); + } + Future _showReleaseNotesDialog( BuildContext context, ReleaseNotes releaseNotes, diff --git a/lib/apps_list/cubit/apps_list_cubit.dart b/lib/apps_list/cubit/apps_list_cubit.dart index f4c83e69..178341d3 100644 --- a/lib/apps_list/cubit/apps_list_cubit.dart +++ b/lib/apps_list/cubit/apps_list_cubit.dart @@ -345,6 +345,13 @@ class AppsListCubit extends Cubit { )); } + /// Clear all interaction errors. + void clearInteractionErrors() { + emit(state.copyWith( + interactionErrors: [], + )); + } + @override Future close() async { _timer?.cancel(); diff --git a/lib/apps_list/widgets/custom_app_bar.dart b/lib/apps_list/widgets/custom_app_bar.dart index 6777e354..1116be3c 100644 --- a/lib/apps_list/widgets/custom_app_bar.dart +++ b/lib/apps_list/widgets/custom_app_bar.dart @@ -21,7 +21,10 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { Widget build(BuildContext context) { final settingsButton = IconButton( icon: const Icon(Icons.settings), - onPressed: () => Navigator.pushNamed(context, SettingsPage.id), + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentMaterialBanner(); + Navigator.pushNamed(context, SettingsPage.id); + }, ); final updateAvailableButton = BlocBuilder( diff --git a/lib/apps_list/widgets/nyrna_error_message.dart b/lib/apps_list/widgets/nyrna_error_message.dart new file mode 100644 index 00000000..fdcbaa1b --- /dev/null +++ b/lib/apps_list/widgets/nyrna_error_message.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; + +import '../../app/app.dart'; +import '../models/models.dart'; + +class NyrnaErrorMessage extends StatelessWidget { + final InteractionError? interactionError; + + const NyrnaErrorMessage(this.interactionError, {super.key}); + + @override + Widget build(BuildContext context) { + if (interactionError == null) return const SizedBox(); + + return Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.red), + borderRadius: BorderRadius.circular(8), + ), + child: Card( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Encountered a problem attempting to ${interactionError!.interactionType.name}.', + style: const TextStyle(fontSize: 18), + ), + const Text( + ''' + This is sometimes resolved by running Nyrna with root / administrator privileges. + + Interacting with applications can go wrong for several reasons. In general, manipulating processes like this is known to be able to cause unpredictable results and there is usually not much Nyrna can do if it responds poorly, not at all, or crashes. + + This is why Nyrna comes with the disclaimer that things can go wrong, and you should be sure to always save your work and games.''', + ), + const Divider(), + const Text('More info'), + ExpansionTile( + title: const Text('If this is a game...'), + children: [ + MarkdownBody( + data: ''' +If this is a game, check if it uses `Easy Anti-Cheat` by searching for it at [pcgamingwiki.com](https://www.pcgamingwiki.com) and checking if the "Middleware" section lists Easy Anti-Cheat. + +Due to the restricted and obfuscated nature of Easy Anti-Cheat Nyrna cannot manage titles that use this.''', + onTapLink: (String text, String? href, String title) { + if (href == null) return; + AppCubit.instance.launchURL(href); + }, + selectable: true, + ), + ], + ), + ExpansionTile( + title: const Text('Report bug'), + children: [ + MarkdownBody( + data: ''' +If you believe this is an issue with Nyrna rather than a limitation of manipulating processes you can [create an issue](https://github.com/Merrit/nyrna/issues). + +For troubleshooting or to include in filing an issue you can obtain more detailed logs by: +- Starting Nyrna with verbose logging, eg: + + `nyrna --verbose` +- Reproducing the error +- Copying the logs from the settings page''', + onTapLink: (String text, String? href, String title) { + if (href == null) return; + AppCubit.instance.launchURL(href); + }, + selectable: true, + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/apps_list/widgets/widgets.dart b/lib/apps_list/widgets/widgets.dart index 655e9512..05d15d09 100644 --- a/lib/apps_list/widgets/widgets.dart +++ b/lib/apps_list/widgets/widgets.dart @@ -1,3 +1,4 @@ export 'custom_app_bar.dart'; export 'first_run_dialog.dart'; +export 'nyrna_error_message.dart'; export 'window_tile.dart'; diff --git a/lib/apps_list/widgets/window_tile.dart b/lib/apps_list/widgets/window_tile.dart index 2877a408..28e06c02 100644 --- a/lib/apps_list/widgets/window_tile.dart +++ b/lib/apps_list/widgets/window_tile.dart @@ -1,11 +1,8 @@ -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import '../../app/app.dart'; import '../../logs/logs.dart'; import '../../native_platform/native_platform.dart'; import '../apps_list.dart'; @@ -147,16 +144,6 @@ class _DetailsButton extends StatelessWidget { return BlocBuilder( builder: (context, state) { - final interactionError = state // - .interactionErrors - .singleWhereOrNull((element) => element.windowId == window.id); - - final errorText = (interactionError != null) ? '❗' : ''; - final Widget errorIndicator = Text( - errorText, - style: const TextStyle(fontFamily: 'Noto Color Emoji'), - ); - final toggleAllButton = MenuItemButton( child: Text('$availableAction all instances'), onPressed: () => context.read().toggleAll(window), @@ -182,7 +169,7 @@ class _DetailsButton extends StatelessWidget { showDialog( context: context, builder: (context) { - return _DetailsDialog(interactionError, window); + return _DetailsDialog(window); }, ); }, @@ -194,7 +181,6 @@ class _DetailsButton extends StatelessWidget { return Row( mainAxisSize: MainAxisSize.min, children: [ - errorIndicator, moreActionsButton, ], ); @@ -204,10 +190,9 @@ class _DetailsButton extends StatelessWidget { } class _DetailsDialog extends StatelessWidget { - final InteractionError? interactionError; final Window window; - const _DetailsDialog(this.interactionError, this.window); + const _DetailsDialog(this.window); @override Widget build(BuildContext context) { @@ -217,35 +202,36 @@ class _DetailsDialog extends StatelessWidget { AppLocalizations.of(context)!.detailsDialogTitle, ), ), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - _ErrorMessage(interactionError), - ListTile( - title: Text( - AppLocalizations.of(context)!.detailsDialogWindowTitle, + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: Text( + AppLocalizations.of(context)!.detailsDialogWindowTitle, + ), + subtitle: SelectableText(window.title), ), - subtitle: SelectableText(window.title), - ), - ListTile( - title: Text( - AppLocalizations.of(context)!.detailsDialogExecutableName, + ListTile( + title: Text( + AppLocalizations.of(context)!.detailsDialogExecutableName, + ), + subtitle: SelectableText(window.process.executable), ), - subtitle: SelectableText(window.process.executable), - ), - ListTile( - title: Text( - AppLocalizations.of(context)!.detailsDialogPID, + ListTile( + title: Text( + AppLocalizations.of(context)!.detailsDialogPID, + ), + subtitle: SelectableText(window.process.pid.toString()), ), - subtitle: SelectableText(window.process.pid.toString()), - ), - ListTile( - title: Text( - AppLocalizations.of(context)!.detailsDialogCurrentStatus, + ListTile( + title: Text( + AppLocalizations.of(context)!.detailsDialogCurrentStatus, + ), + subtitle: SelectableText(window.process.status.name), ), - subtitle: SelectableText(window.process.status.name), - ), - ], + ], + ), ), actions: [ TextButton( @@ -256,77 +242,3 @@ class _DetailsDialog extends StatelessWidget { ); } } - -class _ErrorMessage extends StatelessWidget { - final InteractionError? interactionError; - - const _ErrorMessage(this.interactionError); - - @override - Widget build(BuildContext context) { - if (interactionError == null) return const SizedBox(); - - return Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.red), - borderRadius: BorderRadius.circular(8), - ), - child: Card( - child: ExpansionTile( - leading: const Text( - '❗', - style: TextStyle(fontFamily: 'Noto Color Emoji'), - ), - title: Text( - 'Encountered a problem attempting to ${interactionError!.interactionType.name}.', - ), - children: [ - const Text( - ''' -This is sometimes resolved by running Nyrna with root / administrator privileges. - -Interacting with applications can go wrong for several reasons. In general, manipulating processes like this is known to be able to cause unpredictable results and there is usually not much Nyrna can do if it responds poorly, not at all, or crashes. - -This is why Nyrna comes with the disclaimer that things can go wrong, and you should be sure to always save your work and games.''', - ), - const Divider(), - const Text('More info'), - ExpansionTile( - title: const Text('If this is a game...'), - children: [ - MarkdownBody( - data: ''' -If this is a game, check if it uses `Easy Anti-Cheat` by searching for it at [pcgamingwiki.com](https://www.pcgamingwiki.com) and checking if the "Middleware" section lists Easy Anti-Cheat. - -Due to the restricted and obfuscated nature of Easy Anti-Cheat Nyrna cannot manage titles that use this.''', - onTapLink: (String text, String? href, String title) { - if (href == null) return; - AppCubit.instance.launchURL(href); - }, - ), - ], - ), - ExpansionTile( - title: const Text('Report bug'), - children: [ - MarkdownBody( - data: ''' -If you believe this is an issue with Nyrna rather than a limitation of manipulating processes you can [create an issue](https://github.com/Merrit/nyrna/issues). - -For troubleshooting or to include in filing an issue you can obtain more detailed logs by: -- Starting Nyrna with verbose logging, eg: `nyrna --verbose` -- Reproducing the error -- Copying the logs from the settings page''', - onTapLink: (String text, String? href, String title) { - if (href == null) return; - AppCubit.instance.launchURL(href); - }, - ), - ], - ), - ], - ), - ), - ); - } -} From f5547fae43d969af1fa66e9146dd342a99dda68f Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:11:06 -0400 Subject: [PATCH 18/20] refactor: improve error message appearance --- .../widgets/nyrna_error_message.dart | 104 +++++++++--------- 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/lib/apps_list/widgets/nyrna_error_message.dart b/lib/apps_list/widgets/nyrna_error_message.dart index fdcbaa1b..b57956db 100644 --- a/lib/apps_list/widgets/nyrna_error_message.dart +++ b/lib/apps_list/widgets/nyrna_error_message.dart @@ -13,69 +13,63 @@ class NyrnaErrorMessage extends StatelessWidget { Widget build(BuildContext context) { if (interactionError == null) return const SizedBox(); - return Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.red), - borderRadius: BorderRadius.circular(8), - ), - child: Card( - child: Column( - mainAxisSize: MainAxisSize.min, + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Encountered a problem attempting to ${interactionError!.interactionType.name}.', + style: const TextStyle(fontSize: 18), + ), + const Text( + ''' + This is sometimes resolved by running Nyrna with root / administrator privileges. + + Interacting with applications can go wrong for several reasons. In general, manipulating processes like this is known to be able to cause unpredictable results and there is usually not much Nyrna can do if it responds poorly, not at all, or crashes. + + This is why Nyrna comes with the disclaimer that things can go wrong, and you should be sure to always save your work and games.''', + ), + const Text( + 'More info', + style: TextStyle(fontSize: 18), + ), + ExpansionTile( + title: const Text('If this is a game...'), children: [ - Text( - 'Encountered a problem attempting to ${interactionError!.interactionType.name}.', - style: const TextStyle(fontSize: 18), - ), - const Text( - ''' - This is sometimes resolved by running Nyrna with root / administrator privileges. - - Interacting with applications can go wrong for several reasons. In general, manipulating processes like this is known to be able to cause unpredictable results and there is usually not much Nyrna can do if it responds poorly, not at all, or crashes. - - This is why Nyrna comes with the disclaimer that things can go wrong, and you should be sure to always save your work and games.''', - ), - const Divider(), - const Text('More info'), - ExpansionTile( - title: const Text('If this is a game...'), - children: [ - MarkdownBody( - data: ''' + MarkdownBody( + data: ''' If this is a game, check if it uses `Easy Anti-Cheat` by searching for it at [pcgamingwiki.com](https://www.pcgamingwiki.com) and checking if the "Middleware" section lists Easy Anti-Cheat. Due to the restricted and obfuscated nature of Easy Anti-Cheat Nyrna cannot manage titles that use this.''', - onTapLink: (String text, String? href, String title) { - if (href == null) return; - AppCubit.instance.launchURL(href); - }, - selectable: true, - ), - ], + onTapLink: (String text, String? href, String title) { + if (href == null) return; + AppCubit.instance.launchURL(href); + }, + selectable: true, ), - ExpansionTile( - title: const Text('Report bug'), - children: [ - MarkdownBody( - data: ''' -If you believe this is an issue with Nyrna rather than a limitation of manipulating processes you can [create an issue](https://github.com/Merrit/nyrna/issues). - -For troubleshooting or to include in filing an issue you can obtain more detailed logs by: -- Starting Nyrna with verbose logging, eg: - - `nyrna --verbose` -- Reproducing the error -- Copying the logs from the settings page''', - onTapLink: (String text, String? href, String title) { - if (href == null) return; - AppCubit.instance.launchURL(href); - }, - selectable: true, - ), - ], + ], + ), + ExpansionTile( + title: const Text('Report bug'), + children: [ + MarkdownBody( + data: ''' + If you believe this is an issue with Nyrna rather than a limitation of manipulating processes you can [create an issue](https://github.com/Merrit/nyrna/issues). + + For troubleshooting or to include in filing an issue you can obtain more detailed logs by: + - Starting Nyrna with verbose logging, eg: + +`nyrna --verbose` + - Reproducing the error + - Copying the logs from the settings page''', + onTapLink: (String text, String? href, String title) { + if (href == null) return; + AppCubit.instance.launchURL(href); + }, + selectable: true, ), ], ), - ), + ], ); } } From 87f8c1400b0eb65eec9219917cc2e52e373e1aec Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:14:57 -0400 Subject: [PATCH 19/20] feat(error msg): mention games that grab exclusive input Resolves #220 --- lib/apps_list/widgets/nyrna_error_message.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/apps_list/widgets/nyrna_error_message.dart b/lib/apps_list/widgets/nyrna_error_message.dart index b57956db..3ee8ca02 100644 --- a/lib/apps_list/widgets/nyrna_error_message.dart +++ b/lib/apps_list/widgets/nyrna_error_message.dart @@ -39,7 +39,11 @@ class NyrnaErrorMessage extends StatelessWidget { data: ''' If this is a game, check if it uses `Easy Anti-Cheat` by searching for it at [pcgamingwiki.com](https://www.pcgamingwiki.com) and checking if the "Middleware" section lists Easy Anti-Cheat. -Due to the restricted and obfuscated nature of Easy Anti-Cheat Nyrna cannot manage titles that use this.''', +Due to the restricted and obfuscated nature of Easy Anti-Cheat Nyrna cannot manage titles that use this. + +Also, some games grab exclusive control of the mouse and keyboard, which can cause Nyrna's shortcuts to not work. This is a limitation of the game, not Nyrna. Known examples: + +- `Doom (2016)`''', onTapLink: (String text, String? href, String title) { if (href == null) return; AppCubit.instance.launchURL(href); From 0b3e896b9efdd5db638efb1cbb0f3127740b8077 Mon Sep 17 00:00:00 2001 From: Kristen McWilliam <9575627+Merrit@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:23:41 -0400 Subject: [PATCH 20/20] chore: bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 60edf8f8..9d28506c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: nyrna description: Suspend any game or application. publish_to: "none" -version: 2.21.0 +version: 2.22.0 environment: sdk: ">=3.0.0 <4.0.0"