From 4dfdec90554907d9ca40b666c8d8e68b6d0a9b07 Mon Sep 17 00:00:00 2001 From: tzdwindows 7 <3076584115@qq.com> Date: Sun, 1 Jun 2025 08:39:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(box):=20=E5=A2=9E=E5=BC=BA=E5=B4=A9?= =?UTF-8?q?=E6=BA=83=E6=8A=A5=E5=91=8A=E5=8A=9F=E8=83=BD=E5=B9=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=8D=95=E5=AE=9E=E4=BE=8B=E9=94=81-=20=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E8=AE=BE=E8=AE=A1=E5=B4=A9=E6=BA=83=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E4=BF=A1=E6=81=AF=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=8D=95=E5=AE=9E=E4=BE=8B=E9=94=81=E6=9C=BA=E5=88=B6=EF=BC=8C?= =?UTF-8?q?=E9=98=B2=E6=AD=A2=E5=A4=9A=E4=B8=AA=E5=AE=9E=E4=BE=8B=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E8=BF=90=E8=A1=8C=20-=20=E6=9B=B4=E6=96=B0UI=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=20-=20=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B=E5=B0=8F?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + language/saved_language.properties | 2 +- language/sys_zh_CN.properties | 7 +- library/DogAgent.dll | Bin 0 -> 39424 bytes libs/dog api 1.3.jar | Bin 0 -> 22889 bytes mapping.properties | 1 + .../innovators/box/AxisInnovatorsBox.java | 590 ++++++++++++++++-- .../java/com/axis/innovators/box/Main.java | 78 ++- .../axis/innovators/box/gui/MainWindow.java | 62 +- 9 files changed, 625 insertions(+), 116 deletions(-) create mode 100644 library/DogAgent.dll create mode 100644 libs/dog api 1.3.jar diff --git a/build.gradle b/build.gradle index ab148a7..c2cb0fd 100644 --- a/build.gradle +++ b/build.gradle @@ -72,6 +72,7 @@ dependencies { implementation 'org.graalvm.python:python-embedding:24.2.1' implementation files('libs/JNC-1.0-jnc.jar') + implementation files('libs/dog api 1.3.jar') implementation 'org.fxmisc.richtext:richtextfx:0.11.0' // 更新后的richtextfx implementation 'org.bitbucket.mstrobel:procyon-core:0.5.36' // 使用JitPack版本 diff --git a/language/saved_language.properties b/language/saved_language.properties index c155509..a8bcb83 100644 --- a/language/saved_language.properties +++ b/language/saved_language.properties @@ -1,3 +1,3 @@ #Current Loaded Language -#Thu May 01 15:04:30 CST 2025 +#Sat May 31 10:30:35 CST 2025 loadedLanguage=system\:zh_CN diff --git a/language/sys_zh_CN.properties b/language/sys_zh_CN.properties index 74b7cc8..09194d4 100644 --- a/language/sys_zh_CN.properties +++ b/language/sys_zh_CN.properties @@ -24,6 +24,7 @@ andShow.pluginInfo.writer=\u62A5\u544A\u5DF2\u4FDD\u5B58\u81F3: andShow.pluginInfo.writer.title=\u5BFC\u51FA\u6210\u529F andShow.pluginInfo.writer.error=\u5BFC\u51FA\u5931\u8D25: andShow.pluginInfo.error.writer.title=\u9519\u8BEF +save.crash.report=\u4FDD\u5B58\u5D29\u6E83\u62A5\u544A progressBarManager.title=\u52A0\u8F7D\u4E2D... @@ -116,4 +117,8 @@ settings.4.load_theme_success=\u4E3B\u9898 ' settings.4.load_theme_success.2=' \u5DF2\u6210\u529F\u52A0\u8F7D\uFF01 settings.4.load_theme_success.3=\u6210\u529F settings.4.load_theme_error=\u52A0\u8F7D\u4E3B\u9898\u5931\u8D25: -settings.4.load_theme_error.title=\u9519\u8BEF \ No newline at end of file +settings.4.load_theme_error.title=\u9519\u8BEF + +core.plugins=\u6838\u5FC3\u63D2\u4EF6 +plugin.info=\u63D2\u4EF6\u4FE1\u606F +error.details=\u9519\u8BEF\u8BE6\u60C5 \ No newline at end of file diff --git a/library/DogAgent.dll b/library/DogAgent.dll new file mode 100644 index 0000000000000000000000000000000000000000..a6e16d279a53e091bb3e5ef9d9e1376cbb3fe928 GIT binary patch literal 39424 zcmeHw3w%`7wfCMRlZ3!96U;#H#ejoEkr+tCKtN{5M9$C|h!7qMl7wVJqDf|)2M?(}3)Ir{^HH#iW__(ijCE%&`X8~5vdF799FTLM4zf$Mxr;Y+Vycf*VDBY>y; z$Sk@l%9== zXRB25h4J|g?&<22Vs`vSETSh)cYb5dz6dMXN;rFaLTVrkxeE^?v^6nTuDBzxKPD`v_f8u z%rR>XRcg*-?8uQLR3UohvSy;+750_(Rp@(xOMX|9KPh|znLcON0jkwFsRfN;&e(y4 z#plineJRO0sYXhZFLGHG9Ixwfhr)pUs(WsJTaM z%U7%v^G$m88{)HAY^zf~9&fMl_ArezW*Z4iDg2krfZ3heAw{lMo4xMZHGS8kI!W%7 zB1GeGcZQfeSyW(X@~F*TgJw&SbtYKkaiiwaV+yCr#0IUA@7JL)27CE#qrMiT~g zbSkrW+ilBNVw%t-ktBJ$wVmpCTC_X1)g^B+x#f4Hh=a!Z6Ew*=y-OxDHjreJV?{lJ^in)$VP~Rb-C_n(LA@jA40|*_3B*mGgewGz7sw7 z3Mu@x$zLtW=S%WSO23;5S6D4>xyuQrcmr`~H0NBm{M>hg^@fVg}*X^<>XOPY+rnYU9z2zuycAhm{E-IWG6WB)I4fu zsc2_cDPKMhq+(7JIb-H)KwYdySa~HmTar`wSjevIWC4iznA9b7b`<&`MRb@JnSD;Q ze5kPqY3)6sT!!jN%1ZL+nE4B+t&pZ?{f&CW7?UW>rRfeH`HH$+awym!$>@Igt4#k) z>U%V21u0X1lK>7Pz+ed{0GDKi9a5y!R2NA#nlg;pcrP^>v%iC>x5y-QE#e?`5v-b> zBtkLe_ggAKquJ0Xle)*(?@ZCYs6K{l=qexvga*i=%w5db$xdC+um^mPtQVCawE-v# zgysRPBjA%DUC@*udah{%e1?1_Ma|3kB={s&4kcl{D{5GSxGSn}4!HJR>9hAzeNS@K}3`o~G*n5{y_eVx2AXCL!M?q@4vTCCNw* z2z{TH(5N|`*M_piDC?GAfb=1)NXT8Z;JEU5HX-Fp6E$hj9&6tX5+Dg;3)m9lPz1C% zk*1tT1A(%dFWw+MUusoC5kIK(mUUQI!4e<^=`SXiJet-+8ALd2k6q;xWac9`MB}9L z#8Of7QSjooMl(YBU;Vx1Eu`aC*jMnejXq-C^(mCfZ6B47rFQ7Y-2<<1zZ7Ye3=rlt zFkd<3PoN^&Tp%#Ibx67LECR(U4Gu+jUj#K*VQ6V-qu)^xp@+8ner~Wy3uPMcl`YPZ%hz&HW~FBO+J%)Mzq95&qPe?H&XK zrMJ16Y#7AEkGM09Pv}2IsI6=aTK|3p)l$}i;5#DNhTvNwxC7Ec#!LV}J5qOu)SU?4 zBZ3dd%;&6P41J2atmVr036{EPGfA=piMQ7|y#q^Dw(-^|n8_KnWz#Hn$)8E#Qzn0^ zOD;qWv(P^Kv*16>i>Wz?K%d-r&Ud0|>8_IAP2=1ppKsEa6~_8UyX9}N;`XPy<*%L5 zCE3mxak}!;D~YACn!Zd6>K%yDO6s2eXJ@p+n(a(|4Xd9LK(Yf%oXsI~diPIPYsAdW zL$&vVCtQ(QE2hsu%pf}^2Nui)U()X3xY3kq%x=xY;22Hcf!K)_BUo1WzAI7#;UfgI zqwNA(*P&@b#9v18T?R#HucNNy=kirtb`FxV67Jw~eq%<={6lP%k0^%A8LKmT^?$-d z{mi)4VXZpgu$E&Hyq~I-!q3{^nIvN=k3$73JVw&#r{joq6e)U7?ihegf2rO0#OSs$ zXGzgDy6p!;pMn+iSwIO^D9bfIsV6y57b&xV1->S(D4QbdZ^RBg(wd7s0#a{4q^vt@GZF*CE8h_0&J+I=|_!E=-SePn0y8K?zdnX1x7Av`{&I8DErE z(%NG37Yr?`XtAHuo7UEZb=7$LhbTu&%l#N9Q0rV|&4LWs%3lGEn*eEIkpAdUs)i!@{5^~#ooNrL6>-iYep|0nMt_!)N zb)9QSF93PpAoO_7d-kWOR#&vFg-dW$em?T4Z8o$`v<#e1Lyx>q%c)_#oal$+M1Pzn zW}N71&6n~PND6#gu{J0 zCam2aHiN@+=FmAsH zWuXN;fwFxjf#-FBr3s zj%Rip&z;G5ek|~O0KV;O5qM^C9ya`r@TAA_{Pi>H*T+bdu$V>7jzm1c6==(1lm2V2D>Q1TaN)rZy9Z1KNxRP%GBsnU9SEa%uO7$!P zy3hJB=^@+plRCm}9M_VS<63CH#ngmh59vdumC#;#Xq07r#hru<+RJup2U4&_=b9*% zPTTbDRtDB|%RTnpEd;I2N_z=J2X^ZxTv+uB9L9x+9*UW>K}<-=*)j8n*nfown}U}~ zaw>+)!ny9Sx)4aD_eJ%;<70^7;<{h|EC<%hg0j|wp^V)$XZxq}vQVNNXcM&q8(gxx zS!lf4TcFxPFce7goxI&dkE=jyqK86l-L{`PxDKWY>_>*_ZyiE^vk~27{W2LI*WYMa zhxtJ0Ze@jkBF*j2QIt05LPu0ZRn^=E9Fc!Fp#bkqYYs2^8t+Y_=Jv3vxxE4sU=7|a z8{R-D;_ilCMrm#CBUqwe6uHMqb9)J4(%ck4PKHyzPuTEFgKn+zF*_i=E}_F z0`c}l#3V{-ZvICSQj)Z0s}n0jHdPCa*`jGGe0u{W0ssM^9d|iH=?}G)@V6h)Qu-k86^Y4H zG*ySjSXB{zh_afB@T9Sqm!joh~hi+|?PsPmZ9gLL>hUUV~j1bx3sS2A*?m!r} z#~xD0ZP2l4_D^CK7Bl}DfRJ4o90wih5CCls_n=h{5{yp?zzYE=ic{`=$c>r*6=~r? zeQ5j;pt2InJ%{VpYsf-3#LQbc=&BG*>on%OImc*vh8uj64`%MaJZ4@AK%fK6B}j45 zo{j7kTgLz`FM4xQ(Q&RQcHc=1R@l*hoiyjN^R_bN~t8!R9Iaxa|Tjrzi*?s z6f=Jr=Guug$6<8^^Lb9p{4OtIs6kWEj+arP@^9~HbLM|3G-v*W@;I@e*3d{0H{6&9 zR*T+erLl6#Yb;JVkmr=&8*X1KAY*HIZ*gon>@IxiFzxOpCQ$961(lt!vf~iu#n|#p z7e);OGzBU3Nhzk?2ZxuD+mO;ShlLE-c_ktX?*RE+QF%uuY5@;eT+#53G=!r++<_wY z81|{c7K^$yrUjQuM0|_lN0&i}r`J&lO6bG}P}sAhhF37_lwVFAS%1Y*LEPR7eCWAO zie7e1Pl#spV>b<(?({F@SB0rm7$$<}yW|NDnGO=Ew1tZfnAv_nnq=H;3@aum6olah zR!rV#KC9IIYrYg+jKiWs8|N#N(KH%=*fFzVm4IcUw^xctuAQR~6r zC|>2w301agRbqD`#ip*bYm|-K`wNdDD`q}o<5PEG%sd4!g~#Skz&dNZdtd9Z5Ez+e z*)j(;LYrkcohOaqd5o8k#;Dq|#u=;j@c`GqRns`+jgNR**1x?Kp4fB{R~Mdy=&-?d z2>w0}p;FFm@n2fej^IAT8 z!7##jt?oI0&uM`L1sP<(#_7YIe4^6C-D?#SmpYA!n~RBy$*WCVl>tZ|Tj>6T4RqGZ>RbgGIn>OU!a>4qNWanD1iNh zdNrg~-kyx@FyIBY3%NK%zXZ0&I3lx&>VWoL1s;rTPjdlS6lTtPsFtk@Jl8{7xO>JD)1#t#pBm7>Hu<42dGT24FkW`9JNZ7TpX$;!B6MzDypF|A;#s5X(Mb z4xM!V2UZ<=wn~8N29yisY47SRdE0pV zD`*I@%jyiU%kC_^_;rbv1|y9ffW`*hpxU zJB_7p;SQ5=I|&w=NVInBCUL5ipdiF)9c1VpO2D$W4q@Yyy1J5m0f+I44(MMg2OMct zI%i3D=tC*GC0H`2vKS`K54>ue}eITie_xx98=H?jUz>ZMLL8VN}WNYGpwZaze*>M(?64r zeuGuAbxr;o|k?xG>}_>Dq*2JUYb6;v+>yE??dcG&0W6ZJP({W|#6Mp6DYT^Q@#=gbTOQuNjE8Nb88(O*X`&O{S)A;lIR<4r4 zO=DsDn?p@ax^IPBM0DSZw^rQ09Pz%@`@~t$Xi&rtZu_f=^x7JEl@VR6iS2{xM!XipZN%mJjxc}s#Q6g8j|&|gLYgcLsL3M2|X zB?4exB`wEC3OnLcTdcp!`COC2^G5*}^nOL$l?%;)w3q;f(oDGD<;yVbok%~5@12UT z6`Loq4Z;;2tWh-bRWuz7#I+Gu&4ARkmloFD)G_CmA4o>qUK+s{#-qt6A(-8*CvTZr z7^`cC67Il)!tXQSQb|3uH)kX*7CRutx^M&ernk}EJgoUK^XoWHBGOig4KP$eDCmaA z3yC7;GPF@)FOhuiM)c%s6r!eaz6ZBoy9SEaYXEMUuiSt}!A4E;Bx*PesT?!k%+IO} zbpqQYR7gwlza0|@<=0~7Qp)1Ue+=X}cc*x3Of!JLc^PHLH$GOH9DL{b9`FzCFZ%d3 z&Zzl+^Hf-S$B2smL>}7BlLwXA2^AmW5Y#IRuXtQ?#Wl$l{~CQ06(38k_y@=Uy|#;r z-a)3)b5x_(fmf+ZyOHOD4ApdHjJ+F5nx-)q9wVJh=BHTPfTM1!-T@!RyB?e&YQHn7 z_WlX#K{tB*Kmmaxa04(M&|l*t7QrdWzvfVS@|bl(yy>J^RVL?MdU44VHMp^oC^JwZ zo}mV4Sx-7olRrX{DonU6RKzD-*&voJ++yefIrQKKNTfZ~2vikouP3gM-92SwWYm9* zbiS#2i7q4}8EMA|PXyO8X|(~82%S-t^&GI}0-~(P74ccrbcj$&FVNB@H6J<#hqI}E zxqw^E;SSiYR{d*Ke+~SMSi6L&!J81VSAlQCpa7MFRi_>unMbXXSM)&dK+Dh(Zt3Et zfocv(NAfT+;f7xbaSZJpoT1SpbmO>s!_S2-!f40dzf?E1Wah)y@=QI5>PJ^HO7%rt)oS)4gmz5ICIkO70QO2z0@YRf?*jzMYuEM zlCzP$1H(~xO#XDviUH&I{uQ;!uk-Cp+@1mwppg4GNHB-vDC?D|wJy0RRf?=YWW{lQ zj|3zc?jCa;yI-%?@1)LIx<6K2!zggvhDx2VedP(@cawp8dvU`vu zy5%gY`abI}poL_wN;I+qyOU#ATR{CE-YTR`9o~Yzo6xj`NfWoPfheR;piFf>djI(I znr!%2$fB6}J|vQ9^1OSScw@91(~0FD7Ud^X`Cz>Kb-esqt^ArZmv0y4-Nd?pxBJa$DQIM9UQ2_K2X<=OMMGlu-Jqk9$pf=iK}1WSh%h$ zu#{t}(ze+G)e&N5vLuo7;frf?`uLdW-dTcDWZSsdU%)_tp;#7ZPU8S z+US_N@MN^yLS6Sskx&cK$)|++@I{eHzXYuSSjzEu>hG27h$Q~`%Df6+jk-|5(VeeCcPn{s!jHL)DU+@KWMH?C0#SKWPO+J1a zmT&`dMvp~Tapv#ASrrJ4|NjC&20w0yV<@L5YXJ}v4X&? zkO`8K8RBs(LrD4+EC8{MYozG2RIILDB9YwMLzra4qU)f!KSlNqWdTPPJQqWI5nr;S z1f$f@evih4PG8Z5`dFv5w=Y!+cV$X7o%m41|0sQH6gA(3NksRO$_w0F=x;|HlKCEZ z&_LkjexOrN^$FN(|VaqEu`McR|Gf7Im7CeGZ@~Oh*$ajM}agwV^Cs z;C9i8H!i&5K8%0`)s@e1mPEiZ3;}9AyMdl3y~OeH3*CsL;82|3-4;}IVPni`2$4v9 zOB-ckSZs%BUXaB6*g*3`ojBX}(|od5UfU_v97ZF5MfMT-&gY5nxYvqZ61odwhU!83 zBlVQ{77_*h<^dS3h||x3IOw;6<2apu=>G`xqg2qZ94l?#)37x?l}QPa%l-wGDf=)F zvD~%q!APPd-Nc%af*97KP%i(H!Qca!FrpojB8K%8gBk8tltY7;^GsX`{26Q@Tn6Au z6ox2PZow9bx^!v-b!l{-)};na>%=bIfH=BzE4-0d0wf)wOO%Q({RTYQr;r5?OlU*v zj-WDH<{%kl!z9!Rg6{&5d|V#f`xjIALu2?oqq44xN_5kwa{buE2z|O0V2VS{fu?;l zo^$CDT6!iEHrcSAYQXmj@G$jKbOpS+0-6j({EW;{Ob~Ph!ph?iiK`=TDw1?0TO<;2l5+R^T)>@2a}iuEQPTmo znop4~G#(wJVlcSD)(8uaAqAkuY=}FPK7$8s7P>z*8e!a@k_vE}nbO3m%X@X4t-BiL0cUc*#-CU56A{LT}rYGACVc!CtM7+TO;Y4UNdL?_SR%luzZ`Qh1@Ocvj6wS+kKv16#aDltiJV(X~*a5k~ik zclqdUMN`G-4vpw)NL*2d7BdVj4PqStX%J1ap$5T-l#BK2TpB}M!u&4}VB`2R4&d{+ z12f_P=3uI*ETayf32aULGkgF)<5V1B0AEK2?)yx|0Ja`8ZeJvZ=sggclavp^x1we} zjyk~gGcWy?)XW8-N=-9@iPUWWZy@J+<};G>7Tn|+k(|%Ls+mmAy__7Ulk*{-J_0#q zWW>xBR*;kI^zL2u-ML6o?&kYkgA5ME1W{8tap?pCli~*C;AGhzy-J5;$JxrMfmn6)2=%uT1zd~DK{K5T?t@>msyIPneQdF&oq&=}GRBac|Q*d}8j z7?La%SWwlS6Z9Gap(ApidV@!rlNlOYw{3G~ zb1;yR&?v<^M5zue-u=%>)A3UcgR$UZe41^%l|H7BvKVZy3C#9(U;}#Ws zy!Zm}A}odu3>jWWrFxV?>|e!UQ{tAzlC&D1k>lUOT6IKOjXsgZw4AK)P?}pnD>|AG zODx7pC~wf4pGZNDurRD$hjW+x7)8;1!GCL&B6^&wEg)Im3Gg6YZ{jOY>N#0hk^&r9JWNBW)wA*dfXF>%Xw zm~{?84O0vtH8)LAcWJ+GTV5tZt$*Dfeh=5$586+%G?#odc$QtZWx8w1)4n|JNa6KpEa#Xcxzr>}neZ}CI&`VV;ArC$@WZ_WE-+vrsyVo(?`zZp8!2o9I4O?Q zW2fxPl_Hxh{3jSJPWfsy=u9aIVX+*Q-vNUVm$>Y48W#@F@hJhos z!_iur7R-hj7+2x>9nVh36 z(_Q!mU1`X5P496V7rx|i$>&bR++psLmjdJK?AzXD1McX(4C|d8ACeBJ^+=-hL{-Z9KN3ZeWuK+qUj>=E4vFO(;*Tdt-=@?t544W%1(1Br? z8^ZA({_8P)xm-k2yTPXz7RWF$CKwMFuI(IDvNGuVb>sGK6jbg4H{Ef(4adT^Cw1ZZ z^Q(|(Y<&*zF8vHdfQ>0{0%&_jaH-Ni3bFGMQ|9A^+4&=|IP8|U!&5enAvO+Oq-+u3 z7Ub87{8f}+j{GkDaV!Ox^vpIZcE@4mW3iU8OE$cVgKT^3XiTpM{W*>BlM@{(p9G0dZi4P9SmY@nVTyuxJI0S}a{Qa? z0^1#@Wc_njQ-ilAU*C*%NA!;%L)nC3t#yH2Ehc;}b+fW~)is-^vcu=1f}M-*H$ScGvt(swhx<8xX* zLFZ8c*cu_R@%<12xG#pi6WDgos5I6=mD91GL?AfHfDHMl_$fpHcL_XDF@s-PdHy0y zo_AM)pMHf*y0lgd`{%*c2-9W~*I6))^;c6|);~sGM1KLm#a-x#ej1Xx^k1)JjH>O@ ze~A$BM3-I%C<^g|Q0e*(AT*ppuGE#LquDf+E*lzF5Mo!FMN7oFkHMuSqTuc+Xkm=l zAiTdA^upZIH{%0XY}Na0#*F()X@L&$Z(h5@n^ zfDMSsK8obg%DNW%i1}g^i*jxG1Nt= zq%#zh!k%2z;>Lmbqu5$Vav7GSG866%A|`i8Gb#KCc0mY7-4+qQoASymNPr~owMc~s z7nYf%!o3o#)ARt-1&9<5RV5i6dodC-E2t7OhZkL}F9V2X^pR z)bKpweFYE!;Ju>=L-c=?r)2zrXqstN@QDWnaCwPVZJzfaWIc#C*(1qmQ?b`aRZ=Fd z`ImGDa|$~KB;#)lJAf$k@hsxEyv|*^{x3PN1Mdb=HbZ#~vZ{ZgvJ~I4K&1AHWcsf(kiDzX5`JFnLdrpu_y_Q|Ol*Aa%xv|Dp?F<>y~T;g^fLV&-r7_*Ga}W3vS< zGFb)SQ+q6G;&l2hM-qhQZrA~tNge7NMQyq9ZQ8yHK&;cSi7ltq z;Na6VX^f7}Hhn2A0)Fg_m4g6NDUhQ)BO;?fuiqlr|HnJDRa}z~E%P%`l*uPT8}K>w zrt6dw7zB)DUh5knT-i2!ib<mozz!scib(S0r z=E{r5xM1F`rHo91>3df#zE z=>%yDkAW_ux4#j}kZw00BEd$IQ-x`n{~t(Ucbo{O;S0bq%0iG4Yi$WUt;57)xF-Uz z&hXTO1kLZ&XYzZVw!ff@+dd*DlTWD9_fc%vP-U8Y`1y;TLIaqxA2W}eNe1k@dw^PL zLNcVmK+ODG+TF?bD*(f3%W-5v-jk)<{C#!bH&2sn(O#a*frg|T1VL1x41SsooD{Io z;&CNM-P%o=kbvb*;{Fh^r*x*+X&&JF* zLZgM2Kr09EL8HUP)B)q&pa{&yROw#YE}}LYzQaHe>^BCa&x}f`%J2Caf1kAn#KN^c zq8UyL&!N~Pyp;q{NBd+nfOI_ym2kc=~EspM^cpO~pMKgBrk8IQ8D3wYT< zc!_0m|3=v%k%8Z$C_HF8XbyTB?b|+WX!bZA@?m*^j8>((ve7-p z2khHES>$OBMbfNgqmM%Vq{*j1^h|8@#)Q^LVZ*&kK&z<(3t~p8OCLsrwcwh1N4ky$ z^X6Bjr?BAU`9AW_*6%v?SEyZpS_g#xLx`*FAAhp0UrE_j)XqBx0 zC7{FInO*uHAwaAi(cg`b{bZ*lSRC%Qbm{3=&@j-*_%1@b0oCKU;JBmYIGqClleKqV zZ^#fftVOOZa^5m{G{E>lOWKOzI^%v*WoKc>9DO-*ux!M4Ntl*LVpHd0XA+x=-)O@7 z3jVh7_p*fabRN#+?_*;L@@4*hmA{Yk_v`#E@Lb3tck%ZW{&w(pGk@pt_r?6};_rO^ zF5vH3cpo{kOPAQpq5WK}ms&miNywji9WSpzNYOhipk3elzY`V+ExuiglWBpjyjdg} zXa97IT>KJQ>LL3s-5yMQOxa%==vNRxdGV0+(+=q+`3@ga`(A!5j=!AZ`-kFrAWYxm zL-AaSKZLkVtM?AKjpOXQ4Ij)LNl3ORL8P>+6~;3J@GCef7QoneqwP8wlMxykdStss0D5|CQ=z{);Gow(94rzC-n|QT^*wzd|k7 zuErly{U=oafa<@h`tPd#SE`?*wx9o;BlUBqsNbRDEmHj{s-L6!H>%|`)%a?)+!d;y zr}|@6|I?o_{=B979jgD3>bI-@M%7=h`l1wLJMR^tcU8Yu^)I|n#jB0Ok41cn>N`~b zHr0PY^~e51z%5q&Hr0Pq^(`uX0maxiYCW0vi1@n-#0KReiuR5MR+tZv?LsT10ezqz`x%Ay~*?TKJx5Koqz58 z%TsUudq+GGImx);qzv1v0{1P!tzDbH)`teJrNIUFG^#m6^!8$;G#cY)=NtUNP<5ld z5x?SIwpkrAlv%v7DZh5+Ov|R~fQA0LK%=+1)>CU)zr_-)$FNoVH+Y6d>hFZ7CJnWR z(`2rtVhHU@x24wW5%mT_KA+bgy160HWFb7-^WT7vqtg1l#A_KA z7d25c1NGH@(4xuHXj^OWr=M`MZ=M2q;8b0NcD;tg- ze=gzM!i(l7&|SsvM=ydH(Rx%@8(=if1lrIH2^4DbGzUe&VSGZYZlRoE=`L?T@Z@#i z(k7PAYQd?*gZO=?{MyDw%K|EdXC$_#%!cNT)r}3c7FGWFynzO7s_=49x|1H@b$e?= zjh?w8d58~)K~al^s%5Ok+vLNjRaQ6GRyKS6O{nBXPi0MGbs$i=(c=$5f|FR&;Oxz{ zOEjob0$QoUsMRn&u0BsqLtO({p)S;1L(R0*ctee~e8Q~vSn9y9L`=!+yHGuzFkjEkFCDx5l z^QA*$hs8h}MlNxjO+G;7ExzU&`q4>x@=jj`PEP?awU!eClqs!lY%B-gR5vuAmTunw zmf<-9f6!mu9H;{+MU+V%NE%C>-`iwyxLlK&g%_w?+Uz27u%WnJEDLI}q4X8aoN!t? z)|v#WX{k6K3R>_dQb=-vg#r!gTGP;cou?*fspgEK{r!|+eRUide?29L8D10e`_Ydf zF_|zPiSpBukY3l&Tx%I|xs0<1nm07AL+hSao0x+Pvj+16;@bl5Re5u+MeSN$e7>vv zUE#ENnm0E1z0EXP!4S3J2FCfbdVNDzrx>9;d&zn#*6D$w797&uJ5-Z z-}G2A9L#=6kByYi{|is?}+?gJN??}k+NeELJ!l6CHI25+Q5#GcnvEI!nV`;(P)ENeo2#@ZvV!&um zIl{y1raZ!>;ZCfd@FzYR45djZv$F+d;m-7sWpH=PQ0{Sr&(sEjBAnD_dJ@|~^&~!t z?dU<7ylu!OcZP@HZ3+4131KQiIJ76RUXEAI$c3NMlG1V~$`&B}4E#L!h1W3lZ*cqJ zoNF1YguAqou_;xMn{eLs`0*;Z-@`$H;eVg$i&DnUtw6pGabjjL=Z+fj=aYKj=OcaD za>w$*^{*R#IqiqG+rN8}WoFlt>m~uzF?a1k2sbFuS5^n=p(d2qdxKtkCpABwT`|JAQR0a%TOFtMH`V; zg)@fy_1M_c(;@yQn)bKD=x?P}A({V;Fl)g~1X&f*b_}KQc2oL)_UOi^vGL2s`Le4_ z1v;Fwq|Ztz(BaBd7QUs(nw9R;;VY!HTOsSnUkIP)Ws1D9IyM$*6DR6f*1PGwX};8| zlydMc=4m}Do~%z{`l7L{1Fdm@YHKkblaZbn*X3rh+}bfLw_-HQEkbx%&cL`{lW*eq zOg6sAKy4c^^^WZr;~QO-i@9|KIEqi;^(kEHZ6Him%LGihxjpnQD87XOD4$*_X=&+S z0VpNAg@nk>`mwLF@|1_uKT30DT{xxy?a*bVP(R8iPSP_&(Rs|EJDa6fiS~COf8vFD zX4d&xdQV!1)-PWw`cRR@D&D_=xq@5Rg`fLaPVHuvS+t3@Vr zUBX5KJ(Vrjq3t|x7V?m<%a7+(QC`7lHmT^CZj!EBXBrsWJEkYABh!~rm5#Bazq3$u zJ7aUPz~{|JU>RI`mIc(^Ig8%a#eU&s-omz|rW{O7cV`o=IL=pq^U#Pm+kj><;k*lh zN8mEY5Sm_&Q(*pi@lPn}=f&ghNO?9j?GLG$N7GV1Ny)r6HRVrfna+%qrWDjOk$BU< zvi#{))K`+3oX>(|m<=;w0InP8iT;UkT^4wBA$YVZwLArbFUq7b-&t6f;Am1(nZ$U! zj8E{j;AhVJ&a&nRy!F>Bhz zY+j0npM>pJI1PVdTsK)fZ4!lZ$sMTC7Eo= z`Y|H~R{3^z-hI2#&O_Sr)9?S*6Gr+T9@DpdHv&r=fQYPxcX=wu~Y$0r6moE zR2l8N)MGoT-O%uCaJ##X`E?w~$n zK|wzCF*zOUXad~Csab47(ReoDvE*4ueO?XPs{A()=h?D!Rt7%Lem{-r_ZwJ234S>o z?r~lx>O(q1Is;5{9@eS^Sk6Q1GkW4Y#K%w%-03X)bKtHR%XZFT>;zhIID6 z9=K7@Y55Qi3GliU9V6bB z)v_H3r+~1JsPWMVkB8IpDLx?~f7IFO?Cc^VJKI0LH^+BY72&1!x&c#oHTVp8$meZX zmQt=WrZXe@U_>8`vqt-LqjYT4dgN!Ou}nW-9Sd}ZG^{nFm;vj~D3TRZ@W(k-ytl6d zEuaUV1YYtv9n0b8knD#84Re4yXO_vQGh=Nk+Jp6JHzT<%>PEdqdS)Dlx`|kLG@rt| zCeWKP3v{00Pbv~@NUw)$A0eOMNq3<~)Aw@`_KoLB@s|l9+8fc62v;x+j`FoVTq0cW z2yj}vkB`tU;*m48S;Kqedx8#NH%2ZO@hZ57;Vfq(47U@G=H{*o;4T%;SA_gh z%ix;eehv2t9JMrsrGkI;ES+Uw=8a-mY&3(UVPlyQOF=f%_AK18x}a>?vdW5jzjxEZ zEp$9$vt4apU0!Bi0aI96^TtY>t-NfZW2WsIHUyb)cr`M3GIZjB)|uhSVpi$(Z>X&H zHB{Dm;ggA|QkdB)mxY>zMX}P;469L%XPKu$GfjGGN5X1fS$Q3|4^s~);$2V1LpvST z*=*E8ULy>ym2}P$&}v!*JD_({KsAiJakhnfNtI+>r-LJ^Y4I@fB-B(%d8ljsmY_$i zY4KvJtELf_bq&FA`X(V5f))m~|Dxjlsrd6?UNmNHoK&AX_|2cG`GE7-QKY zvgR-H1Rafyjs`!7gmV#*2;(79X{DPRG{4R8)Ov7ysn+>zhm9sYT*C3%(%zt^%OZRlpe-K>^eut*Vs^ldlqWS%_)$n@yip~vg?;8#edC8z0J)KxAAKUjD5t0-Bf_iX-Z#J-4MLe z>tBv@>PF8}zK*e3guPT8bn!E57<&p&PjlAdZ@>$j%lJ_-)_SaEjLlAf)zYq}w6e_& z!BTInM@`I6OSl_?y?pYCF%q;CG$M%3lx>EBpT5f95cH_ca`S_B#$Hp~LH8=$;?y0z z)1@K2vca=yX&t|Ck*eXl((myA*vdybls!q^V zqn=)Cxk?HAg~qaFOUhh@v&0#;DTOF0pewxBdz#rKX0N?26bSNIxxZl}I=I0TV4HPV z;c#N@Z3Z_j_cYeApXgjTg%0`RKr5>oLm^(D3Do!-d|1dU zyr-w3=XS?Rd%06<+4oWwRIV16mnuDU@5mMiYDyJXCfN50!W#-!dh05ocWv;T264WA z0T#^a(1!Y8W&Bo^235Ia^)>9Rv;_fQC|F}#U|nAwXsD^g*|w*;X?>{9=2)@7ifbYM zN}M-01OqmQC@9`nmD%kQsWj{zfuZ>y!9c3nLI+ou*mJ<+2?m0oZX8vE7uEh}%~&l} zE6@hu83v^#ho9H8XVK;7ne#a=;%Z&5jDn66u}V75lTZ(Y(3rLne7WD1$lm)nd5fp=7xboZf za;6P4TlZg~3#rg7>%W2lthE|Q9zYK;fBvB!xR zSW!eud~Q|Nczs)N>UCOrtp^2PDfvo21gQ|6e(Y1{FG)a2dhVOLNH^8^+K28{TR`wwhWO@N2y@)Gq(%R~!GD+A&-O-*GzUk{N!RqMkR zpQo|`+qO!zWtEK$0bpHOx@^Ug3a7g)-s{Aa%9(-^a~R6ld!ss*%j!tXvxy9shj5{Q*7?fH>KcErvcbE) zlCA(@-^^*8P`XYneH&4rrU_a;dW$8a5!XHI*=%ZCLy!iET|N}9^soi2GT^DNtZQhb z=F%0WT$J-R*EMXw)w0TF+!^(5s>C(Cjj#cUlDN`Acbe3!gi9eXawb7|n>|>fD}!_c zlaIe=GsJ$-Q<;=89`z9%=C`k5MpIzMriSJj=srDsivoF$?1shANeHc#<)-*a3WnWX8SopNvSXpxr zn^TsiM~y20->gf+L$E$qDu0QLTLa&B^zN@)y`w;*Jv}0nAdB5Gs{I4HHWU*3~n? zlL*s*P|-+m@s%P0PHWUi@Ig&Z+iV)xKYfh?rlB)6I$KlV9%>W*#|ZC6cmV$I#=-X6 z3fn$>?TnB7YvCM#A-@K0HNuH!g>;5EF$a4+q?11h&Wdp2*&3b69XG=vo&2}p1`#Iz zeYjklTMfX!2sUsl+CVn*Mm0=!_D9q(*~rID5HNINx>XIgz<&s?9ysYZ+>i^q5yB?; z55h^niSH;F{X+aD2xBQ_=bVju0|=8Hd?g&ElRf-?HB5H#Kd9ke_&>h@`8Z!CJNZs4 z?!w$A{J?aa6(PL^{?Fkms4n>5oq?lAz_h^6%g1>R!Ugcl;feu6KK;5Tv7V*IEF(#g-6gK`Lye>PkTwFmxB;ph%Z z;@KFTsZGXN+_|#wry)EKVe)6dtwlKTtd7q2Zk>l?J)H58-v-x2wCN2F{9f zIt#g14bz#(2{p_d*we!m0DdQY?R+-z43^GjUs?p-M?1-X4{iWq^7Rt<5oO8mEk{2P zCVvo)(i6{+>1_GD<(PvgOTGtgGs5Iw57&k;oypt>$Hx)=7jStj{x@(t5T-k5)8PouCGc;8BRu5)U=`{H%-!&F zSEC%lTZu9#Oa44Kf+63dhBw3StO9=lWZ*L>3~FjzI$R^xj@&-`gyJb`Hot}tZH!^bV2ruB_mEI`m4m_H5M;kkjDdVJmy zn9oQQ-doBx@3e literal 0 HcmV?d00001 diff --git a/libs/dog api 1.3.jar b/libs/dog api 1.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..c6730ff2e0c5120e77645314a0114e671af5380b GIT binary patch literal 22889 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%0Dndn+X2c@_sHuJbC#_{A>tz(o6Oq#rQX+jS%DC z?apO+*MHPCLYn^-*uP2f9|Lp$5&DBL|1rROuU)z(Oa2_-H@*EWz#qc{06H(dAXM~^ zP5Kq_btU1SHXZ+sK9p%D7~yYa~Wtk(a8M5y!cX8Q~BFRlJ3JVKj)x3b^j|5ob1 z()_3&5z73#efbm3FFO5KRs_qp?nh|P?`CuV=Wh9{ao?5buS`E?O+;?|Zngi1>5n?} zS2sUqgP+}8QTtuMKWBh{O~}8x`SFcq`reewvsdc>-_2i1UR41N9RbC=+}2S504q(z G)&Bt0+}^PO literal 0 HcmV?d00001 diff --git a/mapping.properties b/mapping.properties index 5e69b74..25c3475 100644 --- a/mapping.properties +++ b/mapping.properties @@ -1,3 +1,4 @@ + #Obfuscation Mapping Table #Sun Feb 23 18:01:01 CST 2025 com/axis/innovators/box/AxisInnovatorsBox=a/b/c/d/A diff --git a/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java b/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java index 1c4aa22..86916d5 100644 --- a/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java +++ b/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java @@ -20,16 +20,29 @@ import com.axis.innovators.box.verification.UserTags; import com.formdev.flatlaf.FlatLightLaf; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.FileAppender; +import org.apache.logging.log4j.core.appender.RollingFileAppender; +import org.apache.logging.log4j.core.config.Configuration; +import org.api.dog.agent.VirtualMachine; +import org.jetbrains.annotations.NotNull; import org.tzd.lm.LM; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; +import java.awt.event.*; import java.io.*; -import java.util.ArrayList; -import java.util.Arrays; +import java.lang.instrument.Instrumentation; +import java.lang.management.*; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.*; import java.util.List; -import java.util.Map; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** * 主类 @@ -69,6 +82,7 @@ public class AxisInnovatorsBox { try { LibraryLoad.loadLibrary("FridaNative"); LibraryLoad.loadLibrary("ThrowSafely"); + LibraryLoad.loadLibrary("DogAgent"); } catch (Exception e) { logger.error("Failed to load the 'FridaNative' library", e); } @@ -103,129 +117,567 @@ public class AxisInnovatorsBox { * 组织崩溃报告 */ public void organizingCrashReports(Exception e) { - String systemOut = Log4j2OutputStream.systemOutContent.toString(); - String systemErr = Log4j2OutputStream.systemErrContent.toString(); + SwingUtilities.invokeLater(() -> { + String systemOut = Log4j2OutputStream.systemOutContent.toString(); + String systemErr = Log4j2OutputStream.systemErrContent.toString(); - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + String stackTrace = sw.toString(); - String report = "========== 系统标准输出 ==========\n" + systemOut + - "\n========== 系统错误输出 ==========\n" + systemErr + - "\n========== 异常堆栈跟踪 ==========\n" + stackTrace; + String report = "========== 系统标准输出 ==========\n" + systemOut + + "\n========== 系统错误输出 ==========\n" + systemErr + + "\n========== 异常堆栈跟踪 ==========\n" + stackTrace; - SwingUtilities.invokeLater(() -> createAndShowGUI(report)); + SwingUtilities.invokeLater(() -> createAndShowGUI(report)); + }); } private void createAndShowGUI(String reportContent) { - JDialog dialog = new JDialog((Frame) null, - LanguageManager.getLoadedLanguages().getText("andShow.title"), true); - dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - dialog.setLayout(new BorderLayout(10, 10)); + // 使用 JFrame 作为顶级窗口 + JFrame dialog = new JFrame(LanguageManager.getLoadedLanguages().getText("andShow.title")); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception ignored) {} + // 1. 添加窗口关闭监听器,在关闭时调用 quit() + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + quit(); + } - JPanel topPanel = new JPanel(new BorderLayout(10, 10)); + @Override + public void windowClosing(WindowEvent e) { + quit(); + } + }); + + // 2. 设置窗口置顶 + dialog.setAlwaysOnTop(true); + + dialog.setLayout(new BorderLayout(15, 15)); + dialog.getRootPane().setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + + // 顶部面板 - 使用卡片布局增强层次感 + JPanel topPanel = new JPanel(new BorderLayout(10, 15)); + topPanel.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createMatteBorder(0, 0, 1, 0, new Color(220, 220, 220)), + BorderFactory.createEmptyBorder(15, 15, 15, 15) + )); + + // 图标和标题 + JPanel headerPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 15, 0)); Icon errorIcon = UIManager.getIcon("OptionPane.errorIcon"); JLabel iconLabel = new JLabel(errorIcon); JLabel titleLabel = new JLabel(LanguageManager.getLoadedLanguages().getText("andShow.title.2")); + titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 16)); + titleLabel.setForeground(new Color(200, 0, 0)); + headerPanel.add(iconLabel); + headerPanel.add(titleLabel); + + // 说明文本 JLabel feedbackLabel = new JLabel(LanguageManager.getLoadedLanguages().getText("andShow.title.3")); - feedbackLabel.setHorizontalAlignment(SwingConstants.CENTER); + feedbackLabel.setFont(feedbackLabel.getFont().deriveFont(14f)); + feedbackLabel.setForeground(new Color(80, 80, 80)); + feedbackLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10)); - JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10)); - titlePanel.add(iconLabel); - titlePanel.add(titleLabel); - - topPanel.add(titlePanel, BorderLayout.NORTH); + topPanel.add(headerPanel, BorderLayout.NORTH); topPanel.add(feedbackLabel, BorderLayout.CENTER); - topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + // 内容区域 - 使用现代样式 JTextArea contentArea = new JTextArea(reportContent); contentArea.setEditable(false); - contentArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); + contentArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 13)); + contentArea.setBackground(new Color(30, 30, 35)); + contentArea.setCaretColor(Color.WHITE); + contentArea.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15)); + // 插件信息 StringBuilder pluginInfo = new StringBuilder(); - pluginInfo.append( - LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.title")) - .append("\n"); + pluginInfo.append(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.title")) + .append("\n\n"); List corePluginList = new ArrayList<>(); for (PluginDescriptor plugin : PluginLoader.getLoadedPlugins()) { - pluginInfo.append(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.title.1")).append(plugin.getName()).append("\n"); - pluginInfo.append(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.title.2")).append(plugin.getDescription()).append("\n"); - pluginInfo.append(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.title.3")).append(plugin.getSupportedVersions()).append("\n\n"); + pluginInfo.append("• ").append(plugin.getName()).append("\n"); + pluginInfo.append(" ").append(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.title.2")) + .append(plugin.getDescription()).append("\n"); + pluginInfo.append(" ").append(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.title.3")) + .append(plugin.getSupportedVersions()).append("\n\n"); if (plugin.getTransformers() != null) { corePluginList.add(plugin); } } - pluginInfo.append("=== 核心插件 ===\n"); + pluginInfo.append("=== ").append(LanguageManager.getLoadedLanguages().getText("core.plugins")).append(" ===\n\n"); for (PluginDescriptor corePlugin : corePluginList) { - pluginInfo.append("核心插件主类: ").append(corePlugin.getName()).append("\n"); - pluginInfo.append("核心转换器位置: ").append(corePlugin.getTransformers()).append("\n"); + pluginInfo.append("▶ ").append(corePlugin.getName()).append("\n"); + pluginInfo.append(" ").append(LanguageManager.getLoadedLanguages().getText("transformer.location")) + .append(corePlugin.getTransformers()).append("\n"); } - contentArea.append("\n\n=== 插件信息 ===\n"); + contentArea.append("\n\n=== " + + LanguageManager.getLoadedLanguages().getText("plugin.info") + + " ===\n"); contentArea.append(pluginInfo.toString()); JScrollPane scrollPane = new JScrollPane(contentArea); - scrollPane.setBorder(BorderFactory.createTitledBorder("错误详细信息")); + scrollPane.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createLineBorder(new Color(180, 180, 180)), + LanguageManager.getLoadedLanguages().getText("error.details")), + BorderFactory.createEmptyBorder(5, 5, 5, 5) + )); - JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10)); + // 按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 15, 10)); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + + // 创建按钮 JButton exportButton = new JButton(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.exportButton")); JButton closeButton = new JButton(LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.closeButton")); - exportButton.setForeground(Color.BLACK); - closeButton.setForeground(Color.BLACK); + // 设置按钮样式 + setupModernButton(exportButton, new Color(0, 115, 207), new Color(0, 95, 180)); + setupModernButton(closeButton, new Color(100, 100, 100), new Color(70, 70, 70)); - exportButton.setBackground(new Color(0, 120, 215)); - exportButton.setFocusPainted(false); - closeButton.setBackground(new Color(79, 79, 79)); - closeButton.setFocusPainted(false); - - exportButton.addActionListener((ActionEvent e) -> { + exportButton.addActionListener(e -> { JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle("保存崩溃报告"); - fileChooser.setSelectedFile(new File("crash_report.txt")); + fileChooser.setDialogTitle(LanguageManager.getLoadedLanguages().getText("save.crash.report")); - int userSelection = fileChooser.showSaveDialog(dialog); - if (userSelection == JFileChooser.APPROVE_OPTION) { - File fileToSave = fileChooser.getSelectedFile(); - try (FileWriter writer = new FileWriter(fileToSave)) { - writer.write(reportContent + "\n" + pluginInfo); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + Date date = new Date(System.currentTimeMillis()); + String timestamp = formatter.format(date); + + TimeZone tz = TimeZone.getDefault(); + String timezone = tz.getDisplayName(tz.inDaylightTime(date), TimeZone.SHORT).replace(":", ""); + + String filename = "AxisInnovatorsBox崩溃诊断报告_" + timestamp + "_" + timezone + ".zip"; + fileChooser.setSelectedFile(new File(filename)); + + // 设置ZIP文件过滤器 + fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("ZIP Files", "zip")); + + if (fileChooser.showSaveDialog(dialog) == JFileChooser.APPROVE_OPTION) { + File zipFile = fileChooser.getSelectedFile(); + if (!zipFile.getName().toLowerCase().endsWith(".zip")) { + zipFile = new File(zipFile.getAbsolutePath() + ".zip"); + } + + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) { + // 1. 添加崩溃报告文件 + ZipEntry crashEntry = new ZipEntry("basic_information.txt"); + zos.putNextEntry(crashEntry); + String reportData = reportContent + "\n\n" + pluginInfo; + zos.write(reportData.getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); + + // 2. 添加log4j日志文件 + addLog4jLogsToZip(zos); + + // 3. 添加其他调试文件 + addDebugFilesToZip(zos); + + // 成功消息 + String message = LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.writer") + + "\n" + zipFile.getAbsolutePath(); JOptionPane.showMessageDialog(dialog, - LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.writer") - + "\n" + fileToSave.getAbsolutePath(), + message, LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.writer.title"), JOptionPane.INFORMATION_MESSAGE); } catch (IOException ex) { + String errorMessage = LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.writer.error") + + "\n" + ex.getMessage(); JOptionPane.showMessageDialog(dialog, - LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.writer.error") - + "\n" + ex.getMessage(), + errorMessage, LanguageManager.getLoadedLanguages().getText("andShow.pluginInfo.error.writer.title"), JOptionPane.ERROR_MESSAGE); } } }); - closeButton.addActionListener(e -> quit()); + // 3. 添加错误音效并关闭窗口 + closeButton.addActionListener(e -> { + playErrorSound(); // 播放错误音效 + dialog.dispose(); // 关闭窗口 + quit(); // 调用退出函数 + }); buttonPanel.add(exportButton); buttonPanel.add(closeButton); + // 组装主界面 dialog.add(topPanel, BorderLayout.NORTH); dialog.add(scrollPane, BorderLayout.CENTER); dialog.add(buttonPanel, BorderLayout.SOUTH); - dialog.setSize(800, 600); + dialog.setSize(900, 650); dialog.setLocationRelativeTo(null); + + // 播放错误音效 + playErrorSound(); + + // 显示窗口 dialog.setVisible(true); } + // 播放错误音效的方法 + private void playErrorSound() { + try { + // 使用系统默认的错误音效 + Toolkit.getDefaultToolkit().beep(); + + // 或者播放自定义音效 + /* + File soundFile = new File("error_sound.wav"); + if (soundFile.exists()) { + AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundFile); + Clip clip = AudioSystem.getClip(); + clip.open(audioIn); + clip.start(); + } + */ + } catch (Exception ex) { + // 忽略音效播放错误 + } + } + + private void addLog4jLogsToZip(ZipOutputStream zos) throws IOException { + LoggerContext context = (LoggerContext) LogManager.getContext(false); + Configuration config = context.getConfiguration(); + Set addedFiles = new HashSet<>(); + + // 获取所有配置的附加器 + Collection appenders = config.getAppenders().values(); + for (Appender appender : appenders) { + processAppender(zos, addedFiles, appender); + } + } + + private void processAppender(ZipOutputStream zos, Set addedFiles, + Appender appender) throws IOException { + if (appender instanceof FileAppender) { + FileAppender fileAppender = (FileAppender) appender; + String fileName = fileAppender.getFileName(); + + if (fileName != null && !addedFiles.contains(fileName)) { + addFileToZip(zos, new File(fileName), "logs/"); + addedFiles.add(fileName); + } + } + + if (appender instanceof RollingFileAppender rollingAppender) { + addRollingLogFiles(zos, rollingAppender, addedFiles); + } + } + + private void addRollingLogFiles(ZipOutputStream zos, RollingFileAppender appender, + Set addedFiles) throws IOException { + String fileName = appender.getFileName(); + if (fileName == null) { + return; + } + + File logFile = new File(fileName); + File logDir = logFile.getParentFile(); + String baseName = getString(appender); + + if (logDir != null && logDir.exists()) { + File[] logFiles = logDir.listFiles((dir, name) -> + name.startsWith(baseName) || name.startsWith("box")); + + if (logFiles != null) { + for (File file : logFiles) { + String absolutePath = file.getAbsolutePath(); + if (!addedFiles.contains(absolutePath)) { + addFileToZip(zos, file, "logs/"); + addedFiles.add(absolutePath); + } + } + } + } + } + + private static @NotNull String getString(RollingFileAppender appender) { + String baseName; + + String filePattern = appender.getFilePattern(); + if (filePattern != null) { + // 移除目录部分 + int lastSlash = Math.max(filePattern.lastIndexOf('/'), filePattern.lastIndexOf('\\')); + if (lastSlash > 0) { + filePattern = filePattern.substring(lastSlash + 1); + } + int patternStart = filePattern.indexOf('%'); + if (patternStart == -1) patternStart = filePattern.indexOf('$'); + + if (patternStart > 0) { + baseName = filePattern.substring(0, patternStart); + } else { + baseName = "box"; + } + } else { + baseName = "box"; + } + return baseName; + } + + private void addDebugFilesToZip(ZipOutputStream zos) throws IOException { + // 1. 添加系统信息文件 + addFileToZip(zos, generateSystemInfoFile(), "debug_files/system_info.txt"); + // 2. 添加JVM加载的类信息 + addFileToZip(zos, generateClassLoaderInfo(), "debug_files/class_loader_info.txt"); + // 3. 添加内存状态信息 + addFileToZip(zos, generateMemoryInfo(), "debug_files/memory_info.txt"); + // 4. 添加线程堆栈信息 + addFileToZip(zos, generateThreadDump(), "debug_files/thread_dump.txt"); + // 5. 添加GC信息 + addFileToZip(zos, generateGCInfo(), "debug_files/gc_info.txt"); + // 6. 添加系统属性 + addFileToZip(zos, generateSystemProperties(), "debug_files/system_properties.txt"); + // 7. 添加环境变量 + addFileToZip(zos, generateEnvironmentVariables(), "debug_files/environment_variables.txt"); + } + + private File generateClassLoaderInfo() throws IOException { + File tempFile = File.createTempFile("class_loader", ".txt"); + try (PrintWriter writer = new PrintWriter(tempFile)) { + writer.println("===== Class Loader Hierarchy ====="); + Instrumentation instrumentation = null; + try { + + VirtualMachine vm = VirtualMachine.getVirtualMachine(ProcessHandle.current().pid(), true); + instrumentation = vm.getInstrumentation(); + } catch (Exception e) { + writer.println("Failed to attach to VM: " + e.getMessage()); + e.printStackTrace(writer); + } + + if (instrumentation != null) { + writer.println("\n===== Loaded Classes ====="); + Class[] allClasses = instrumentation.getAllLoadedClasses(); + writer.println("Total Classes: " + allClasses.length); + + Map>> classesByLoader = Arrays.stream(allClasses) + .collect(Collectors.groupingBy( + cls -> cls.getClassLoader() == null ? + BootstrapClassLoader.INSTANCE : + cls.getClassLoader() + )); + + for (Map.Entry>> entry : classesByLoader.entrySet()) { + ClassLoader loader = entry.getKey(); + List> classes = entry.getValue(); + + String loaderName = (loader == BootstrapClassLoader.INSTANCE) ? + "Bootstrap ClassLoader" : + loader.toString(); + + writer.println("\nClassLoader: " + loaderName); + writer.println("Classes Count: " + classes.size()); + + for (Class cls : classes) { + writer.println(" - " + cls.getName()); + } + } + } + + } + tempFile.deleteOnExit(); + return tempFile; + } + + private static class BootstrapClassLoader extends ClassLoader { + static final BootstrapClassLoader INSTANCE = new BootstrapClassLoader(); + private BootstrapClassLoader() {} + + @Override + public String toString() { + return "Bootstrap ClassLoader"; + } + } + + private File generateMemoryInfo() throws IOException { + File tempFile = File.createTempFile("memory", ".txt"); + try (PrintWriter writer = new PrintWriter(tempFile)) { + MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean(); + + writer.println("===== Heap Memory Usage ====="); + MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); + writer.println("Init: " + formatMemory(heapUsage.getInit())); + writer.println("Used: " + formatMemory(heapUsage.getUsed())); + writer.println("Committed: " + formatMemory(heapUsage.getCommitted())); + writer.println("Max: " + formatMemory(heapUsage.getMax())); + + writer.println("\n===== Non-Heap Memory Usage ====="); + MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); + writer.println("Init: " + formatMemory(nonHeapUsage.getInit())); + writer.println("Used: " + formatMemory(nonHeapUsage.getUsed())); + writer.println("Committed: " + formatMemory(nonHeapUsage.getCommitted())); + writer.println("Max: " + formatMemory(nonHeapUsage.getMax())); + + writer.println("\n===== Memory Pool Details ====="); + List pools = ManagementFactory.getMemoryPoolMXBeans(); + for (MemoryPoolMXBean pool : pools) { + writer.println("\nPool: " + pool.getName()); + writer.println("Type: " + pool.getType()); + MemoryUsage usage = pool.getUsage(); + writer.println("Usage: " + formatMemory(usage.getUsed()) + " / " + formatMemory(usage.getCommitted())); + } + } + tempFile.deleteOnExit(); + return tempFile; + } + + private String formatMemory(long bytes) { + if (bytes < 1024) return bytes + " B"; + int exp = (int) (Math.log(bytes) / Math.log(1024)); + char unit = "KMGTPE".charAt(exp - 1); + return String.format("%.1f %sB", bytes / Math.pow(1024, exp), unit); + } + + private File generateThreadDump() throws IOException { + File tempFile = File.createTempFile("thread_dump", ".txt"); + try (PrintWriter writer = new PrintWriter(tempFile)) { + ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); + ThreadInfo[] threadInfos = threadMxBean.dumpAllThreads(true, true); + + writer.println("===== Thread Dump (" + threadInfos.length + " threads) ====="); + for (ThreadInfo threadInfo : threadInfos) { + writer.println("\nThread #" + threadInfo.getThreadId() + ": " + threadInfo.getThreadName()); + writer.println("State: " + threadInfo.getThreadState()); + writer.println("Stack Trace:"); + for (StackTraceElement stackTraceElement : threadInfo.getStackTrace()) { + writer.println(" " + stackTraceElement); + } + } + } + tempFile.deleteOnExit(); + return tempFile; + } + + private File generateGCInfo() throws IOException { + File tempFile = File.createTempFile("gc_", ".txt"); + try (PrintWriter writer = new PrintWriter(tempFile)) { + List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); + + writer.println("===== Garbage Collection ====="); + for (GarbageCollectorMXBean gcBean : gcBeans) { + writer.println("\nCollector: " + gcBean.getName()); + writer.println("Collections: " + gcBean.getCollectionCount()); + writer.println("Time: " + gcBean.getCollectionTime() + " ms"); + } + } + tempFile.deleteOnExit(); + return tempFile; + } + + // 生成系统属性 + private File generateSystemProperties() throws IOException { + File tempFile = File.createTempFile("system_props", ".txt"); + try (PrintWriter writer = new PrintWriter(tempFile)) { + Properties props = System.getProperties(); + writer.println("===== System Properties ====="); + for (String name : props.stringPropertyNames()) { + writer.println(name + " = " + props.getProperty(name)); + } + } + tempFile.deleteOnExit(); + return tempFile; + } + + // 生成环境变量 + private File generateEnvironmentVariables() throws IOException { + File tempFile = File.createTempFile("env_vars", ".txt"); + try (PrintWriter writer = new PrintWriter(tempFile)) { + Map env = System.getenv(); + writer.println("===== Environment Variables ====="); + for (Map.Entry entry : env.entrySet()) { + writer.println(entry.getKey() + " = " + entry.getValue()); + } + } + tempFile.deleteOnExit(); + return tempFile; + } + + // 添加目录到ZIP(递归) + private void addDirectoryToZip(ZipOutputStream zos, File dir, String basePath) throws IOException { + if (!dir.exists() || !dir.isDirectory()) return; + + for (File file : dir.listFiles()) { + String entryPath = basePath + "/" + file.getName(); + if (file.isDirectory()) { + addDirectoryToZip(zos, file, entryPath); + } else { + addFileToZip(zos, file, entryPath); + } + } + } + + private void addFileToZip(ZipOutputStream zos, File file, String entryPath) throws IOException { + if (!file.exists()) return; + + String entryName = entryPath + file.getName(); + ZipEntry zipEntry = new ZipEntry(entryName); + zos.putNextEntry(zipEntry); + + try (FileInputStream fis = new FileInputStream(file)) { + byte[] buffer = new byte[1024]; + int length; + while ((length = fis.read(buffer)) > 0) { + zos.write(buffer, 0, length); + } + } + zos.closeEntry(); + } + + // 生成系统信息文件的方法 + private File generateSystemInfoFile() throws IOException { + File tempFile = File.createTempFile("system_info", ".txt"); + try (PrintWriter writer = new PrintWriter(tempFile)) { + writer.println("===== System Information ====="); + writer.println("OS: " + System.getProperty("os.name")); + writer.println("Version: " + System.getProperty("os.version")); + writer.println("Java Version: " + System.getProperty("java.version")); + writer.println("User: " + System.getProperty("user.name")); + writer.println("\n===== Runtime Information ====="); + writer.println("Free Memory: " + Runtime.getRuntime().freeMemory() / (1024 * 1024) + " MB"); + writer.println("Max Memory: " + Runtime.getRuntime().maxMemory() / (1024 * 1024) + " MB"); + } + tempFile.deleteOnExit(); + return tempFile; + } + + + private void setupModernButton(JButton button, Color bgColor, Color hoverColor) { + button.setFont(button.getFont().deriveFont(Font.BOLD)); + button.setFocusPainted(false); + button.setBorder(BorderFactory.createEmptyBorder(8, 20, 8, 20)); + button.setBackground(bgColor); + button.setForeground(Color.WHITE); + + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(hoverColor); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(bgColor); + } + }); + + button.getModel().addChangeListener(e -> { + if (button.getModel().isPressed()) { + button.setBackground(hoverColor.darker()); + } else { + button.setBackground(button.getModel().isRollover() ? hoverColor : bgColor); + } + }); + } + /** * 初始化Log4j2 */ @@ -316,9 +768,6 @@ public class AxisInnovatorsBox { windowsJDialog.repaint(); } - //public void execute(Runnable runnable){ - // thread. - //} /** * 重新加载窗口 @@ -394,7 +843,8 @@ public class AxisInnovatorsBox { main.runWindow(); } catch (Exception e) { logger.error("There was a problem starting the main thread", e); - main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + if (main.ex != null) + main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); main.organizingCrashReports(e); throw new RuntimeException(e); } @@ -407,9 +857,11 @@ public class AxisInnovatorsBox { throw new RuntimeException(e); } }, "TrayThread").start(); + } catch (Exception e) { logger.error("Failed to load plugins", e); - main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + if (main.ex != null) + main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); main.organizingCrashReports(e); throw new RuntimeException(e); } @@ -418,8 +870,10 @@ public class AxisInnovatorsBox { main.thread.start(); } catch (Exception e) { logger.error("In unexpected errors", e); - main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + if (main.ex != null) + main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); main.organizingCrashReports(e); + throw new RuntimeException(e); } } diff --git a/src/main/java/com/axis/innovators/box/Main.java b/src/main/java/com/axis/innovators/box/Main.java index ad5e0bd..21c9533 100644 --- a/src/main/java/com/axis/innovators/box/Main.java +++ b/src/main/java/com/axis/innovators/box/Main.java @@ -9,6 +9,12 @@ import com.axis.innovators.box.tools.FolderCreator; import com.axis.innovators.box.register.LanguageManager; import javax.swing.*; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.OverlappingFileLockException; import java.util.List; import java.util.Map; @@ -16,11 +22,27 @@ import java.util.Map; * @author tzdwindows 7 */ public class Main { + // 单实例锁文件位置(系统临时目录) + private static final String LOCK_FILE = System.getProperty("java.io.tmpdir") + "/axis_innovators_box.lock"; + private static FileLock lock = null; + private static RandomAccessFile lockFile = null; + private static FileChannel lockChannel = null; + public static void main(String[] args) { + if (!acquireLock()) { + JOptionPane.showMessageDialog( + null, + "程序已在运行中,无法启动多个实例", + "错误", + JOptionPane.ERROR_MESSAGE + ); + System.exit(1); + } + FolderCleaner.cleanFolder(FolderCreator.getLogsFolder(), 10); LanguageManager.loadSavedLanguage(); - if (LanguageManager.getLoadedLanguages() == null){ + if (LanguageManager.getLoadedLanguages() == null) { LanguageManager.loadLanguage("system:zh_CN"); } @@ -28,7 +50,7 @@ public class Main { for (Map fileInfo : validFiles) { String extension = fileInfo.get("extension"); String path = fileInfo.get("path"); - if (".jar".equals(extension)){ + if (".jar".equals(extension)) { SwingUtilities.invokeLater(() -> { try { UIManager.setLookAndFeel(new com.formdev.flatlaf.FlatDarculaLaf()); @@ -38,15 +60,63 @@ public class Main { ModernJarViewer viewer = new ModernJarViewer(null, path); viewer.setVisible(true); }); + releaseLock(); // 释放锁(窗口模式) return; } - if (".html".equals(extension)){ + if (".html".equals(extension)) { MainApplication.popupHTMLWindow(path); + releaseLock(); // 释放锁(窗口模式) return; } } AxisInnovatorsBox.run(args); } -} + + /** + * 尝试获取文件锁(单实例检查) + */ + private static boolean acquireLock() { + try { + lockFile = new RandomAccessFile(LOCK_FILE, "rw"); + lockChannel = lockFile.getChannel(); + + lock = lockChannel.tryLock(); + return lock != null; + } catch (OverlappingFileLockException e) { + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 释放文件锁 + */ + private static void releaseLock() { + try { + if (lock != null && lock.isValid()) { + lock.release(); + } + if (lockChannel != null) { + lockChannel.close(); + } + if (lockFile != null) { + lockFile.close(); + } + // 可选:删除锁文件 + new File(LOCK_FILE).delete(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + // 添加JVM关闭钩子确保锁释放 + static { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + releaseLock(); + })); + } +} \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/gui/MainWindow.java b/src/main/java/com/axis/innovators/box/gui/MainWindow.java index 496fb3b..77e161d 100644 --- a/src/main/java/com/axis/innovators/box/gui/MainWindow.java +++ b/src/main/java/com/axis/innovators/box/gui/MainWindow.java @@ -36,8 +36,6 @@ public class MainWindow extends JFrame { private final Map cardElevations = new HashMap<>(); private final Color CARD_COLOR = Color.WHITE; private final List categories = new ArrayList<>(); - private final boolean isBackground = true; - private final boolean isBlur = true; private SystemTray systemTray; //private TrayIcon trayIcon; @@ -62,7 +60,6 @@ public class MainWindow extends JFrame { categories.add(category); } - public void initUI() { setTitle(LanguageManager.getLoadedLanguages().getText("mainWindow.title")); setDefaultCloseOperation(EXIT_ON_CLOSE); @@ -78,13 +75,14 @@ public class MainWindow extends JFrame { mainPanel.setOpaque(true); mainPanel.setLayout(new BorderLayout(20, 20)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 30, 30)); mainPanel.add(createHeader(), BorderLayout.NORTH); mainPanel.add(createCategoryTabs(), BorderLayout.CENTER); + //mainPanel.add(createFooter(), BorderLayout.SOUTH); 底部菜单 add(mainPanel); - createSystemTray(); + //createSystemTray(); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { @@ -93,47 +91,25 @@ public class MainWindow extends JFrame { }); } - private void createSystemTray() { - if (!SystemTray.isSupported()) { - logger.error("系统托盘不支持!"); - return; - } + private JPanel createFooter() { + JPanel footer = new JPanel(); + footer.setLayout(new BoxLayout(footer, BoxLayout.X_AXIS)); + footer.setBorder(BorderFactory.createEmptyBorder(15, 30, 15, 30)); - // 初始化系统托盘 - systemTray = SystemTray.getSystemTray(); + JLabel version = new JLabel("轴创工具箱 v1.0"); + version.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + version.setForeground(new Color(120, 120, 120)); - // 1. 加载并处理圆角图标(修正图像类型) - ImageIcon rawIcon = LoadIcon.loadIcon("logo.png", 64); - Image roundedImage = createRoundedIcon(rawIcon.getImage(), 16); + footer.add(version); + footer.add(Box.createHorizontalGlue()); - // 2. 创建支持中文的弹出菜单 - PopupMenu popup = new PopupMenu(); + JLabel status = new JLabel("已加载 " + categories.size() + " 个分类, " + + categories.stream().mapToInt(c -> c.getTools().size()).sum() + " 个工具"); + status.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + status.setForeground(new Color(120, 120, 120)); + footer.add(status); - // 3. 创建菜单项(使用标准AWT组件) - MenuItem openItem = createBaseMenuItem("打开主界面", e -> setVisible(true)); - MenuItem decompileItem = createBaseMenuItem("打开反编译工具", e -> - new ModernJarViewer(null).setVisible(true)); - MenuItem exitItem = createBaseMenuItem("退出程序", e -> AxisInnovatorsBox.getMain().quit()); - - // 4. 构建菜单结构 - popup.add(openItem); - popup.addSeparator(); - popup.add(decompileItem); - popup.addSeparator(); - popup.add(exitItem); - - // 5. 创建托盘图标 - //trayIcon = new TrayIcon(roundedImage, "轴创工具箱", popup); - //trayIcon.setImageAutoSize(true); - - // 6. 添加事件监听 - //addTrayEventListeners(); - - //try { - // systemTray.add(trayIcon); - //} catch (AWTException ex) { - // logger.error("添加系统托盘图标失败", ex); - //} + return footer; } // 基础菜单项创建方法(解决方法不存在问题) @@ -347,6 +323,8 @@ public class MainWindow extends JFrame { title.setFont(new Font("微软雅黑", Font.BOLD, 28)); title.setForeground(new Color(255, 255, 255)); + + JButton settings = new JButton(LoadIcon.loadIcon("settings.png", 32)); settings.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_BORDERLESS); settings.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));