From 69f2dcd527c454808010d00406d86592741359c3 Mon Sep 17 00:00:00 2001 From: Alessandro Autiero Date: Thu, 24 Aug 2023 19:28:31 +0200 Subject: [PATCH] 8.2 --- assets/images/auth.png | Bin 0 -> 698 bytes assets/images/cloud.png | Bin 0 -> 522 bytes assets/images/download.png | Bin 0 -> 1126 bytes assets/images/host.png | Bin 0 -> 1266 bytes assets/images/info.png | Bin 0 -> 549 bytes assets/images/play.png | Bin 0 -> 1048 bytes assets/images/settings.png | Bin 0 -> 1065 bytes assets/images/user.png | Bin 0 -> 2115 bytes .../bitsdojo_window-0.1.5/CHANGELOG.md | 45 --- dependencies/bitsdojo_window-0.1.5/LICENSE | 21 -- dependencies/bitsdojo_window-0.1.5/README.md | 262 ------------------ .../lib/bitsdojo_window.dart | 5 - .../lib/src/app_window.dart | 43 --- .../lib/src/widgets/window_border.dart | 49 ---- .../lib/src/widgets/window_caption.dart | 48 ---- .../bitsdojo_window-0.1.5/pubspec.yaml | 31 --- lib/cli.dart | 5 +- lib/main.dart | 38 +-- lib/src/cli/compatibility.dart | 3 +- lib/src/cli/config.dart | 5 +- lib/src/cli/game.dart | 20 +- lib/src/cli/reboot.dart | 5 +- lib/src/cli/server.dart | 5 +- lib/src/model/fortnite_version.dart | 20 +- lib/src/ui/controller/game_controller.dart | 2 - lib/src/ui/controller/hosting_controller.dart | 6 +- lib/src/ui/controller/server_controller.dart | 4 +- .../ui/controller/settings_controller.dart | 10 +- lib/src/ui/dialog/add_local_version.dart | 5 +- lib/src/ui/dialog/add_server_version.dart | 15 +- lib/src/ui/dialog/dialog.dart | 6 - lib/src/ui/dialog/game_dialogs.dart | 2 +- lib/src/ui/dialog/server_dialogs.dart | 8 +- lib/src/ui/dialog/snackbar.dart | 2 +- lib/src/ui/page/browse_page.dart | 4 - lib/src/ui/page/home_page.dart | 227 +++++++++------ lib/src/ui/page/hosting_page.dart | 12 +- lib/src/ui/page/info_page.dart | 16 +- lib/src/ui/page/launcher_page.dart | 190 +------------ lib/src/ui/page/play_page.dart | 154 ++++++++++ lib/src/ui/page/server_page.dart | 22 +- lib/src/ui/page/settings_page.dart | 21 +- lib/src/ui/widget/home/build_selector.dart | 2 +- lib/src/ui/widget/home/launch_button.dart | 38 +-- lib/src/ui/widget/home/setting_tile.dart | 30 +- lib/src/ui/widget/home/version_selector.dart | 10 +- .../icons => lib/src/ui/widget/os}/icons.dart | 26 +- .../ui/widget/os}/mouse_state_builder.dart | 15 +- lib/src/ui/widget/os/window_border.dart | 20 +- .../src/ui/widget/os}/window_button.dart | 112 ++++---- ...dow_buttons.dart => window_title_bar.dart} | 2 +- lib/src/ui/widget/server/server_button.dart | 2 +- .../widget/server/server_type_selector.dart | 2 +- lib/src/ui/widget/shared/file_selector.dart | 5 - lib/src/ui/widget/shared/fluent_card.dart | 16 -- lib/src/ui/widget/shared/profile_widget.dart | 56 ++++ lib/src/util/build.dart | 3 +- lib/src/util/checks.dart | 5 +- lib/src/util/error.dart | 4 +- lib/src/util/injector.dart | 2 +- lib/src/util/os.dart | 4 +- lib/src/util/process.dart | 1 - lib/src/util/server.dart | 5 +- pubspec.yaml | 5 +- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + .../exe/custom-inno-setup-script.iss | 36 +++ windows/packaging/exe/make_config.yaml | 3 + windows/runner/main.cpp | 25 +- windows/runner/win32_window.cpp | 20 +- 70 files changed, 677 insertions(+), 1087 deletions(-) create mode 100644 assets/images/auth.png create mode 100644 assets/images/cloud.png create mode 100644 assets/images/download.png create mode 100644 assets/images/host.png create mode 100644 assets/images/info.png create mode 100644 assets/images/play.png create mode 100644 assets/images/settings.png create mode 100644 assets/images/user.png delete mode 100644 dependencies/bitsdojo_window-0.1.5/CHANGELOG.md delete mode 100644 dependencies/bitsdojo_window-0.1.5/LICENSE delete mode 100644 dependencies/bitsdojo_window-0.1.5/README.md delete mode 100644 dependencies/bitsdojo_window-0.1.5/lib/bitsdojo_window.dart delete mode 100644 dependencies/bitsdojo_window-0.1.5/lib/src/app_window.dart delete mode 100644 dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_border.dart delete mode 100644 dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_caption.dart delete mode 100644 dependencies/bitsdojo_window-0.1.5/pubspec.yaml create mode 100644 lib/src/ui/page/play_page.dart rename {dependencies/bitsdojo_window-0.1.5/lib/src/icons => lib/src/ui/widget/os}/icons.dart (86%) rename {dependencies/bitsdojo_window-0.1.5/lib/src/widgets => lib/src/ui/widget/os}/mouse_state_builder.dart (82%) rename {dependencies/bitsdojo_window-0.1.5/lib/src/widgets => lib/src/ui/widget/os}/window_button.dart (61%) rename lib/src/ui/widget/os/{window_buttons.dart => window_title_bar.dart} (96%) delete mode 100644 lib/src/ui/widget/shared/fluent_card.dart create mode 100644 lib/src/ui/widget/shared/profile_widget.dart create mode 100644 windows/packaging/exe/custom-inno-setup-script.iss diff --git a/assets/images/auth.png b/assets/images/auth.png new file mode 100644 index 0000000000000000000000000000000000000000..999befebd56ea7f47e2196f666f975831d9c9a23 GIT binary patch literal 698 zcmV;r0!96aP)~lP{>4S7P zo09LgyEET!mYp4;wI(#983WHqqeZvxIUUxYpAAwOUu7(IDYk3ya`d;X7}=B?zpb2oS68>g-LsAoKonPChm-;Nd*GOavTwGJ>YHMPTIVC|BcN> zht)-!_(FqPmvLhx&7le)eT$`DjL$%G0Ki`ho{a@PorzOeGB zaXo}Caj|?o3+Sk4PxV+X+baM8(a)Z0fWxW^09aEuz?iQDZ1{QzN|igP)f$6Aa8W}d=%5bb)Gf)qAw8dqv{uuShI@-+ zzEu3YebH9mcTR?g8Nrw&4TW`2kUoT7{O0C4TCm4+on`+0FEe++PkIxK#TpGV)c^nh M07*qoM6N<$f-hC(+yDRo literal 0 HcmV?d00001 diff --git a/assets/images/download.png b/assets/images/download.png new file mode 100644 index 0000000000000000000000000000000000000000..9b66b0dc0683f2df36bb4830f2bebf40766018d4 GIT binary patch literal 1126 zcmV-s1eyDZP)t$=_=-R5y=q^+o5@Q%H zSu$a$M8Sm_O&3fCCIlpcSqvbC5a#gqXUvFUKg>j75Orvxfe9v%ku2F58gx)tvUazQ zwx?@PZ|m`gqpZ6mo6IM9|GbyydB5lTKHz@_waC6Fj26cmtWvXDlB85LBJ_^j`}1o6 z1CJyiS1MN-3moT-HfMo-?Thm4TnhjoIOfK{wKMnc+_>r%COq5Y@%W7;3*=i$>s5w= z6PtFmGAeC;I?u`h9S=|x5b$}?dZ2D})N^;Q;PbXGTEO+esq93O_t?s7I3km$^9ng& zP-XU}rjqz{@1`+#|Me}=Xz2IF2vC;d=SE#kzZo);6kyT-gq}Mfh6NmUJ#%~9b7v)h z&T#3Xh6U6L;L9ToIMjF;w#UuTXc&0CUNr39fgR01r+c&Y`JiceK4w9tHJG>L zS)8?1u45Sn@C=}40dX>jT%8Vf`%38bEEEbEa6uh2spHkUU6aB@ z7l4}pAmg;T$E)g(&2d-7N&qNGQVN8SX+s~r2|@@YDU~s^^T=tFZ)EWEo~{nxK;P9X z6C;DQGDgAc6w2(3MnVHJdao1NIdXFptTZbMEE z2QuTQZG52`RqNK`r;av+69l;{o=n%`F%e%Jtn&@KZ`D88iORDSzb9wdeK|%O$0&H& zxVwjZa`YprynGFedCCQC=)T^K*SGH!P1cey07OE8#OTo9Vps_5j)eT3^UY`h*f@@> zsoA(We*3R+N$^LcSR^(lqT#4iU0pp!2-yI@HXWvndzeQ+1mI635(A7pYie|Cxbmr0 z&r&Qa13l~MHoo5&xYTv2SrCLa0RHKiT=2N_p~O*o{^RDB)ZpFwk{FJrx9{)m4_U3& zlS?970HmnM(fjQ;ozl>tUy6of(#2mdCS5Mqf#o270F}d0>N)k*chc$hbE!ge;U56_ s5NGqYXU`xV9qKO7$RWP6u0Uw$OQKE^O5_u>I z38^vBgoMP)13ZY)f`O(FT1iN$MU6&{C~__3S^~Xs6X>+l_MDk>whwg5OlL@p3Hxbh zt$+Rhzt-7%A9%n^{8!+D=jvxT+FhZf=~L)G54Sh}{=WnUHa+_!+LrE5rTK`yeFw4KqV;V0c z>3{#?$0+u7s`WTpAhS~TRFx3c_xe*;i75gyS()bDR;X#+44;IUEbw@^+nl-iH3 z!_|wWkeQmrl=fQfIFC;WX9=x81KI#&A{vjybF`t5UNeOONI^RF(OuDhu%L zvgsVT6y@>_+u3#C%#NiGW$oDVR+Tu`Gfc;^n{@X^3Ha3INwLHx*4Ee|3{|H}bCS*2 zqIR>_+P%>=D+`72swA64M9t=q^;LuR)D(kE8Q~UDyZOVE5n;+scf71fu~Ku0KN7o10dx6B+c4!tXJ8~TNDIX~06O4XsfR7s>5o9%1-OmF zMgW;(zTpfGYi&CTs%BB!cqmO^PE%*aykF=2CHx-kj@W$H6BwAiclJ{Ycbt23QTNJ& zd(=FMN8#Ka4Gb9?Jwn878L34+1n~aB&|2$F)y6aR==V!Z literal 0 HcmV?d00001 diff --git a/assets/images/info.png b/assets/images/info.png new file mode 100644 index 0000000000000000000000000000000000000000..f6037adc986e0a940b9c5994c80aa6ef03538174 GIT binary patch literal 549 zcmV+=0^0qFP)v6 zD6H8c*CL!<0%EULb~f(%lSafl$R-xDtW|_~u#k1WZ4yjQCTILBeY^R7-shWPX5d{O ziLW424wtaH0^~s^08qWcP!W~AdU5dZMSyJ3%xOZlPzs(IPQ=*t`qz=_lL49Fwt!(D z818y`(^F=o>@v@#4Z-pN z-%0uYBbWf8GGl zgrEMEA-)EO%jQ7U@V&3ytt1u zZy2>}(V+XY`_asU>;q}v$Zd1bFRstdc}*{i!xb@h4mkEX3mh4>vo7;iK3>@%Tx>o6 nJn*3vz5*&n*o~g~yPmE87V&;Kl`fJX00000NkvXXu0mjfR2lR9 literal 0 HcmV?d00001 diff --git a/assets/images/play.png b/assets/images/play.png new file mode 100644 index 0000000000000000000000000000000000000000..1e370e58d8c6bfd2f4f7c674958d9e5c92e2bb7a GIT binary patch literal 1048 zcmV+z1n2vSP)ccK~zYI?Umb4TvZgte|yiI87`dxq+BIwF(n-!sqtw_K_y>rc99`X)4hYBIucSNt)#q0xo;Ak3{-Bg{{XYA& zO-l9Rm$!R6vR2mX(L83)@Jz;W(ALLFiFJSAyMnctkLTh)2q}gRR+S72A#z(L7@3I& zrQ{BXrp;YUFX+UR<_25Y9xwG(zU`WRBpua#u&!)4U*O5ya=^j450q?|k;+&^Vrdj= zwJSl*bA=Qa{5@32Gze;5s-+773FXL_8|(aIZU6`8Do~P$#ku*(6_ys3=zRMvUVXC@ zfZ_s;7iu)*>b#C3&)0A*z05`Ybb5$Ix^X)5>k&0KUgz_TTE~ZfP}LQ;Y1s)xUQ49pe$bLMDw|5Rd?S{C*tEMCEd5 znuc3j*#VE+MMI4rkLKFI0n&AqL|YCKG7bK$EhpM?Xl*E&%;tjb<*d!GAAZR<$K|@_R0KGRpWB9=%lu(4n#yNYjhr6ZK+wI53|6ns7 z4?kpXa$=R&&`{S7z#kJ+czi1h7akkmO=9-~ue2T}W7;eH$l<)b<+V1x{h|*L9Dnbf zXD?7uQpo93#{lrIepG;?ogFj-XDn>%q%6b9ThTd*ZDPj)^?q<9Tl2cN)m|~JBTZy zNqbVJEOU51u{CHeZV-tZC&%7r`plZ|LVJD2vR!8sgd%Z+x%k%nNZcTq&J78G zJNG88mlb%p21Sx(Y8Q(bHBA#O2+@0p4wH&Sq_Q7l_Mx+H%5+Nv7v@l}MS_ z9V7J-Y*1K<7i&baGv zQmm|>*f($tK$ORj)_$`tkB7Q%eG~j>Rd-3s9-g1{uk_lIULd!qt{tze0;2#57Y(wZ z=*xgtSW1C_H)yY-q#Il2ZUEz8_l%IvO-l7&F94XkTK-a$=i~MYOQ|>*H*HrxeA=1l z#Z8oX=T^muwX#FWEo!o33)(R^vIJaG@C2Tr$2;2)npMME-p6;qjiKPC?V1QdP%-1~ zNaNA@N&kuq;5wW{83kVGjag&Mu(jfE22~jXSSz;hgolm{AW5&Q+q`4O!nIb+Mc{q| zAXe7nT&=FV^^NNZ4UI>o)<9M_p;*({Fd2~zXy@R>zJX%`U-U9Bt$3bjJ5<=QQU{9MhAx|}8~&y!A@j3;8IE3fQR)EG3z{ug_@Po~ zFTi>kofwMb%uouKGMBH+w2DZN03Lv?3%8b&;my~aERTFNCABEa=>^ReOB5Qmb>`mP zk;DslX`6R_{oV+A4$;}rI6$-3dA*46ZLe{F&t8(E=ki-8q&Bjt(AY8$Rc<-2nBIeJ z0#V)AVg%^q2hjLjV-$H+M9x4raV8O=qa1wmYfbbXoLY@x+mCiN0Y77xQ^Ude z4uj+Q$|s7x9)91>CpUvy>v<}C>Sj0^hN?Ho2_K!vcD?a3_LmQ)oQGjsH`U=N!@+y% zL&e_{R>26o7L<7EjnDPFKTAAWEb(BNT!4{OPZ%wkh%<0}xqM26w|m1-DL9StitlKo zXI(FB*BQ+ynM8k@5?TAx=|j!|1E5An`ZR#lp1{lAS2IphH~S3u=v_m^8V9hdyPzGS zX23hHVG6j^#-0tm^9C)u_g063hG46PvAU1%f@}I;mzTCT5o}N~0n00000NkvXXu0mjftGD!B literal 0 HcmV?d00001 diff --git a/assets/images/user.png b/assets/images/user.png new file mode 100644 index 0000000000000000000000000000000000000000..68947e0b4d9d48545b773161b54caf83e271690c GIT binary patch literal 2115 zcmV-J2)y@+P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2iQqOK~#8N-J4rX zR7V)cheaa@6v0cpagmE6F;=QZDfnPwwFEV7+Qg8wg&0>++w`HeuTA=yQhO+T!BkJ4m%*y8)mu>&$|D z4#|b2K>Xn*`{3Id-BNFKTb);gxQ-)~$6HEUO{TzR{$ zuI{pVJphkB0Lm{$QV)rcg5c)`C>vc zz1=L;LMJ31t$-^~?}kAP72hD?3XT?5uU@SR3JT=SBUV?9jg6|Ip+U8@w5YDGE-_Ag ze7st-W{v9X>{R#f-#5Q$JG6W|hQ(@LNDC+|EDUkG-CTM~;UN%RaI5; zmS4VnX?|)D9v&{OW8J!Sbj0e!i4&^2TAon{x1euoNl8hs_yAmR4Nr^mixw?Xxw*Nb ze0h1fs;sOWqC8<4KjS^Tm)}WDOf)~Won(i@L7n@YAQv!ghi`K0)~%ABIdeu`zU(m= z8vyU&y?8*iWy=<`R12T+k7WQYeV=b|-n@CLySrPI@)q99?<`obKqVw_6-PRGU3+B7k|mPfxN$?gytnXPeur3fXdsokvju32`ex6bE$O32k0kX4>pOGi%#lRJ_Co8Eh&=C>_O&VE21Ed*w`+4^4nWQsk&Xm*_X3d%UkoRK3mMWCdSL>hn_m0GxR<%)X!`n8IRijoM=TQV~O`9ao?|KTFY$Tcn7&t4j znUg0^s=IgZibLG7V~4Z^204RaSyon-+P;0ebOCmsQ>RXupK2p41Y;pL5QaXHjZB|D zT_!?S3*c;z6QReCAImj|%k=bg6&)Qd*X;MDrKQq>G~=cL_+P?}YkhDea5|l8#*C4B zTt`QT!c!89omL@AjtV08}bbbv+-agor^YZe7q$%0Vn$x>Uw<_E`o&{=z!wA6O^- zfsHg#cPjwmIXqjS0SG<)ix=FI^A9>i)z&OKJ%|lW{f|DUFfZ#@+rrKj%O$zpSQl1PuyWqJx z_ya~YJc%959E9=%9AAGtwg3ya+xKfm;ET*Z-p_f`7y@H5-{=b>bC(bU~58iqYj6ox~QlqFn>Hf954ts26+-~1%%7GJpRd3DclR^G92MX t;eQbRe7+gNGjjZKW)0pnm+dv7)c>T{!)p9oFp~fP002ovPDHLkV1fbL-PiyC literal 0 HcmV?d00001 diff --git a/dependencies/bitsdojo_window-0.1.5/CHANGELOG.md b/dependencies/bitsdojo_window-0.1.5/CHANGELOG.md deleted file mode 100644 index c022588..0000000 --- a/dependencies/bitsdojo_window-0.1.5/CHANGELOG.md +++ /dev/null @@ -1,45 +0,0 @@ -## 0.1.5 - - Runs on Windows 7 -## 0.1.4 - - Updated win32 to 3.0.0 -## 0.1.3 - - Updated ffi to 2.0.0 -## 0.1.2 - - Flutter 3.0 support -## 0.1.1+1 - - Added Linux usage instructions -## 0.1.1 - - Linux support now stable -## 0.1.0+1 - - Fix gtk library name on Linux -## 0.1.0 - - Added null safety support -## 0.0.9 - - Linux support added -## 0.0.8 - - Added macOS readme instructions -## 0.0.7 - - macOS support added -## 0.0.6 - - Works with latest Flutter version (master channel) -## 0.0.5 - - Works with latest Flutter version (dev channel) -## 0.0.4 - - Better integration with other plugins -## 0.0.3 - - Using dpi-aware values for title bar and buttons dimensions - - Dynamically calculating default button padding instead of fixed one -## 0.0.2 - - Added video tutorial link -## 0.0.1 - -* Initial release - - Custom window frame - remove standard Windows titlebar and buttons - - Hide window on startup - - Show/hide window - - Minimize/Maximize/Restore/Close window - - Move window using Flutter widget - - Set window size, minimum size and maximum size - - Set window position - - Set window alignment on screen (center/topLeft/topRight/bottomLeft/bottomRight) - - Set window title diff --git a/dependencies/bitsdojo_window-0.1.5/LICENSE b/dependencies/bitsdojo_window-0.1.5/LICENSE deleted file mode 100644 index 93d3f15..0000000 --- a/dependencies/bitsdojo_window-0.1.5/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020-2021 Bogdan Hobeanu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dependencies/bitsdojo_window-0.1.5/README.md b/dependencies/bitsdojo_window-0.1.5/README.md deleted file mode 100644 index a55b3e1..0000000 --- a/dependencies/bitsdojo_window-0.1.5/README.md +++ /dev/null @@ -1,262 +0,0 @@ -# bitsdojo_window - -A [Flutter package](https://pub.dev/packages/bitsdojo_window) that makes it easy to customize and work with your Flutter desktop app window **on Windows, macOS and Linux**. - -Watch the tutorial to get started. Click the image below to watch the video: - -[![IMAGE ALT TEXT](https://img.youtube.com/vi/bee2AHQpGK4/0.jpg)](https://www.youtube.com/watch?v=bee2AHQpGK4 "Click to open") - - - -**Features**: - - - Custom window frame - remove standard Windows/macOS/Linux titlebar and buttons - - Hide window on startup - - Show/hide window - - Move window using Flutter widget - - Minimize/Maximize/Restore/Close window - - Set window size, minimum size and maximum size - - Set window position - - Set window alignment on screen (center/topLeft/topRight/bottomLeft/bottomRight) - - Set window title - -# Getting Started - -Install the package using `pubspec.yaml` - -# For Windows apps - -Inside your application folder, go to `windows\runner\main.cpp` and add these two lines at the beginning of the file: - -```cpp -#include -auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP); -``` - -# For macOS apps - -Inside your application folder, go to `macos\runner\MainFlutterWindow.swift` and add this line after the one saying `import FlutterMacOS` : - -```swift -import FlutterMacOS -import bitsdojo_window_macos // Add this line -``` - -Then change this line from: - -```swift -class MainFlutterWindow: NSWindow { -``` - -to this: - -```swift -class MainFlutterWindow: BitsdojoWindow { -``` - -After changing `NSWindow` to `BitsdojoWindow` add these lines below the line you changed: - -```swift -override func bitsdojo_window_configure() -> UInt { - return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP -} -``` - -Your code should now look like this: - -```swift -class MainFlutterWindow: BitsdojoWindow { - - override func bitsdojo_window_configure() -> UInt { - return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP - } - - override func awakeFromNib() { - ... //rest of your code -``` -# - -If you don't want to use a custom frame and prefer the standard window titlebar and buttons, you can remove the `BDW_CUSTOM_FRAME` flag from the code above. - -If you don't want to hide the window on startup, you can remove the `BDW_HIDE_ON_STARTUP` flag from the code above. - -# For Linux apps - -Inside your application folder, go to `linux\my_application.cc` and add this line at the beginning of the file: - -```cpp -#include -``` -Then look for these two lines: - -```cpp -gtk_window_set_default_size(window, 1280, 720); -gtk_widget_show(GTK_WIDGET(window)); -``` -and change them to this: - -```cpp -auto bdw = bitsdojo_window_from(window); // <--- add this line -bdw->setCustomFrame(true); // <-- add this line -//gtk_window_set_default_size(window, 1280, 720); // <-- comment this line -gtk_widget_show(GTK_WIDGET(window)); -``` - -As you can see, we commented the line calling `gtk_window_set_default_size` and added these two lines before `gtk_widget_show(GTK_WIDGET(window));` - -```cpp -auto bdw = bitsdojo_window_from(window); -bdw->setCustomFrame(true); -``` - -# Flutter app integration - -Now go to `lib\main.dart` and add this code in the `main` function right after `runApp(MyApp());` : - -```dart -void main() { - runApp(MyApp()); - - // Add this code below - - doWhenWindowReady(() { - const initialSize = Size(600, 450); - appWindow.minSize = initialSize; - appWindow.size = initialSize; - appWindow.alignment = Alignment.center; - appWindow.show(); - }); -} -``` -This will set an initial size and a minimum size for your application window, center it on the screen and show it on the screen. - -You can find examples in the `example` folder. - -Here is an example that displays this window: -
-Click to expand - -```dart -import 'package:flutter/material.dart'; -import 'package:bitsdojo_window/bitsdojo_window.dart'; - -void main() { - runApp(const MyApp()); - doWhenWindowReady(() { - final win = appWindow; - const initialSize = Size(600, 450); - win.minSize = initialSize; - win.size = initialSize; - win.alignment = Alignment.center; - win.title = "Custom window with Flutter"; - win.show(); - }); -} - -const borderColor = Color(0xFF805306); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - home: Scaffold( - body: WindowBorder( - color: borderColor, - width: 1, - child: Row( - children: const [LeftSide(), RightSide()], - ), - ), - ), - ); - } -} - -const sidebarColor = Color(0xFFF6A00C); - -class LeftSide extends StatelessWidget { - const LeftSide({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - return SizedBox( - width: 200, - child: Container( - color: sidebarColor, - child: Column( - children: [ - WindowTitleBarBox(child: MoveWindow()), - Expanded(child: Container()) - ], - ))); - } -} - -const backgroundStartColor = Color(0xFFFFD500); -const backgroundEndColor = Color(0xFFF6A00C); - -class RightSide extends StatelessWidget { - const RightSide({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - return Expanded( - child: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [backgroundStartColor, backgroundEndColor], - stops: [0.0, 1.0]), - ), - child: Column(children: [ - WindowTitleBarBox( - child: Row( - children: [Expanded(child: MoveWindow()), const WindowButtons()], - ), - ) - ]), - ), - ); - } -} - -final buttonColors = WindowButtonColors( - iconNormal: const Color(0xFF805306), - mouseOver: const Color(0xFFF6A00C), - mouseDown: const Color(0xFF805306), - iconMouseOver: const Color(0xFF805306), - iconMouseDown: const Color(0xFFFFD500)); - -final closeButtonColors = WindowButtonColors( - mouseOver: const Color(0xFFD32F2F), - mouseDown: const Color(0xFFB71C1C), - iconNormal: const Color(0xFF805306), - iconMouseOver: Colors.white); - -class WindowButtons extends StatelessWidget { - const WindowButtons({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - return Row( - children: [ - MinimizeWindowButton(colors: buttonColors), - MaximizeWindowButton(colors: buttonColors), - CloseWindowButton(colors: closeButtonColors), - ], - ); - } -} -``` -
- -# -# ❤️ **Sponsors - friends helping this package** - -I am developing this package in my spare time and any help is appreciated. -If you want to help you can [become a sponsor](https://github.com/sponsors/bitsdojo). - -🙏 Thank you! - -Want to help? [Become a sponsor](https://github.com/sponsors/bitsdojo) diff --git a/dependencies/bitsdojo_window-0.1.5/lib/bitsdojo_window.dart b/dependencies/bitsdojo_window-0.1.5/lib/bitsdojo_window.dart deleted file mode 100644 index 0b3205e..0000000 --- a/dependencies/bitsdojo_window-0.1.5/lib/bitsdojo_window.dart +++ /dev/null @@ -1,5 +0,0 @@ -export 'src/widgets/window_border.dart'; -export 'src/widgets/window_button.dart'; -export 'src/widgets/window_caption.dart'; -export 'src/icons/icons.dart'; -export 'src/app_window.dart'; diff --git a/dependencies/bitsdojo_window-0.1.5/lib/src/app_window.dart b/dependencies/bitsdojo_window-0.1.5/lib/src/app_window.dart deleted file mode 100644 index 8ab6e38..0000000 --- a/dependencies/bitsdojo_window-0.1.5/lib/src/app_window.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:bitsdojo_window_platform_interface/bitsdojo_window_platform_interface.dart'; -import 'package:bitsdojo_window_platform_interface/method_channel_bitsdojo_window.dart'; -import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart'; -import 'package:bitsdojo_window_macos/bitsdojo_window_macos.dart'; -import 'package:bitsdojo_window_linux/bitsdojo_window_linux.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; -import 'dart:io' show Platform; - -bool _platformInstanceNeedsInit = true; - -void initPlatformInstance() { - if (!kIsWeb) { - if (BitsdojoWindowPlatform.instance is MethodChannelBitsdojoWindow) { - if (Platform.isWindows) { - BitsdojoWindowPlatform.instance = BitsdojoWindowWindows(); - } else if (Platform.isMacOS) { - BitsdojoWindowPlatform.instance = BitsdojoWindowMacOS(); - } else if (Platform.isLinux) { - BitsdojoWindowPlatform.instance = BitsdojoWindowLinux(); - } - } - } else { - BitsdojoWindowPlatform.instance = BitsdojoWindowPlatformNotImplemented(); - } -} - -BitsdojoWindowPlatform get _platform { - var needsInit = _platformInstanceNeedsInit; - if (needsInit) { - initPlatformInstance(); - _platformInstanceNeedsInit = false; - } - return BitsdojoWindowPlatform.instance; -} - -void doWhenWindowReady(VoidCallback callback) { - _platform.doWhenWindowReady(callback); -} - -DesktopWindow get appWindow { - return _platform.appWindow; -} diff --git a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_border.dart b/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_border.dart deleted file mode 100644 index 5592653..0000000 --- a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_border.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart' - show WinDesktopWindow; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import '../app_window.dart'; - -class WindowBorder extends StatelessWidget { - final Widget child; - final Color color; - final double? width; - - WindowBorder({Key? key, required this.child, required this.color, this.width}) - : super(key: key); - - @override - Widget build(BuildContext context) { - bool isWindowsApp = - (!kIsWeb) && (defaultTargetPlatform == TargetPlatform.windows); - bool isLinuxApp = - (!kIsWeb) && (defaultTargetPlatform == TargetPlatform.linux); - - // Only show border on Windows and Linux - if (!(isWindowsApp || isLinuxApp)) { - return child; - } - - var borderWidth = width ?? 1; - var topBorderWidth = width ?? 1; - - if (appWindow is WinDesktopWindow) { - appWindow as WinDesktopWindow..setWindowCutOnMaximize(borderWidth.ceil()); - } - - if (isWindowsApp) { - topBorderWidth += 1 / appWindow.scaleFactor; - } - final topBorderSide = BorderSide(color: this.color, width: topBorderWidth); - final borderSide = BorderSide(color: this.color, width: borderWidth); - - return Container( - child: child, - decoration: BoxDecoration( - border: Border( - top: topBorderSide, - left: borderSide, - right: borderSide, - bottom: borderSide))); - } -} diff --git a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_caption.dart b/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_caption.dart deleted file mode 100644 index 2a15b59..0000000 --- a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_caption.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../app_window.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; - -class _MoveWindow extends StatelessWidget { - _MoveWindow({Key? key, this.child, this.onDoubleTap}) : super(key: key); - final Widget? child; - final VoidCallback? onDoubleTap; - @override - Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onPanStart: (details) { - appWindow.startDragging(); - }, - onDoubleTap: this.onDoubleTap ?? () => appWindow.maximizeOrRestore(), - child: this.child ?? Container()); - } -} - -class MoveWindow extends StatelessWidget { - final Widget? child; - final VoidCallback? onDoubleTap; - MoveWindow({Key? key, this.child, this.onDoubleTap}) : super(key: key); - @override - Widget build(BuildContext context) { - if (child == null) return _MoveWindow(onDoubleTap: this.onDoubleTap); - return _MoveWindow( - onDoubleTap: this.onDoubleTap, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [Expanded(child: this.child!)]), - ); - } -} - -class WindowTitleBarBox extends StatelessWidget { - final Widget? child; - WindowTitleBarBox({Key? key, this.child}) : super(key: key); - @override - Widget build(BuildContext context) { - if (kIsWeb) { - return Container(); - } - final titlebarHeight = appWindow.titleBarHeight; - return SizedBox(height: titlebarHeight, child: this.child ?? Container()); - } -} diff --git a/dependencies/bitsdojo_window-0.1.5/pubspec.yaml b/dependencies/bitsdojo_window-0.1.5/pubspec.yaml deleted file mode 100644 index 47ef658..0000000 --- a/dependencies/bitsdojo_window-0.1.5/pubspec.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: bitsdojo_window -description: A package to help with creating custom windows with Flutter desktop (custom border, titlebar and minimize/maximize/close buttons) and common desktop window operations (show/hide/position on screen) for Windows and macOS -version: 0.1.5 -homepage: https://www.bitsdojo.com -repository: https://github.com/bitsdojo/bitsdojo_window - -environment: - sdk: ">=2.17.0 <3.0.0" - flutter: ">=1.20.0" - -flutter: - plugin: - platforms: - windows: - default_package: bitsdojo_window_windows - macos: - default_package: bitsdojo_window_macos - linux: - default_package: bitsdojo_window_linux - -dependencies: - flutter: - sdk: flutter - bitsdojo_window_platform_interface: ^0.1.2 - #path: ../bitsdojo_window_platform_interface - bitsdojo_window_windows: ^0.1.5 - #path: ../bitsdojo_window_windows - bitsdojo_window_macos: ^0.1.3 - #path: ../bitsdojo_window_macos - bitsdojo_window_linux: ^0.1.3 - #path: ../bitsdojo_window_linux diff --git a/lib/cli.dart b/lib/cli.dart index f126fc9..58edec4 100644 --- a/lib/cli.dart +++ b/lib/cli.dart @@ -68,12 +68,11 @@ void main(List args) async { } stdout.writeln("Launching game..."); - if(version.executable == null){ + var executable = await version.executable; + if(executable == null){ throw Exception("Missing game executable at: ${version.location.path}"); } - await patchHeadless(version.executable!); - var serverType = getServerType(result); var serverHost = result["server-host"] ?? serverJson["${serverType.id}_host"]; var serverPort = result["server-port"] ?? serverJson["${serverType.id}_port"]; diff --git a/lib/main.dart b/lib/main.dart index 0188371..c7013da 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,5 @@ import 'dart:async'; -import 'package:bitsdojo_window/bitsdojo_window.dart'; -import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart' - show WinDesktopWindow; import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; @@ -17,6 +14,8 @@ import 'package:reboot_launcher/src/ui/page/home_page.dart'; import 'package:reboot_launcher/supabase.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:system_theme/system_theme.dart'; +import 'package:flutter_acrylic/flutter_acrylic.dart'; +import 'package:window_manager/window_manager.dart'; const double kDefaultWindowWidth = 1024; const double kDefaultWindowHeight = 1024; @@ -42,21 +41,21 @@ void main() async { Get.put(BuildController()); Get.put(SettingsController()); Get.put(HostingController()); - doWhenWindowReady(() { - var controller = Get.find(); - var size = Size(controller.width, controller.height); - var window = appWindow as WinDesktopWindow; - window.setWindowCutOnMaximize(appBarSize * 2); - appWindow.size = size; - if(controller.offsetX != null && controller.offsetY != null){ - appWindow.position = Offset(controller.offsetX!, controller.offsetY!); - }else { - appWindow.alignment = Alignment.center; - } - - appWindow.title = "Reboot Launcher"; - appWindow.show(); - }); + await windowManager.ensureInitialized(); + var controller = Get.find(); + var size = Size(controller.width, controller.height); + await windowManager.setSize(size); + if(controller.offsetX != null && controller.offsetY != null){ + await windowManager.setPosition(Offset(controller.offsetX!, controller.offsetY!)); + }else { + await windowManager.setAlignment(Alignment.center); + }; + await Window.initialize(); + await Window.setEffect( + effect: WindowEffect.acrylic, + color: Colors.transparent, + dark: SystemTheme.isDarkMode + ); var supabase = Supabase.instance.client; await supabase.from('hosts') .delete() @@ -91,6 +90,7 @@ class _RebootApplicationState extends State { FluentThemeData _createTheme(Brightness brightness) => FluentThemeData( brightness: brightness, accentColor: SystemTheme.accentColor.accent.toAccentColor(), - visualDensity: VisualDensity.standard + visualDensity: VisualDensity.standard, + scaffoldBackgroundColor: Colors.transparent ); } diff --git a/lib/src/cli/compatibility.dart b/lib/src/cli/compatibility.dart index bf4814b..9756966 100644 --- a/lib/src/cli/compatibility.dart +++ b/lib/src/cli/compatibility.dart @@ -1,8 +1,7 @@ import 'dart:collection'; import 'dart:convert'; -import 'dart:io'; - import 'dart:ffi'; +import 'dart:io'; import 'package:ffi/ffi.dart'; import 'package:win32/win32.dart'; diff --git a/lib/src/cli/config.dart b/lib/src/cli/config.dart index b170f9e..49c8b03 100644 --- a/lib/src/cli/config.dart +++ b/lib/src/cli/config.dart @@ -1,9 +1,8 @@ import 'dart:convert'; import 'package:args/args.dart'; - -import '../model/fortnite_version.dart'; -import '../model/server_type.dart'; +import 'package:reboot_launcher/src/model/fortnite_version.dart'; +import 'package:reboot_launcher/src/model/server_type.dart'; Iterable getServerTypes() => ServerType.values.map((entry) => entry.id); diff --git a/lib/src/cli/game.dart b/lib/src/cli/game.dart index 066560f..fea89f7 100644 --- a/lib/src/cli/game.dart +++ b/lib/src/cli/game.dart @@ -2,12 +2,11 @@ import 'dart:io'; import 'package:process_run/shell.dart'; import 'package:reboot_launcher/cli.dart'; - -import '../model/fortnite_version.dart'; -import '../util/injector.dart'; -import '../util/os.dart'; -import '../util/process.dart'; -import '../util/server.dart'; +import 'package:reboot_launcher/src/model/fortnite_version.dart'; +import 'package:reboot_launcher/src/util/injector.dart'; +import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/util/process.dart'; +import 'package:reboot_launcher/src/util/server.dart'; final List _errorStrings = [ "port 3551 failed: Connection refused", @@ -25,10 +24,9 @@ Future startGame() async { await _startLauncherProcess(version); await _startEacProcess(version); - var gamePath = version.executable?.path; - if (gamePath == null) { - throw Exception("${version.location - .path} no longer contains a Fortnite executable, did you delete or move it?"); + var executable = await version.executable; + if (executable == null) { + throw Exception("${version.location.path} no longer contains a Fortnite executable, did you delete or move it?"); } if (username == null) { @@ -36,7 +34,7 @@ Future startGame() async { stdout.writeln("No username was specified, using $username by default. Use --username to specify one"); } - _gameProcess = await Process.start(gamePath, createRebootArgs(username!, "", host, "")) + _gameProcess = await Process.start(executable.path, createRebootArgs(username!, "", host, "")) ..exitCode.then((_) => _onClose()) ..outLines.forEach((line) => _onGameOutput(line, dll, host, verbose)); } diff --git a/lib/src/cli/reboot.dart b/lib/src/cli/reboot.dart index 8994b79..b0e122d 100644 --- a/lib/src/cli/reboot.dart +++ b/lib/src/cli/reboot.dart @@ -1,10 +1,9 @@ import 'dart:io'; import 'package:archive/archive_io.dart'; -import 'package:reboot_launcher/src/util/server.dart'; - -import '../util/os.dart'; import 'package:http/http.dart' as http; +import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/util/server.dart'; const String _baseDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968021373169674/cobalt.dll"; const String _consoleDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968095033524234/console.dll"; diff --git a/lib/src/cli/server.dart b/lib/src/cli/server.dart index 49ca783..e710b58 100644 --- a/lib/src/cli/server.dart +++ b/lib/src/cli/server.dart @@ -1,9 +1,8 @@ import 'dart:io'; import 'package:process_run/shell.dart'; - -import '../model/server_type.dart'; -import '../util/server.dart' as server; +import 'package:reboot_launcher/src/model/server_type.dart'; +import 'package:reboot_launcher/src/util/server.dart' as server; Future startServer(String? host, String? port, ServerType type) async { stdout.writeln("Starting backend server..."); diff --git a/lib/src/model/fortnite_version.dart b/lib/src/model/fortnite_version.dart index dab7375..61ebfde 100644 --- a/lib/src/model/fortnite_version.dart +++ b/lib/src/model/fortnite_version.dart @@ -1,6 +1,8 @@ import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:path/path.dart' as path; +import 'package:reboot_launcher/src/util/patcher.dart'; class FortniteVersion { String name; @@ -22,8 +24,22 @@ class FortniteVersion { } } - File? get executable { - return findExecutable(location, "FortniteClient-Win64-Shipping.exe"); + Future get executable async { + var result = findExecutable(location, "FortniteClient-Win64-Shipping-Reboot.exe"); + if(result != null) { + return result; + } + + var original = findExecutable(location, "FortniteClient-Win64-Shipping.exe"); + if(original == null) { + return null; + } + + await Future.wait([ + compute(patchMatchmaking, original), + compute(patchHeadless, original) + ]); + return original; } File? get launcher { diff --git a/lib/src/ui/controller/game_controller.dart b/lib/src/ui/controller/game_controller.dart index 6649dd0..3bd6862 100644 --- a/lib/src/ui/controller/game_controller.dart +++ b/lib/src/ui/controller/game_controller.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:collection'; import 'dart:convert'; import 'package:fluent_ui/fluent_ui.dart'; @@ -9,7 +8,6 @@ import 'package:reboot_launcher/src/model/fortnite_version.dart'; import 'package:reboot_launcher/src/model/game_instance.dart'; import 'package:uuid/uuid.dart'; -import '../../model/update_status.dart'; const String kDefaultPlayerName = "Player"; diff --git a/lib/src/ui/controller/hosting_controller.dart b/lib/src/ui/controller/hosting_controller.dart index 6052fbd..7e37855 100644 --- a/lib/src/ui/controller/hosting_controller.dart +++ b/lib/src/ui/controller/hosting_controller.dart @@ -4,9 +4,9 @@ import 'package:get_storage/get_storage.dart'; import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; import 'package:reboot_launcher/src/ui/controller/update_controller.dart'; -import '../../model/game_instance.dart'; -import '../../model/update_status.dart'; -import '../../util/reboot.dart'; +import 'package:reboot_launcher/src/model/game_instance.dart'; +import 'package:reboot_launcher/src/model/update_status.dart'; +import 'package:reboot_launcher/src/util/reboot.dart'; const String kDefaultServerName = "Reboot Game Server"; diff --git a/lib/src/ui/controller/server_controller.dart b/lib/src/ui/controller/server_controller.dart index 95e0c0a..729f43e 100644 --- a/lib/src/ui/controller/server_controller.dart +++ b/lib/src/ui/controller/server_controller.dart @@ -4,8 +4,8 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; -import '../../model/server_type.dart'; -import '../../util/server.dart'; +import 'package:reboot_launcher/src/model/server_type.dart'; +import 'package:reboot_launcher/src/util/server.dart'; class ServerController extends GetxController { static const String _kDefaultServerHost = "127.0.0.1"; diff --git a/lib/src/ui/controller/settings_controller.dart b/lib/src/ui/controller/settings_controller.dart index 2e4eb91..e10af0d 100644 --- a/lib/src/ui/controller/settings_controller.dart +++ b/lib/src/ui/controller/settings_controller.dart @@ -1,3 +1,4 @@ +import 'dart:ui'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; @@ -5,9 +6,8 @@ import 'package:get_storage/get_storage.dart'; import 'package:reboot_launcher/main.dart'; import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/server.dart'; -import 'dart:ui'; -import '../../util/reboot.dart'; +import 'package:reboot_launcher/src/util/reboot.dart'; class SettingsController extends GetxController { static const String _kDefaultIp = "127.0.0.1"; @@ -49,9 +49,9 @@ class SettingsController extends GetxController { autoUpdate = RxBool(_storage.read("auto_update") ?? _kDefaultAutoUpdate); autoUpdate.listen((value) => _storage.write("auto_update", value)); scrollingDistance = 0.0; - firstRun = RxBool(_storage.read("fr") ?? true); - firstRun.listen((value) => _storage.write("fr", value)); - index = RxInt(firstRun() ? 0 : 1); + firstRun = RxBool(_storage.read("first_run") ?? true); + firstRun.listen((value) => _storage.write("first_run", value)); + index = RxInt(firstRun() ? 3 : 0); } TextEditingController _createController(String key, String name) { diff --git a/lib/src/ui/dialog/add_local_version.dart b/lib/src/ui/dialog/add_local_version.dart index 4f02c4e..fd1a6b5 100644 --- a/lib/src/ui/dialog/add_local_version.dart +++ b/lib/src/ui/dialog/add_local_version.dart @@ -6,9 +6,8 @@ import 'package:reboot_launcher/src/model/fortnite_version.dart'; import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; import 'package:reboot_launcher/src/ui/widget/home/version_name_input.dart'; -import '../../util/checks.dart'; -import '../widget/shared/file_selector.dart'; -import '../widget/shared/smart_check_box.dart'; +import 'package:reboot_launcher/src/util/checks.dart'; +import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart'; import 'dialog.dart'; import 'dialog_button.dart'; diff --git a/lib/src/ui/dialog/add_server_version.dart b/lib/src/ui/dialog/add_server_version.dart index bde9d1d..73a6622 100644 --- a/lib/src/ui/dialog/add_server_version.dart +++ b/lib/src/ui/dialog/add_server_version.dart @@ -6,17 +6,16 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/model/fortnite_version.dart'; -import 'package:reboot_launcher/src/util/error.dart'; -import 'package:reboot_launcher/src/util/os.dart'; -import 'package:reboot_launcher/src/util/build.dart'; import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; +import 'package:reboot_launcher/src/util/build.dart'; +import 'package:reboot_launcher/src/util/os.dart'; import 'package:universal_disk_space/universal_disk_space.dart'; -import '../../util/checks.dart'; -import '../controller/build_controller.dart'; -import '../widget/home/build_selector.dart'; -import '../widget/home/version_name_input.dart'; -import '../widget/shared/file_selector.dart'; +import 'package:reboot_launcher/src/util/checks.dart'; +import 'package:reboot_launcher/src/ui/controller/build_controller.dart'; +import 'package:reboot_launcher/src/ui/widget/home/build_selector.dart'; +import 'package:reboot_launcher/src/ui/widget/home/version_name_input.dart'; +import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart'; import 'dialog.dart'; import 'dialog_button.dart'; diff --git a/lib/src/ui/dialog/dialog.dart b/lib/src/ui/dialog/dialog.dart index 2a4640f..8fcf82d 100644 --- a/lib/src/ui/dialog/dialog.dart +++ b/lib/src/ui/dialog/dialog.dart @@ -1,7 +1,5 @@ -import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:clipboard/clipboard.dart'; import 'package:fluent_ui/fluent_ui.dart'; -import 'package:flutter/material.dart'; import 'package:reboot_launcher/src/ui/dialog/snackbar.dart'; import 'dialog_button.dart'; @@ -24,10 +22,6 @@ class GenericDialog extends AbstractDialog { Widget build(BuildContext context) { return Stack( children: [ - MoveWindow( - child: const SizedBox.expand(), - ), - ContentDialog( style: ContentDialogThemeData( padding: padding ?? const EdgeInsets.only(left: 20, right: 20, top: 15.0, bottom: 5.0) diff --git a/lib/src/ui/dialog/game_dialogs.dart b/lib/src/ui/dialog/game_dialogs.dart index 15146af..0953595 100644 --- a/lib/src/ui/dialog/game_dialogs.dart +++ b/lib/src/ui/dialog/game_dialogs.dart @@ -1,7 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:reboot_launcher/src/model/fortnite_version.dart'; -import '../../../main.dart'; +import 'package:reboot_launcher/main.dart'; import 'dialog.dart'; const String _unsupportedServerError = "The build you are currently using is not supported by Reboot. " diff --git a/lib/src/ui/dialog/server_dialogs.dart b/lib/src/ui/dialog/server_dialogs.dart index b2783ac..d4e580e 100644 --- a/lib/src/ui/dialog/server_dialogs.dart +++ b/lib/src/ui/dialog/server_dialogs.dart @@ -1,14 +1,12 @@ import 'package:fluent_ui/fluent_ui.dart'; - import 'package:reboot_launcher/src/model/server_type.dart'; -import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/ui/dialog/snackbar.dart'; import 'package:sync/semaphore.dart'; import 'package:url_launcher/url_launcher.dart'; -import '../../../main.dart'; -import '../../util/server.dart'; -import '../controller/server_controller.dart'; +import 'package:reboot_launcher/main.dart'; +import 'package:reboot_launcher/src/util/server.dart'; +import 'package:reboot_launcher/src/ui/controller/server_controller.dart'; import 'dialog.dart'; import 'dialog_button.dart'; diff --git a/lib/src/ui/dialog/snackbar.dart b/lib/src/ui/dialog/snackbar.dart index 05ff95a..4134bdf 100644 --- a/lib/src/ui/dialog/snackbar.dart +++ b/lib/src/ui/dialog/snackbar.dart @@ -1,6 +1,6 @@ import 'package:fluent_ui/fluent_ui.dart'; -import '../../../main.dart'; +import 'package:reboot_launcher/main.dart'; void showMessage(String text){ showSnackbar( diff --git a/lib/src/ui/page/browse_page.dart b/lib/src/ui/page/browse_page.dart index 81d237d..3f3ed5c 100644 --- a/lib/src/ui/page/browse_page.dart +++ b/lib/src/ui/page/browse_page.dart @@ -1,8 +1,4 @@ import 'package:fluent_ui/fluent_ui.dart'; -import 'package:get/get.dart'; -import 'package:reboot_launcher/src/ui/controller/hosting_controller.dart'; -import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart'; -import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart'; import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; diff --git a/lib/src/ui/page/home_page.dart b/lib/src/ui/page/home_page.dart index 9e04ab4..fc4bbd4 100644 --- a/lib/src/ui/page/home_page.dart +++ b/lib/src/ui/page/home_page.dart @@ -1,18 +1,16 @@ -import 'package:bitsdojo_window/bitsdojo_window.dart' hide WindowBorder; import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:reboot_launcher/main.dart'; -import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/ui/page/launcher_page.dart'; import 'package:reboot_launcher/src/ui/page/server_page.dart'; import 'package:reboot_launcher/src/ui/page/settings_page.dart'; -import 'package:window_manager/window_manager.dart'; +import 'package:reboot_launcher/src/ui/widget/shared/profile_widget.dart'; -import '../controller/game_controller.dart'; -import '../controller/settings_controller.dart'; -import '../widget/os/window_border.dart'; -import '../widget/os/window_buttons.dart'; +import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; +import 'package:reboot_launcher/src/ui/widget/os/window_border.dart'; +import 'package:reboot_launcher/src/ui/widget/os/window_title_bar.dart'; +import 'package:window_manager/window_manager.dart'; import 'hosting_page.dart'; import 'info_page.dart'; @@ -25,8 +23,8 @@ class HomePage extends StatefulWidget { class _HomePageState extends State with WindowListener, AutomaticKeepAliveClientMixin { static const double _kDefaultPadding = 12.0; - static const int _kPagesLength = 5; - + static const int _kPagesLength = 6; + final SettingsController _settingsController = Get.find(); final GlobalKey _searchKey = GlobalKey(); final FocusNode _searchFocusNode = FocusNode(); @@ -41,6 +39,7 @@ class _HomePageState extends State with WindowListener, AutomaticKeepA @override void initState() { + windowManager.show(); windowManager.addListener(this); _searchController.addListener(_onSearch); super.initState(); @@ -52,7 +51,8 @@ class _HomePageState extends State with WindowListener, AutomaticKeepA return; } - _searchItems.value = _allItems.whereType() + _searchItems.value = _allItems + .whereType() .where((item) => (item.title as Text).data!.toLowerCase().contains(searchValue.toLowerCase())) .toList() .cast(); @@ -84,73 +84,88 @@ class _HomePageState extends State with WindowListener, AutomaticKeepA @override void onWindowMoved() { - _settingsController.saveWindowOffset(appWindow.position); + windowManager.getPosition() + .then((value) => _settingsController.saveWindowOffset(value)); super.onWindowMoved(); } @override Widget build(BuildContext context) { super.build(context); - return Stack( - children: [ - LayoutBuilder( - builder: (context, specs) => Obx(() => NavigationView( - paneBodyBuilder: (pane, body) => Padding( - padding: const EdgeInsets.all(_kDefaultPadding), - child: body + return Stack(children: [ + LayoutBuilder( + builder: (context, specs) => Obx(() => NavigationPaneTheme( + data: NavigationPaneThemeData( + backgroundColor: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.9), ), - appBar: NavigationAppBar( - title: _draggableArea, - actions: WindowTitleBar(focused: _focused()), - automaticallyImplyLeading: false, - leading: _backButton - ), - pane: NavigationPane( - key: appKey, - selected: _selectedIndex, - onChanged: _onIndexChanged, - displayMode: specs.biggest.width <= 1536 ? PaneDisplayMode.compact : PaneDisplayMode.open, - items: _items, - footerItems: _footerItems, - autoSuggestBox: _autoSuggestBox, - autoSuggestBoxReplacement: const Icon(FluentIcons.search), - ), - onOpenSearch: () => _searchFocusNode.requestFocus(), - transitionBuilder: (child, animation) => child - )) - ), - if(isWin11) - Obx(() => _focused.value ? const WindowBorder() : const SizedBox()) - ] - ); + child: NavigationView( + paneBodyBuilder: (pane, body) => Padding( + padding: const EdgeInsets.all(_kDefaultPadding), + child: body + ), + appBar: NavigationAppBar( + height: 32, + title: _draggableArea, + actions: WindowTitleBar(focused: _focused()), + automaticallyImplyLeading: false, + leading: _backButton + ), + pane: NavigationPane( + key: appKey, + selected: _selectedIndex, + onChanged: _onIndexChanged, + menuButton: const SizedBox(), + displayMode: PaneDisplayMode.open, + items: _items, + header: ProfileWidget(), + footerItems: _footerItems, + autoSuggestBox: _autoSuggestBox, + autoSuggestBoxReplacement: const Icon(FluentIcons.search), + ), + contentShape: const RoundedRectangleBorder(), + onOpenSearch: () => _searchFocusNode.requestFocus(), + transitionBuilder: (child, animation) => child), + ) + ) + ), + if (isWin11) + Obx(() => _focused.value ? const WindowBorder() : const SizedBox()) + ]); } + GestureDetector get _draggableArea => GestureDetector( + onDoubleTap: () async => await windowManager.isMaximized() ? await windowManager.restore() : await windowManager.maximize(), + onHorizontalDragStart: (event) => windowManager.startDragging(), + onVerticalDragStart: (event) => windowManager.startDragging() + ); + Widget get _backButton => Obx(() { - for(var entry in _navigationStatus){ + for (var entry in _navigationStatus) { entry.value; } var onBack = _onBack(); - return PaneItem( - enabled: onBack != null, - icon: const Icon(FluentIcons.back, size: 14.0), - body: const SizedBox.shrink(), - ).build( - context, - false, - onBack, - displayMode: PaneDisplayMode.compact + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Button( + onPressed: onBack, + style: ButtonStyle( + backgroundColor: ButtonState.all(Colors.transparent), + border: ButtonState.all(BorderSide(color: Colors.transparent)) + ), + child: const Icon(FluentIcons.back, size: 13.0) + ) ); }); Function()? _onBack() { var navigator = _navigators[_settingsController.index.value].currentState; - if(navigator == null || !navigator.mounted || !navigator.canPop()){ + if (navigator == null || !navigator.mounted || !navigator.canPop()) { return null; } var status = _navigationStatus[_settingsController.index.value]; - if(status.value <= 0){ + if (status.value <= 0) { return null; } @@ -165,17 +180,15 @@ class _HomePageState extends State with WindowListener, AutomaticKeepA _settingsController.index.value = index; } - TextBox get _autoSuggestBox => TextBox( - key: _searchKey, - controller: _searchController, - placeholder: 'Search', - focusNode: _searchFocusNode - ); - - GestureDetector get _draggableArea => GestureDetector( - onDoubleTap: () => appWindow.maximizeOrRestore(), - onHorizontalDragStart: (event) => appWindow.startDragging(), - onVerticalDragStart: (event) => appWindow.startDragging() + Widget get _autoSuggestBox => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: TextBox( + key: _searchKey, + controller: _searchController, + placeholder: 'Find a setting', + focusNode: _searchFocusNode, + autofocus: true + ), ); int? get _selectedIndex { @@ -184,11 +197,12 @@ class _HomePageState extends State with WindowListener, AutomaticKeepA return _settingsController.index(); } - if(_settingsController.index() >= _allItems.length){ + if (_settingsController.index() >= _allItems.length) { return null; } - var indexOnScreen = searchItems.indexOf(_allItems[_settingsController.index()]); + var indexOnScreen = + searchItems.indexOf(_allItems[_settingsController.index()]); if (indexOnScreen.isNegative) { return null; } @@ -199,36 +213,75 @@ class _HomePageState extends State with WindowListener, AutomaticKeepA List get _allItems => [..._items, ..._footerItems]; List get _footerItems => searchValue.isNotEmpty ? [] : [ - PaneItem( - title: const Text("Settings"), - icon: const Icon(FluentIcons.settings), - body: SettingsPage() - ) + PaneItem( + title: const Text("Downloads"), + icon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: SizedBox.square( + dimension: 24, + child: Image.asset("assets/images/download.png") + ) + ), + body: const SettingsPage() + ), + PaneItem( + title: const Text("Settings"), + icon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: SizedBox.square( + dimension: 24, + child: Image.asset("assets/images/settings.png") + ) + ), + body: const SettingsPage() + ) ]; List get _items => _searchItems() ?? [ - PaneItem( - title: const Text("Tutorial"), - icon: const Icon(FluentIcons.info), - body: InfoPage(_navigators[0], _navigationStatus[0]) - ), PaneItem( title: const Text("Play"), - icon: const Icon(FluentIcons.game), - body: LauncherPage(_navigators[1], _navigationStatus[1]) + icon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: SizedBox.square( + dimension: 24, + child: Image.asset("assets/images/play.png") + ) + ), + body: LauncherPage(_navigators[0], _navigationStatus[0]) ), - PaneItem( title: const Text("Host"), - icon: const Icon(FluentIcons.server_processes), - body: HostingPage(_navigators[2], _navigationStatus[2]) + icon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: SizedBox.square( + dimension: 24, + child: Image.asset("assets/images/host.png") + ) + ), + body: HostingPage(_navigators[1], _navigationStatus[1]) ), - PaneItem( - title: const Text("Backend"), - icon: const Icon(FluentIcons.user_window), - body: ServerPage(_navigators[3], _navigationStatus[3]) + title: const Text("Authenticator"), + icon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: SizedBox.square( + dimension: 24, + child: Image.asset("assets/images/cloud.png") + ) + ), + body: ServerPage(_navigators[2], _navigationStatus[2]) ), + PaneItem( + title: const Text("Tutorial"), + icon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: SizedBox.square( + dimension: 24, + child: Image.asset("assets/images/info.png") + ) + ), + body: InfoPage(_navigators[3], _navigationStatus[3]) + ) ]; String get searchValue => _searchController.text; diff --git a/lib/src/ui/page/hosting_page.dart b/lib/src/ui/page/hosting_page.dart index d162942..5649032 100644 --- a/lib/src/ui/page/hosting_page.dart +++ b/lib/src/ui/page/hosting_page.dart @@ -3,10 +3,10 @@ import 'package:get/get.dart'; import 'package:reboot_launcher/src/ui/controller/hosting_controller.dart'; import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart'; -import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart'; import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart'; +import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart'; -import '../../model/update_status.dart'; +import 'package:reboot_launcher/src/model/update_status.dart'; import 'browse_page.dart'; class HostingPage extends StatefulWidget { @@ -38,7 +38,7 @@ class _HostingPageState extends State with AutomaticKeepAliveClient mainAxisAlignment: MainAxisAlignment.center, children: [ ProgressRing(), - SizedBox(height: 16.0), + SizedBox(height: 8.0), Text("Updating Reboot DLL...") ], ), @@ -97,7 +97,7 @@ class _HostPageState extends State<_HostPage> with AutomaticKeepAliveClientMixin child: _hostingController.updateStatus.value == UpdateStatus.error ? _updateError : _rebootGuiInfo, )), const SizedBox( - height: 16.0 + height: 8.0 ), SettingTile( title: "Game Server", @@ -135,7 +135,7 @@ class _HostPageState extends State<_HostPage> with AutomaticKeepAliveClientMixin ], ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Version", @@ -163,7 +163,7 @@ class _HostPageState extends State<_HostPage> with AutomaticKeepAliveClientMixin ] ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Browse available servers", diff --git a/lib/src/ui/page/info_page.dart b/lib/src/ui/page/info_page.dart index 2fad66c..3274a8f 100644 --- a/lib/src/ui/page/info_page.dart +++ b/lib/src/ui/page/info_page.dart @@ -1,20 +1,16 @@ import 'dart:async'; import 'package:fluent_ui/fluent_ui.dart'; -import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/ui/dialog/snackbar.dart'; import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart'; import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart'; import 'package:reboot_launcher/src/util/checks.dart'; -import 'package:reboot_launcher/src/util/server.dart'; -import '../../util/os.dart'; -import '../controller/game_controller.dart'; -import '../controller/settings_controller.dart'; -import '../dialog/dialog.dart'; -import '../dialog/dialog_button.dart'; -import '../widget/home/version_selector.dart'; +import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; +import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; +import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart'; class InfoPage extends StatefulWidget { final GlobalKey navigatorKey; @@ -219,7 +215,7 @@ class _PlayPageState extends State<_PlayPage> { ], ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: '2. Download Fortnite', @@ -255,7 +251,7 @@ class _PlayPageState extends State<_PlayPage> { ], ), const SizedBox( - height: 16.0, + height: 8.0, ), StreamBuilder( stream: _remoteGameServerStream.stream, diff --git a/lib/src/ui/page/launcher_page.dart b/lib/src/ui/page/launcher_page.dart index dddb996..1d84ecb 100644 --- a/lib/src/ui/page/launcher_page.dart +++ b/lib/src/ui/page/launcher_page.dart @@ -1,20 +1,8 @@ - - -import 'dart:async'; - import 'package:fluent_ui/fluent_ui.dart'; -import 'package:flutter/material.dart' show Icons; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; -import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; -import 'package:reboot_launcher/src/ui/dialog/snackbar.dart'; import 'package:reboot_launcher/src/ui/page/browse_page.dart'; -import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart'; -import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart'; -import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart'; +import 'package:reboot_launcher/src/ui/page/play_page.dart'; -import '../../util/checks.dart'; -import '../../util/os.dart'; class LauncherPage extends StatefulWidget { final GlobalKey navigatorKey; @@ -48,185 +36,11 @@ class _LauncherPageState extends State with AutomaticKeepAliveClie Widget _createScreen(String? name) { switch(name){ case "home": - return _GamePage(widget.navigatorKey, widget.nestedNavigation); + return PlayPage(widget.navigatorKey, widget.nestedNavigation); case "browse": return const BrowsePage(); default: throw Exception("Unknown page: $name"); } } -} - -class _GamePage extends StatefulWidget { - final GlobalKey navigatorKey; - final RxInt nestedNavigation; - const _GamePage(this.navigatorKey, this.nestedNavigation, {Key? key}) : super(key: key); - - @override - State<_GamePage> createState() => _GamePageState(); -} - -class _GamePageState extends State<_GamePage> { - final GameController _gameController = Get.find(); - final SettingsController _settingsController = Get.find(); - late final RxBool _showPasswordTrailing = RxBool(_gameController.password.text.isNotEmpty); - final StreamController _matchmakingStream = StreamController(); - - @override - void initState() { - _gameController.password.addListener(() => _matchmakingStream.add(null)); - _settingsController.matchmakingIp.addListener(() => _matchmakingStream.add(null)); - super.initState(); - } - - @override - Widget build(BuildContext context) => Column( - children: [ - Expanded( - child: ListView( - children: [ - SettingTile( - title: "Credentials", - subtitle: "Your in-game login credentials", - expandedContentSpacing: 0, - expandedContent: [ - SettingTile( - title: "Username", - subtitle: "The username that other players will see when you are in game", - isChild: true, - content: TextFormBox( - placeholder: "Username", - controller: _gameController.username, - autovalidateMode: AutovalidateMode.always - ), - ), - SettingTile( - title: "Password", - subtitle: "The password of your account, only used if the backend requires it", - isChild: true, - content: Obx(() => TextFormBox( - placeholder: "Password", - controller: _gameController.password, - autovalidateMode: AutovalidateMode.always, - obscureText: !_gameController.showPassword.value, - enableSuggestions: false, - autocorrect: false, - onChanged: (text) => _showPasswordTrailing.value = text.isNotEmpty, - suffix: Button( - onPressed: () => _gameController.showPassword.value = !_gameController.showPassword.value, - style: ButtonStyle( - shape: ButtonState.all(const CircleBorder()), - backgroundColor: ButtonState.all(Colors.transparent) - ), - child: Icon( - _gameController.showPassword.value ? Icons.visibility_off : Icons.visibility, - color: _showPasswordTrailing.value ? null : Colors.transparent - ), - ) - )) - ) - ], - ), - const SizedBox( - height: 16.0, - ), - StreamBuilder( - stream: _matchmakingStream.stream, - builder: (context, value) => - SettingTile( - title: "Matchmaking host", - subtitle: "Enter the IP address of the game server hosting the match", - content: TextFormBox( - placeholder: "IP:PORT", - controller: _settingsController.matchmakingIp, - validator: checkMatchmaking, - autovalidateMode: AutovalidateMode.always - ), - expandedContent: [ - SettingTile( - title: "Automatically start game server", - subtitle: "This option is available when the matchmaker is set to localhost", - contentWidth: null, - content: !isLocalHost(_settingsController.matchmakingIp.text) || _gameController.password.text.isNotEmpty ? _disabledAutoGameServerSwitch : _autoGameServerSwitch, - isChild: true - ), - SettingTile( - title: "Browse available servers", - subtitle: "Discover new game servers that fit your play-style", - content: Button( - onPressed: () { - widget.navigatorKey.currentState?.pushNamed('browse'); - widget.nestedNavigation.value += 1; - }, - child: const Text("Browse") - ), - isChild: true - ) - ] - ) - ), - const SizedBox( - height: 16.0, - ), - SettingTile( - title: "Version", - subtitle: "Select the version of Fortnite you want to play", - content: const VersionSelector(), - expandedContent: [ - SettingTile( - title: "Add a version from this PC's local storage", - subtitle: "Versions coming from your local disk are not guaranteed to work", - content: Button( - onPressed: () => VersionSelector.openAddDialog(context), - child: const Text("Add build"), - ), - isChild: true - ), - SettingTile( - title: "Download any version from the cloud", - subtitle: "A curated list of supported versions by Project Reboot", - content: Button( - onPressed: () => VersionSelector.openDownloadDialog(context), - child: const Text("Download"), - ), - isChild: true - ) - ] - ) - ], - ), - ), - const SizedBox( - height: 8.0, - ), - const LaunchButton( - host: false - ) - ], - ); - - Widget get _disabledAutoGameServerSwitch => Container( - foregroundDecoration: const BoxDecoration( - color: Colors.grey, - backgroundBlendMode: BlendMode.saturation, - ), - child: _autoGameServerSwitch, - ); - - Widget get _autoGameServerSwitch => Obx(() => ToggleSwitch( - checked: _gameController.autoStartGameServer() && isLocalHost(_settingsController.matchmakingIp.text) && _gameController.password.text.isEmpty, - onChanged: (value) { - if(!isLocalHost(_settingsController.matchmakingIp.text)){ - showMessage("This option isn't available when the matchmaker isn't set to 127.0.0.1"); - return; - } - - if(_gameController.password.text.isNotEmpty){ - showMessage("This option isn't available when the password isn't empty(LawinV2)"); - return; - } - - _gameController.autoStartGameServer.value = value; - } - )); } \ No newline at end of file diff --git a/lib/src/ui/page/play_page.dart b/lib/src/ui/page/play_page.dart new file mode 100644 index 0000000..29af481 --- /dev/null +++ b/lib/src/ui/page/play_page.dart @@ -0,0 +1,154 @@ +import 'dart:async'; + +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:get/get.dart'; +import 'package:get/get_rx/src/rx_types/rx_types.dart'; + +import 'package:reboot_launcher/src/util/checks.dart'; +import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; +import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; +import 'package:reboot_launcher/src/ui/dialog/snackbar.dart'; +import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart'; +import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart'; +import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart'; + +class PlayPage extends StatefulWidget { + final GlobalKey navigatorKey; + final RxInt nestedNavigation; + const PlayPage(this.navigatorKey, this.nestedNavigation, {Key? key}) : super(key: key); + + @override + State createState() => _PlayPageState(); +} + +class _PlayPageState extends State { + final GameController _gameController = Get.find(); + final SettingsController _settingsController = Get.find(); + final StreamController _matchmakingStream = StreamController(); + + @override + void initState() { + _gameController.password.addListener(() => _matchmakingStream.add(null)); + _settingsController.matchmakingIp.addListener(() => + _matchmakingStream.add(null)); + super.initState(); + } + + @override + Widget build(BuildContext context) => Column( + children: [ + Expanded( + child: ListView( + children: [ + SettingTile( + title: "Version", + subtitle: "Select the version of Fortnite you want to play", + content: const VersionSelector(), + expandedContent: [ + SettingTile( + title: "Add a version from this PC's local storage", + subtitle: "Versions coming from your local disk are not guaranteed to work", + content: Button( + onPressed: () => + VersionSelector.openAddDialog(context), + child: const Text("Add build"), + ), + isChild: true + ), + SettingTile( + title: "Download any version from the cloud", + subtitle: "A curated list of supported versions by Project Reboot", + content: Button( + onPressed: () => + VersionSelector.openDownloadDialog(context), + child: const Text("Download"), + ), + isChild: true + ) + ] + ), + const SizedBox( + height: 8.0, + ), + StreamBuilder( + stream: _matchmakingStream.stream, + builder: (context, value) => + SettingTile( + title: "Matchmaking host", + subtitle: "Enter the IP address of the game server hosting the match", + content: TextFormBox( + placeholder: "IP:PORT", + controller: _settingsController.matchmakingIp, + validator: checkMatchmaking, + autovalidateMode: AutovalidateMode.always + ), + expandedContent: [ + SettingTile( + title: "Automatically start game server", + subtitle: "This option is available when the matchmaker is set to localhost", + contentWidth: null, + content: !isLocalHost( + _settingsController.matchmakingIp.text) || + _gameController.password.text.isNotEmpty + ? _disabledAutoGameServerSwitch + : _autoGameServerSwitch, + isChild: true + ), + SettingTile( + title: "Browse available servers", + subtitle: "Discover new game servers that fit your play-style", + content: Button( + onPressed: () { + widget.navigatorKey.currentState + ?.pushNamed('browse'); + widget.nestedNavigation.value += 1; + }, + child: const Text("Browse") + ), + isChild: true + ) + ] + ) + ), + ], + ), + ), + const SizedBox( + height: 8.0, + ), + const LaunchButton( + host: false + ) + ], + ); + + Widget get _disabledAutoGameServerSwitch => Container( + foregroundDecoration: const BoxDecoration( + color: Colors.grey, + backgroundBlendMode: BlendMode.saturation, + ), + child: _autoGameServerSwitch, + ); + + Widget get _autoGameServerSwitch => Obx(() => ToggleSwitch( + checked: _gameController.autoStartGameServer() && + isLocalHost(_settingsController.matchmakingIp.text) && + _gameController.password.text.isEmpty, + onChanged: (value) { + if (!isLocalHost(_settingsController.matchmakingIp.text)) { + showMessage( + "This option isn't available when the matchmaker isn't set to 127.0.0.1"); + return; + } + + if (_gameController.password.text.isNotEmpty) { + showMessage( + "This option isn't available when the password isn't empty(LawinV2)"); + return; + } + + _gameController.autoStartGameServer.value = value; + } + )); +} \ No newline at end of file diff --git a/lib/src/ui/page/server_page.dart b/lib/src/ui/page/server_page.dart index ece1285..d481271 100644 --- a/lib/src/ui/page/server_page.dart +++ b/lib/src/ui/page/server_page.dart @@ -1,15 +1,15 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/model/server_type.dart'; -import 'package:reboot_launcher/src/util/server.dart'; import 'package:reboot_launcher/src/ui/controller/server_controller.dart'; -import 'package:reboot_launcher/src/ui/widget/server/server_type_selector.dart'; import 'package:reboot_launcher/src/ui/widget/server/server_button.dart'; +import 'package:reboot_launcher/src/ui/widget/server/server_type_selector.dart'; +import 'package:reboot_launcher/src/util/server.dart'; import 'package:url_launcher/url_launcher.dart'; -import '../dialog/dialog.dart'; -import '../dialog/dialog_button.dart'; -import '../widget/home/setting_tile.dart'; +import 'package:reboot_launcher/src/ui/dialog/dialog.dart'; +import 'package:reboot_launcher/src/ui/dialog/dialog_button.dart'; +import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart'; class ServerPage extends StatefulWidget { final GlobalKey navigatorKey; @@ -43,7 +43,7 @@ class _ServerPageState extends State with AutomaticKeepAliveClientMi ), ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Host", @@ -55,7 +55,7 @@ class _ServerPageState extends State with AutomaticKeepAliveClientMi ) ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Port", @@ -67,7 +67,7 @@ class _ServerPageState extends State with AutomaticKeepAliveClientMi ) ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Type", @@ -75,7 +75,7 @@ class _ServerPageState extends State with AutomaticKeepAliveClientMi content: ServerTypeSelector() ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Detached", @@ -87,7 +87,7 @@ class _ServerPageState extends State with AutomaticKeepAliveClientMi )) ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Server files", @@ -98,7 +98,7 @@ class _ServerPageState extends State with AutomaticKeepAliveClientMi ) ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Reset Backend", diff --git a/lib/src/ui/page/settings_page.dart b/lib/src/ui/page/settings_page.dart index 10a3b20..d4fee61 100644 --- a/lib/src/ui/page/settings_page.dart +++ b/lib/src/ui/page/settings_page.dart @@ -1,5 +1,4 @@ import 'package:fluent_ui/fluent_ui.dart'; -import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; @@ -7,12 +6,10 @@ import 'package:reboot_launcher/src/ui/dialog/dialog_button.dart'; import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart'; import 'package:url_launcher/url_launcher.dart'; - -import '../../util/checks.dart'; -import '../../util/os.dart'; -import '../../util/selector.dart'; -import '../dialog/dialog.dart'; -import '../widget/home/setting_tile.dart'; +import 'package:reboot_launcher/src/util/checks.dart'; +import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/ui/dialog/dialog.dart'; +import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart'; class SettingsPage extends StatefulWidget { const SettingsPage({Key? key}) : super(key: key); @@ -56,7 +53,7 @@ class _SettingsPageState extends State with AutomaticKeepAliveClie ], ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Automatic updates", @@ -82,7 +79,7 @@ class _SettingsPageState extends State with AutomaticKeepAliveClie ] ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Custom launch arguments", @@ -93,7 +90,7 @@ class _SettingsPageState extends State with AutomaticKeepAliveClie ) ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Create a bug report", @@ -104,7 +101,7 @@ class _SettingsPageState extends State with AutomaticKeepAliveClie ) ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Reset settings", @@ -134,7 +131,7 @@ class _SettingsPageState extends State with AutomaticKeepAliveClie ) ), const SizedBox( - height: 16.0, + height: 8.0, ), SettingTile( title: "Version status", diff --git a/lib/src/ui/widget/home/build_selector.dart b/lib/src/ui/widget/home/build_selector.dart index 4bf8038..45d9f9f 100644 --- a/lib/src/ui/widget/home/build_selector.dart +++ b/lib/src/ui/widget/home/build_selector.dart @@ -1,7 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/ui/controller/build_controller.dart'; import 'package:reboot_launcher/src/model/fortnite_build.dart'; +import 'package:reboot_launcher/src/ui/controller/build_controller.dart'; class BuildSelector extends StatefulWidget { final Function() onSelected; diff --git a/lib/src/ui/widget/home/launch_button.dart b/lib/src/ui/widget/home/launch_button.dart index 75c3552..cb60ebc 100644 --- a/lib/src/ui/widget/home/launch_button.dart +++ b/lib/src/ui/widget/home/launch_button.dart @@ -1,32 +1,29 @@ import 'dart:async'; -import 'dart:collection'; import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; +import 'package:path/path.dart' as path; import 'package:process_run/shell.dart'; +import 'package:reboot_launcher/src/../main.dart'; +import 'package:reboot_launcher/src/model/fortnite_version.dart'; +import 'package:reboot_launcher/src/model/game_instance.dart'; +import 'package:reboot_launcher/src/model/server_type.dart'; import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; import 'package:reboot_launcher/src/ui/controller/hosting_controller.dart'; import 'package:reboot_launcher/src/ui/controller/server_controller.dart'; +import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; import 'package:reboot_launcher/src/ui/dialog/dialog.dart'; import 'package:reboot_launcher/src/ui/dialog/game_dialogs.dart'; import 'package:reboot_launcher/src/ui/dialog/server_dialogs.dart'; -import 'package:reboot_launcher/src/model/fortnite_version.dart'; -import 'package:reboot_launcher/src/model/server_type.dart'; -import 'package:reboot_launcher/src/util/os.dart'; -import 'package:reboot_launcher/src/util/injector.dart'; -import 'package:reboot_launcher/src/util/patcher.dart'; -import 'package:reboot_launcher/src/util/server.dart'; -import 'package:path/path.dart' as path; - -import 'package:reboot_launcher/src/../main.dart'; -import 'package:reboot_launcher/src/ui/controller/settings_controller.dart'; import 'package:reboot_launcher/src/ui/dialog/snackbar.dart'; -import 'package:reboot_launcher/src/model/game_instance.dart'; +import 'package:reboot_launcher/src/util/injector.dart'; +import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/util/server.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; -import '../../../util/process.dart'; +import 'package:reboot_launcher/src/util/process.dart'; class LaunchButton extends StatefulWidget { final bool host; @@ -124,7 +121,8 @@ class _LaunchButtonState extends State { try { var version = _gameController.selectedVersion!; - if(version.executable?.path == null){ + var executable = await version.executable; + if(executable == null){ showMissingBuildError(version); _onStop(widget.host); return; @@ -136,9 +134,6 @@ class _LaunchButtonState extends State { return; } - await compute(patchHeadless, version.executable!); - // Is this needed? await compute(patchMatchmaking, version.executable!); - var automaticallyStartedServer = await _startMatchMakingServer(); await _startGameProcesses(version, widget.host, automaticallyStartedServer); @@ -156,7 +151,14 @@ class _LaunchButtonState extends State { _setStarted(host, true); var launcherProcess = await _createLauncherProcess(version); var eacProcess = await _createEacProcess(version); - var gameProcess = await _createGameProcess(version.executable!.path, host); + var executable = await version.executable; + if(executable == null){ + showMissingBuildError(version); + _onStop(widget.host); + return; + } + + var gameProcess = await _createGameProcess(executable.path, host); var watchDogProcess = _createWatchdogProcess(gameProcess, launcherProcess, eacProcess); var instance = GameInstance(gameProcess, launcherProcess, eacProcess, watchDogProcess, hasChildServer); if(host){ diff --git a/lib/src/ui/widget/home/setting_tile.dart b/lib/src/ui/widget/home/setting_tile.dart index 28381f4..26ccca8 100644 --- a/lib/src/ui/widget/home/setting_tile.dart +++ b/lib/src/ui/widget/home/setting_tile.dart @@ -1,5 +1,4 @@ import 'package:fluent_ui/fluent_ui.dart'; -import 'package:reboot_launcher/src/ui/widget/shared/fluent_card.dart'; class SettingTile extends StatefulWidget { static const double kDefaultContentWidth = 200.0; @@ -42,19 +41,17 @@ class _SettingTileState extends State { return _contentCard; } - return Mica( - elevation: 1, - child: Expander( - initiallyExpanded: true, - contentBackgroundColor: FluentTheme.of(context).menuColor, - headerShape: (open) => const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(4.0)), - ), - header: _header, - headerHeight: widget.expandedContentHeaderHeight, - trailing: _trailing, - content: _content - ), + return Expander( + initiallyExpanded: true, + headerShape: (open) => const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(4.0)), + ), + header: SizedBox( + height: widget.expandedContentHeaderHeight, + child: _header + ), + trailing: _trailing, + content: _content ); } @@ -90,8 +87,9 @@ class _SettingTileState extends State { ); } - return FluentCard( - child: _contentCardBody, + return Card( + borderRadius: const BorderRadius.vertical(top: Radius.circular(4.0)), + child: _contentCardBody ); } diff --git a/lib/src/ui/widget/home/version_selector.dart b/lib/src/ui/widget/home/version_selector.dart index 2b07282..cdb634e 100644 --- a/lib/src/ui/widget/home/version_selector.dart +++ b/lib/src/ui/widget/home/version_selector.dart @@ -4,18 +4,18 @@ import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/gestures.dart'; import 'package:get/get.dart'; +import 'package:reboot_launcher/src/model/fortnite_version.dart'; import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; +import 'package:reboot_launcher/src/ui/dialog/add_local_version.dart'; +import 'package:reboot_launcher/src/ui/dialog/add_server_version.dart'; import 'package:reboot_launcher/src/ui/dialog/dialog.dart'; import 'package:reboot_launcher/src/ui/dialog/dialog_button.dart'; -import 'package:reboot_launcher/src/model/fortnite_version.dart'; -import 'package:reboot_launcher/src/ui/dialog/add_local_version.dart'; import 'package:reboot_launcher/src/ui/widget/shared/smart_check_box.dart'; +import 'package:reboot_launcher/src/util/checks.dart'; import 'package:reboot_launcher/src/util/os.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:reboot_launcher/src/ui/dialog/add_server_version.dart'; -import 'package:reboot_launcher/src/util/checks.dart'; -import '../shared/file_selector.dart'; +import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart'; class VersionSelector extends StatefulWidget { const VersionSelector({Key? key}) : super(key: key); diff --git a/dependencies/bitsdojo_window-0.1.5/lib/src/icons/icons.dart b/lib/src/ui/widget/os/icons.dart similarity index 86% rename from dependencies/bitsdojo_window-0.1.5/lib/src/icons/icons.dart rename to lib/src/ui/widget/os/icons.dart index c0b00eb..68ece22 100644 --- a/dependencies/bitsdojo_window-0.1.5/lib/src/icons/icons.dart +++ b/lib/src/ui/widget/os/icons.dart @@ -7,7 +7,9 @@ import 'package:flutter/widgets.dart'; /// Close class CloseIcon extends StatelessWidget { final Color color; - CloseIcon({Key? key, required this.color}) : super(key: key); + + const CloseIcon({Key? key, required this.color}) : super(key: key); + @override Widget build(BuildContext context) => Align( alignment: Alignment.topLeft, @@ -28,13 +30,16 @@ class CloseIcon extends StatelessWidget { /// Maximize class MaximizeIcon extends StatelessWidget { final Color color; - MaximizeIcon({Key? key, required this.color}) : super(key: key); + + const MaximizeIcon({Key? key, required this.color}) : super(key: key); + @override Widget build(BuildContext context) => _AlignedPaint(_MaximizePainter(color)); } class _MaximizePainter extends _IconPainter { _MaximizePainter(Color color) : super(color); + @override void paint(Canvas canvas, Size size) { Paint p = getPaint(color); @@ -45,22 +50,25 @@ class _MaximizePainter extends _IconPainter { /// Restore class RestoreIcon extends StatelessWidget { final Color color; - RestoreIcon({ + + const RestoreIcon({ Key? key, required this.color, }) : super(key: key); + @override Widget build(BuildContext context) => _AlignedPaint(_RestorePainter(color)); } class _RestorePainter extends _IconPainter { _RestorePainter(Color color) : super(color); + @override void paint(Canvas canvas, Size size) { Paint p = getPaint(color); canvas.drawRect(Rect.fromLTRB(0, 2, size.width - 2, size.height), p); - canvas.drawLine(Offset(2, 2), Offset(2, 0), p); - canvas.drawLine(Offset(2, 0), Offset(size.width, 0), p); + canvas.drawLine(const Offset(2, 2), const Offset(2, 0), p); + canvas.drawLine(const Offset(2, 0), Offset(size.width, 0), p); canvas.drawLine( Offset(size.width, 0), Offset(size.width, size.height - 2), p); canvas.drawLine(Offset(size.width, size.height - 2), @@ -71,13 +79,16 @@ class _RestorePainter extends _IconPainter { /// Minimize class MinimizeIcon extends StatelessWidget { final Color color; - MinimizeIcon({Key? key, required this.color}) : super(key: key); + + const MinimizeIcon({Key? key, required this.color}) : super(key: key); + @override Widget build(BuildContext context) => _AlignedPaint(_MinimizePainter(color)); } class _MinimizePainter extends _IconPainter { _MinimizePainter(Color color) : super(color); + @override void paint(Canvas canvas, Size size) { Paint p = getPaint(color); @@ -89,6 +100,7 @@ class _MinimizePainter extends _IconPainter { /// Helpers abstract class _IconPainter extends CustomPainter { _IconPainter(this.color); + final Color color; @override @@ -103,7 +115,7 @@ class _AlignedPaint extends StatelessWidget { Widget build(BuildContext context) { return Align( alignment: Alignment.center, - child: CustomPaint(size: Size(10, 10), painter: painter)); + child: CustomPaint(size: const Size(10, 10), painter: painter)); } } diff --git a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/mouse_state_builder.dart b/lib/src/ui/widget/os/mouse_state_builder.dart similarity index 82% rename from dependencies/bitsdojo_window-0.1.5/lib/src/widgets/mouse_state_builder.dart rename to lib/src/ui/widget/os/mouse_state_builder.dart index 3266758..395951e 100644 --- a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/mouse_state_builder.dart +++ b/lib/src/ui/widget/os/mouse_state_builder.dart @@ -6,26 +6,29 @@ typedef MouseStateBuilderCB = Widget Function( class MouseState { bool isMouseOver = false; bool isMouseDown = false; + MouseState(); + @override String toString() { - return "isMouseDown: ${this.isMouseDown} - isMouseOver: ${this.isMouseOver}"; + return "isMouseDown: $isMouseDown - isMouseOver: $isMouseOver"; } } -T? _ambiguate(T? value) => value; - class MouseStateBuilder extends StatefulWidget { final MouseStateBuilderCB builder; final VoidCallback? onPressed; - MouseStateBuilder({Key? key, required this.builder, this.onPressed}) + + const MouseStateBuilder({Key? key, required this.builder, this.onPressed}) : super(key: key); + @override - _MouseStateBuilderState createState() => _MouseStateBuilderState(); + State createState() => _MouseStateBuilderState(); } class _MouseStateBuilderState extends State { late MouseState _mouseState; + _MouseStateBuilderState() { _mouseState = MouseState(); } @@ -59,7 +62,7 @@ class _MouseStateBuilderState extends State { _mouseState.isMouseDown = false; _mouseState.isMouseOver = false; }); - _ambiguate(WidgetsBinding.instance)!.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { if (widget.onPressed != null) { widget.onPressed!(); } diff --git a/lib/src/ui/widget/os/window_border.dart b/lib/src/ui/widget/os/window_border.dart index 2fdcbc2..ae90b8b 100644 --- a/lib/src/ui/widget/os/window_border.dart +++ b/lib/src/ui/widget/os/window_border.dart @@ -1,4 +1,3 @@ -import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:flutter/material.dart'; import 'package:reboot_launcher/src/util/os.dart'; import 'package:system_theme/system_theme.dart'; @@ -10,18 +9,19 @@ class WindowBorder extends StatelessWidget { Widget build(BuildContext context) { return IgnorePointer( child: Padding( - padding: EdgeInsets.only( - top: 1 / appWindow.scaleFactor + padding: const EdgeInsets.only( + top: 1 ), child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: SystemTheme.accentColor.accent, - width: appBarSize.toDouble() + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: SystemTheme.accentColor.accent, + width: appBarSize.toDouble() + ) ) - ) ), - )); + ) + ); } } diff --git a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_button.dart b/lib/src/ui/widget/os/window_button.dart similarity index 61% rename from dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_button.dart rename to lib/src/ui/widget/os/window_button.dart index 607c4b9..cfa2b12 100644 --- a/dependencies/bitsdojo_window-0.1.5/lib/src/widgets/window_button.dart +++ b/lib/src/ui/widget/os/window_button.dart @@ -1,10 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:window_manager/window_manager.dart'; -import './mouse_state_builder.dart'; -import '../icons/icons.dart'; -import '../app_window.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; -import 'dart:io' show Platform; +import 'icons.dart'; +import 'mouse_state_builder.dart'; typedef WindowButtonIconBuilder = Widget Function( WindowButtonContext buttonContext); @@ -16,6 +14,7 @@ class WindowButtonContext { MouseState mouseState; Color? backgroundColor; Color iconColor; + WindowButtonContext( {required this.context, required this.mouseState, @@ -30,6 +29,7 @@ class WindowButtonColors { late Color iconNormal; late Color iconMouseOver; late Color iconMouseDown; + WindowButtonColors( {Color? normal, Color? mouseOver, @@ -48,11 +48,11 @@ class WindowButtonColors { final _defaultButtonColors = WindowButtonColors( normal: Colors.transparent, - iconNormal: Color(0xFF805306), - mouseOver: Color(0xFF404040), - mouseDown: Color(0xFF202020), - iconMouseOver: Color(0xFFFFFFFF), - iconMouseDown: Color(0xFFF0F0F0)); + iconNormal: const Color(0xFF805306), + mouseOver: const Color(0xFF404040), + mouseDown: const Color(0xFF202020), + iconMouseOver: const Color(0xFFFFFFFF), + iconMouseDown: const Color(0xFFF0F0F0)); class WindowButton extends StatelessWidget { final WindowButtonBuilder? builder; @@ -88,51 +88,35 @@ class WindowButton extends StatelessWidget { @override Widget build(BuildContext context) { - if (kIsWeb) { - return Container(); - } else { - // Don't show button on macOS - if (Platform.isMacOS) { - return Container(); - } - } - final buttonSize = appWindow.titleBarButtonSize; return MouseStateBuilder( - builder: (context, mouseState) { - WindowButtonContext buttonContext = WindowButtonContext( - mouseState: mouseState, - context: context, - backgroundColor: getBackgroundColor(mouseState), - iconColor: getIconColor(mouseState)); + builder: (context, mouseState) { + WindowButtonContext buttonContext = WindowButtonContext( + mouseState: mouseState, + context: context, + backgroundColor: getBackgroundColor(mouseState), + iconColor: getIconColor(mouseState)); - var icon = (this.iconBuilder != null) - ? this.iconBuilder!(buttonContext) - : Container(); - double borderSize = appWindow.borderSize; - double defaultPadding = - (appWindow.titleBarHeight - borderSize) / 3 - (borderSize / 2); - // Used when buttonContext.backgroundColor is null, allowing the AnimatedContainer to fade-out smoothly. - var fadeOutColor = - getBackgroundColor(MouseState()..isMouseOver = true).withOpacity(0); - var padding = this.padding ?? EdgeInsets.zero; - var animationMs = - mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0); - Widget iconWithPadding = Padding(padding: padding, child: icon); - iconWithPadding = AnimatedContainer( - curve: Curves.easeOut, - duration: Duration(milliseconds: animationMs), - color: buttonContext.backgroundColor ?? fadeOutColor, - child: iconWithPadding); - var button = (this.builder != null) - ? this.builder!(buttonContext, icon) - : iconWithPadding; - return SizedBox( - width: 48, height: 48, child: button); - }, - onPressed: () { - if (this.onPressed != null) this.onPressed!(); - }, - ); + var icon = + (iconBuilder != null) ? iconBuilder!(buttonContext) : Container(); + var fadeOutColor = + getBackgroundColor(MouseState()..isMouseOver = true) + .withOpacity(0); + var padding = this.padding ?? EdgeInsets.zero; + var animationMs = mouseState.isMouseOver + ? (animate ? 100 : 0) + : (animate ? 200 : 0); + Widget iconWithPadding = Padding(padding: padding, child: icon); + iconWithPadding = AnimatedContainer( + curve: Curves.easeOut, + duration: Duration(milliseconds: animationMs), + color: buttonContext.backgroundColor ?? fadeOutColor, + child: iconWithPadding); + var button = (builder != null) + ? builder!(buttonContext, icon) + : iconWithPadding; + return SizedBox.square(dimension: 45, child: button); + }, + onPressed: onPressed); } } @@ -148,7 +132,7 @@ class MinimizeWindowButton extends WindowButton { animate: animate ?? false, iconBuilder: (buttonContext) => MinimizeIcon(color: buttonContext.iconColor), - onPressed: onPressed ?? () => appWindow.minimize()); + onPressed: onPressed ?? () => windowManager.minimize()); } class MaximizeWindowButton extends WindowButton { @@ -163,7 +147,10 @@ class MaximizeWindowButton extends WindowButton { animate: animate ?? false, iconBuilder: (buttonContext) => MaximizeIcon(color: buttonContext.iconColor), - onPressed: onPressed ?? () => appWindow.maximizeOrRestore()); + onPressed: onPressed ?? + () async => await windowManager.isMaximized() + ? await windowManager.restore() + : await windowManager.maximize()); } class RestoreWindowButton extends WindowButton { @@ -178,14 +165,17 @@ class RestoreWindowButton extends WindowButton { animate: animate ?? false, iconBuilder: (buttonContext) => RestoreIcon(color: buttonContext.iconColor), - onPressed: onPressed ?? () => appWindow.maximizeOrRestore()); + onPressed: onPressed ?? + () async => await windowManager.isMaximized() + ? await windowManager.restore() + : await windowManager.maximize()); } final _defaultCloseButtonColors = WindowButtonColors( - mouseOver: Color(0xFFD32F2F), - mouseDown: Color(0xFFB71C1C), - iconNormal: Color(0xFF805306), - iconMouseOver: Color(0xFFFFFFFF)); + mouseOver: const Color(0xFFD32F2F), + mouseDown: const Color(0xFFB71C1C), + iconNormal: const Color(0xFF805306), + iconMouseOver: const Color(0xFFFFFFFF)); class CloseWindowButton extends WindowButton { CloseWindowButton( @@ -199,5 +189,5 @@ class CloseWindowButton extends WindowButton { animate: animate ?? false, iconBuilder: (buttonContext) => CloseIcon(color: buttonContext.iconColor), - onPressed: onPressed ?? () => appWindow.close()); + onPressed: onPressed ?? () => windowManager.close()); } diff --git a/lib/src/ui/widget/os/window_buttons.dart b/lib/src/ui/widget/os/window_title_bar.dart similarity index 96% rename from lib/src/ui/widget/os/window_buttons.dart rename to lib/src/ui/widget/os/window_title_bar.dart index 5dce903..156a455 100644 --- a/lib/src/ui/widget/os/window_buttons.dart +++ b/lib/src/ui/widget/os/window_title_bar.dart @@ -1,5 +1,5 @@ -import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:fluent_ui/fluent_ui.dart'; +import 'package:reboot_launcher/src/ui/widget/os/window_button.dart'; import 'package:reboot_launcher/src/util/os.dart'; import 'package:system_theme/system_theme.dart'; diff --git a/lib/src/ui/widget/server/server_button.dart b/lib/src/ui/widget/server/server_button.dart index 2f25a3a..92da23c 100644 --- a/lib/src/ui/widget/server/server_button.dart +++ b/lib/src/ui/widget/server/server_button.dart @@ -1,8 +1,8 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; +import 'package:reboot_launcher/src/model/server_type.dart'; import 'package:reboot_launcher/src/ui/controller/server_controller.dart'; import 'package:reboot_launcher/src/ui/dialog/server_dialogs.dart'; -import 'package:reboot_launcher/src/model/server_type.dart'; class ServerButton extends StatefulWidget { const ServerButton({Key? key}) : super(key: key); diff --git a/lib/src/ui/widget/server/server_type_selector.dart b/lib/src/ui/widget/server/server_type_selector.dart index db73d5e..4b536eb 100644 --- a/lib/src/ui/widget/server/server_type_selector.dart +++ b/lib/src/ui/widget/server/server_type_selector.dart @@ -1,7 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/ui/controller/server_controller.dart'; import 'package:reboot_launcher/src/model/server_type.dart'; +import 'package:reboot_launcher/src/ui/controller/server_controller.dart'; class ServerTypeSelector extends StatelessWidget { final ServerController _serverController = Get.find(); diff --git a/lib/src/ui/widget/shared/file_selector.dart b/lib/src/ui/widget/shared/file_selector.dart index a3eca52..2b3b601 100644 --- a/lib/src/ui/widget/shared/file_selector.dart +++ b/lib/src/ui/widget/shared/file_selector.dart @@ -1,11 +1,6 @@ -import 'dart:async'; - -import 'package:file_picker/file_picker.dart'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/foundation.dart'; -import 'package:get/get.dart'; import 'package:reboot_launcher/src/ui/dialog/snackbar.dart'; - import 'package:reboot_launcher/src/util/selector.dart'; class FileSelector extends StatefulWidget { diff --git a/lib/src/ui/widget/shared/fluent_card.dart b/lib/src/ui/widget/shared/fluent_card.dart deleted file mode 100644 index f49e766..0000000 --- a/lib/src/ui/widget/shared/fluent_card.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:fluent_ui/fluent_ui.dart'; - -class FluentCard extends StatelessWidget { - final Widget child; - const FluentCard({Key? key, required this.child}) : super(key: key); - - @override - Widget build(BuildContext context) => Mica( - elevation: 1, - child: Card( - backgroundColor: FluentTheme.of(context).menuColor, - borderRadius: const BorderRadius.vertical(top: Radius.circular(4.0)), - child: child - ) - ); -} diff --git a/lib/src/ui/widget/shared/profile_widget.dart b/lib/src/ui/widget/shared/profile_widget.dart new file mode 100644 index 0000000..77f9bd7 --- /dev/null +++ b/lib/src/ui/widget/shared/profile_widget.dart @@ -0,0 +1,56 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:get/get.dart'; + +import '../../controller/game_controller.dart'; + +class ProfileWidget extends StatelessWidget { + final GameController _gameController = Get.find(); + + ProfileWidget({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 12.0 + ), + child: GestureDetector( + child: Row( + children: [ + Container( + width: 64, + height: 64, + decoration: const BoxDecoration( + shape: BoxShape.circle + ), + child: Image.asset("assets/images/user.png") + ), + const SizedBox( + width: 12.0, + ), + const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Auties00", + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w600 + ), + ), + Text( + "alautiero@gmail.com", + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w100 + ), + ) + ], + ) + ], + ), + ), + ); + } +} diff --git a/lib/src/util/build.dart b/lib/src/util/build.dart index f654e10..097238e 100644 --- a/lib/src/util/build.dart +++ b/lib/src/util/build.dart @@ -2,13 +2,12 @@ import 'dart:async'; import 'dart:io'; import 'dart:isolate'; -import 'package:archive/archive_io.dart'; import 'package:html/parser.dart' show parse; import 'package:http/http.dart' as http; +import 'package:path/path.dart' as path; import 'package:reboot_launcher/src/model/fortnite_build.dart'; import 'package:reboot_launcher/src/util/time.dart'; import 'package:reboot_launcher/src/util/version.dart' as parser; -import 'package:path/path.dart' as path; import 'os.dart'; diff --git a/lib/src/util/checks.dart b/lib/src/util/checks.dart index b1de1ee..02d7259 100644 --- a/lib/src/util/checks.dart +++ b/lib/src/util/checks.dart @@ -1,9 +1,6 @@ -import 'dart:async'; import 'dart:io'; -import 'package:reboot_launcher/src/util/server.dart'; - -import '../model/fortnite_version.dart'; +import 'package:reboot_launcher/src/model/fortnite_version.dart'; String? checkVersion(String? text, List versions) { if (text == null || text.isEmpty) { diff --git a/lib/src/util/error.dart b/lib/src/util/error.dart index 377242c..e146f77 100644 --- a/lib/src/util/error.dart +++ b/lib/src/util/error.dart @@ -1,7 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; -import '../../../main.dart'; -import '../ui/dialog/dialog.dart'; +import 'package:reboot_launcher/main.dart'; +import 'package:reboot_launcher/src/ui/dialog/dialog.dart'; String? lastError; diff --git a/lib/src/util/injector.dart b/lib/src/util/injector.dart index f0cfa84..552e739 100644 --- a/lib/src/util/injector.dart +++ b/lib/src/util/injector.dart @@ -2,8 +2,8 @@ import 'dart:ffi'; -import 'package:win32/win32.dart'; import 'package:ffi/ffi.dart'; +import 'package:win32/win32.dart'; final _kernel32 = DynamicLibrary.open('kernel32.dll'); final _CreateRemoteThread = _kernel32.lookupFunction< diff --git a/lib/src/util/os.dart b/lib/src/util/os.dart index 30201b8..6945269 100644 --- a/lib/src/util/os.dart +++ b/lib/src/util/os.dart @@ -1,8 +1,8 @@ +import 'dart:ffi'; import 'dart:io'; -import 'package:win32/win32.dart'; import 'package:ffi/ffi.dart'; -import 'dart:ffi'; +import 'package:win32/win32.dart'; const int appBarSize = 2; diff --git a/lib/src/util/process.dart b/lib/src/util/process.dart index 4f8e246..59c7b93 100644 --- a/lib/src/util/process.dart +++ b/lib/src/util/process.dart @@ -1,6 +1,5 @@ import 'dart:ffi'; -import 'package:win32/src/kernel32.dart'; import 'package:win32/win32.dart'; final _ntdll = DynamicLibrary.open('ntdll.dll'); diff --git a/lib/src/util/server.dart b/lib/src/util/server.dart index 2ca1048..5d0e89c 100644 --- a/lib/src/util/server.dart +++ b/lib/src/util/server.dart @@ -2,15 +2,14 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; +import 'package:http/http.dart' as http; import 'package:ini/ini.dart'; import 'package:process_run/shell.dart'; import 'package:reboot_launcher/src/model/server_type.dart'; import 'package:reboot_launcher/src/ui/controller/game_controller.dart'; import 'package:reboot_launcher/src/util/os.dart'; -import 'package:shelf_proxy/shelf_proxy.dart'; import 'package:shelf/shelf_io.dart'; - -import 'package:http/http.dart' as http; +import 'package:shelf_proxy/shelf_proxy.dart'; final serverLogFile = File("${logsDirectory.path}\\server.log"); final serverDirectory = Directory("${assetsDirectory.path}\\lawin"); diff --git a/pubspec.yaml b/pubspec.yaml index 30c6511..ae24dfe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,9 +11,7 @@ dependencies: flutter: sdk: flutter - bitsdojo_window: - path: ./dependencies/bitsdojo_window-0.1.5 - fluent_ui: ^4.6.2 + fluent_ui: ^4.7.3 bitsdojo_window_windows: ^0.1.5 system_theme: ^2.0.0 http: ^0.13.5 @@ -43,6 +41,7 @@ dependencies: supabase_flutter: ^1.10.0 supabase: ^1.9.1 fluentui_system_icons: ^1.1.202 + flutter_acrylic: ^1.1.3 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index ae6c766..0418bb6 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("AppLinksPluginCApi")); BitsdojoWindowPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); + FlutterAcrylicPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterAcrylicPlugin")); ScreenRetrieverPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); SystemThemePluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b1095ae..65e1e6c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links bitsdojo_window_windows + flutter_acrylic screen_retriever system_theme url_launcher_windows diff --git a/windows/packaging/exe/custom-inno-setup-script.iss b/windows/packaging/exe/custom-inno-setup-script.iss new file mode 100644 index 0000000..a974572 --- /dev/null +++ b/windows/packaging/exe/custom-inno-setup-script.iss @@ -0,0 +1,36 @@ +[Setup] +AppId={{APP_ID}} +AppVersion={{APP_VERSION}} +AppName={{DISPLAY_NAME}} +AppPublisher={{PUBLISHER_NAME}} +AppPublisherURL={{PUBLISHER_URL}} +AppSupportURL={{PUBLISHER_URL}} +AppUpdatesURL={{PUBLISHER_URL}} +DefaultDirName={{INSTALL_DIR_NAME}} +DisableProgramGroupPage=yes +OutputBaseFilename={{OUTPUT_BASE_FILENAME}} +Compression=lzma +SolidCompression=yes +SetupIconFile={{SETUP_ICON_FILE}} +WizardStyle=modern +PrivilegesRequired=admin +ArchitecturesAllowed=x64 +ArchitecturesInstallIn64BitMode=x64 + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce +Name: "launchAtStartup"; Description: "{cm:AutoStartProgram,{{DISPLAY_NAME}}}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "reboot_launcher-8.1.0+8.1.0-windows-setup_exe\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs + +[Run] +Filename: "{app}\\{{EXECUTABLE_NAME}}"; Description: "{cm:LaunchProgram,{{DISPLAY_NAME}}}"; Flags: runascurrentuser nowait postinstall skipifsilent + +[Icons] +Name: "{autoprograms}\{{DISPLAY_NAME}}"; Filename: "{app}\{{EXECUTABLE_NAME}}" +Name: "{autodesktop}\{{DISPLAY_NAME}}"; Filename: "{app}\{{EXECUTABLE_NAME}}"; Tasks: desktopicon +Name: "{userstartup}\{{DISPLAY_NAME}}"; Filename: "{app}\{{EXECUTABLE_NAME}}"; WorkingDir: "{app}"; Tasks: launchAtStartup diff --git a/windows/packaging/exe/make_config.yaml b/windows/packaging/exe/make_config.yaml index 69687f3..7e38c5a 100644 --- a/windows/packaging/exe/make_config.yaml +++ b/windows/packaging/exe/make_config.yaml @@ -1,6 +1,9 @@ +script_template: "custom-inno-setup-script.iss" app_id: 31868Auties00.RebootLauncher publisher_name: Auties00 +publisher_url: https://github.com/Auties00 display_name: Reboot Launcher +install_dir_name: Reboot Launcher create_desktop_icon: true locales: - en \ No newline at end of file diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index 5c2ec15..d39742d 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -1,5 +1,5 @@ #include -auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP); +auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME); #include @@ -15,19 +15,20 @@ auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP); #include #include -bool CheckOneInstance() -{ - HANDLE m_hStartEvent = CreateEventW( NULL, FALSE, FALSE, L"reboot_launcher"); - if(m_hStartEvent == NULL) - { - CloseHandle( m_hStartEvent ); +bool CheckOneInstance(){ + HANDLE hMutex = CreateMutexW(NULL, TRUE, L"RebootLauncherMutex"); + if (hMutex == NULL) { return false; } - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - CloseHandle( m_hStartEvent ); - m_hStartEvent = NULL; + if (GetLastError() == ERROR_ALREADY_EXISTS) { + HWND hwndExisting = FindWindowW(NULL, L"Reboot Launcher"); + if (hwndExisting != NULL) { + ShowWindow(hwndExisting, SW_RESTORE); + SetForegroundWindow(hwndExisting); + } + + CloseHandle(hMutex); return false; } @@ -58,7 +59,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"reboot_launcher", origin, size)) { + if (!window.CreateAndShow(L"Reboot Launcher", origin, size)) { return EXIT_FAILURE; } diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp index c10f08d..47e2ff0 100644 --- a/windows/runner/win32_window.cpp +++ b/windows/runner/win32_window.cpp @@ -4,6 +4,8 @@ #include "resource.h" +#include + namespace { constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; @@ -108,7 +110,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, Destroy(); const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); + WindowClassRegistrar::GetInstance()->GetWindowClass(); const POINT target_point = {static_cast(origin.x), static_cast(origin.y)}; @@ -117,10 +119,18 @@ bool Win32Window::CreateAndShow(const std::wstring& title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); + window_class, + title.c_str(), + WS_OVERLAPPED & ~WS_VISIBLE, + Scale(origin.x, scale_factor), + Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), + Scale(size.height, scale_factor), + nullptr, + nullptr, + GetModuleHandle(nullptr), + this + ); if (!window) { return false;