From a2a7c6f9a57ab92f2f6293aa4d2a4fdb43d6be74 Mon Sep 17 00:00:00 2001 From: Andrew Ward Date: Sat, 22 Mar 2025 12:18:40 +0000 Subject: [PATCH] lots of ux improvements and small bug fixes --- .../presets_manager.cpython-312.pyc | Bin 37857 -> 38348 bytes utils/__pycache__/text_to_mic.cpython-312.pyc | Bin 68610 -> 69544 bytes .../tone_presets_manager.cpython-312.pyc | Bin 26016 -> 26011 bytes utils/ai_editor_manager.py | 2 +- utils/presets_manager.py | 34 +++++++--- utils/settings_manager.py | 2 +- utils/text_to_mic.py | 61 +++++++++++------- utils/tone_presets_manager.py | 4 +- utils/version_checker.py | 20 ++++-- 9 files changed, 81 insertions(+), 42 deletions(-) diff --git a/utils/__pycache__/presets_manager.cpython-312.pyc b/utils/__pycache__/presets_manager.cpython-312.pyc index e4f719777558e451b52138c6907b5daebdf0ec9d..93971626901c965c4fcd231a68913a83e30f3f45 100644 GIT binary patch delta 5925 zcmaJ_4^))bm7h2N7#J8}W?EjFqS4NEt}Wlrm4Mc4tX;DGQ(M!&+x9yv=^Wro-pdKV@-}Hl%Wy zNiMcK|pOW3b7Fq0h1Jpu2C#})MUc{m)_|A74tY*Dw2Hw`s+((U8gTZR<)G%Aff zA2u3ZkAasHtnjQkNqb6la3|bbYk_SwQShEQ57t{U;J?fp*giPBJ{9&_erznlwRkZ> z3FKPO7^<=BRP!}(&6>J*9notM;j4&} ziQv@8`U4(s?}4DK?&=kS+MF8Rh(mlelqW4ssUt2mUrm%|rQbyTS{O)Ll11{JOg0S% zx_Q6P*WKUO=k`m;KPTa0(o9?~@&wcf_A#CZk0m#-XW&=K6;b&}YH^l=!4@)+in89< z-+yRmfVaar+pBCR)GgVPn9%Qcb-VqC-2s=f!Ek!XW|j-LmaJfT5S>!0UryqAxF*G} zO-Y+Eq}?{yXAJfqWL(kSE~}p@tG{VzxT}YbjI~R}g59J^q)}gk|3BM>@T@AtctHqe zDw1F(BaNBho;^7>z=r4koND+Wv$nW}_UwpP>h%P9B2ME;2$$5H%#?MW!ybQ7vDS{( zeml#le-Q@)CGc97!+ck-ic7p3rK;M-rjyFXD|mjm*nWzczd>?HnM;h1Q@;V;b}UN} zBANGrIBoVCHVNyqzs>TY*q##pF#8dfaEd0(OW;nZ&0Ugv8i{z2Bth{V5*r{}?RHcQ ze`PDYkZXmB+&uO-@Oths6lpq>5^lupm_-0Bk8pH_m$;uZF>b zK_eX`f?v^FUn#c!eEhOkqCeK50R;b(?0W;ADT1>gX31% zQXI=Z!ilK{_bawrhH|cK-?`$Ss>Nh}k>)la%pOH>>ST?7sE_Z2!BV^VF&Y!f&T2{lBT^6(WkBF6w;V%(fA-GELR|pU8z{lkh`x9(kegy4!Yx&`l zoj58Ry1ahL<@WjT*ml#LFo9TC9NQS)9-{1lJuB{+NX9ECq{IyQ zBXW2L(&rbQpQ=_d`2NZ)oO`u76MnaHP1)Rhq4ygkYfgdJXwLtkfLg=gsR}xXS1Weq zER^uKH0$e^W?JZ5l~t`=e2q|;JBXc@j(DqBm24N@+F4txn0*{6BSp};vWU&XXRB!E zeU(*e_IId23S3{^U|V!VBy|r>DS?FQbXZ+w#{1k{m1d*G@wQUbP@-cY^)|urs#Mkw z->u4T>LkJeg8c+;0xN>73k2Okk5ec1gnx@jnr?TH|3vhWGb@v24oC0UJ$H)JH7<7UpC%Oju2ZnrThid=>swWtT zs6zHEQib#!S-MT(+UkbPbr~!J)~q{$irtG!F`5l3)#Dg7dsU-wwb&N^VqLkqiIfpd zGKO>)R8njx>VoQf+DW>{*qACv;Zn4aKBNmpjo_t{;zlr8Ptx_mHfoSeqtU@M*j`tT z3p#2oNikCNRD5Kdsh)IbRlzKntjl8wFjJSo9Pn{WIv6*k#V1bEWg#i?q4DjdxRht?98v_Ll@#~g~6lBaBu386$O4gX@K^r?(V zy)rgx4w)A$nv9ELX)={Esa3{NfAhf#(%+F4ij~AlJ#1Xn!zBC3=!ohMxUw7%ab+*$ z3eMS`AmuEu+Y+*n3b8@DA)*~z1%ve#D^e3Q+w*wn&@ z)5fr2p*`ij~I*X8~S}ief~g|oo^uCe#B_L!t=&H@P{-viNXl zRH#{Uge22}keY3`>vzx8@1EYXcY1%<&H8Rd_;-oBo?sIu(%mR9c5Axr4@3}BBeen% zgitmLN48SRzOZ$3Y%7u55L%phaCd7;!Y~mY#Ppqz(vlS|>jt>jALLI!RZC&sK4g(i zz1%C|#`F)kdohSF$Wuck;WV6T$!YRZ_c?+K1f2u{g6|QC+u2UNT?kH_&{vL^ya8p? z4{&$D6HvVO6ZoQK=cB?&{{xxjsBSlxTwY0WuDc}U9?@fuaQDD~M{)%{M}z!6(LWRX zJ?_IUZ(lF}oJfB{2-pxh;e|)6rbwE67bzol*xqc{7tzLF3;*Gf1XdVrnlPOYo%g@e z^oH@u=(LF{`Oo#LC28ktUTJ=#X{LD7&zH{>ZT*d{B^Vm#+qB{5TN7C;DbH^akRs^%^mc@vFZSZWPSLJJ@_P)bB5TQBE@sD)YLq@Gzhi<2 z^^Pib2G;J7^yF>b8o1tL4PV=FUyW~mKibu9;$IFiA? z+5fSkhZ?qftl=`3ffZ5xB5UefHp+T01_d6(!e?IWqFnzG*4EZog-M*@@8MgW8?OXv=5pEw;oNgY&MZxZ%WfmqWv{!PEFbQ;f8RiR-4fa0c$_239@!*$ zy84H(Dv?|P_hC<@<`WxC8@}ibh5r#^x^vmTLuq#hik*9D2>-C#%nGN;_!+V<&NblS zJ^j2-Nc>+f02T1Ql+C^Z=GihY<8$-NICJ5?rT15!w$CX?O+ok`P*)Y2ugfB?{eLg;iX__ru8 zSzYjfKbslD>i#jca&%))B!{0He1)-Ms1ICAT1MwkM<67WQV$(7Sh{51E0l^<$yem$ zdxOoG6E6kNFqcM## zwu%U=Aw6W*i*$A|To>BJ(r8Kpf0QP+5$qt?Nze{2jnws9o=M4n;QTXkN%s2|kvaTM3`7rMUHkQTy z434o3z1aA7VB?s*z85FTM!FWRuAyMC-_O?*g$?svB+^6BLqPj3!dxdt5Nfs9#9NYV zgPAcKTpuf7ZQ#-xhpL-;0@9(5-p^XSfrxm<@8xejShLmy9}Q6Sk6gtP}FOM=1hx5 zQiot-XGR5nWu%ZI+OTF=3dGD&@^We8xg^fsXuM+xW&?u^D&c zR0&I!O6mrRz|irR^rPk<;Exh9ScB66m(P}*SV|;2K{kO1hZEF0MBpPBBsfkGB6yR4 z{Di+tAo5Qt^;F~~A5m|X;Ex2tsVZrpiyrq-?-+rZ9@nxaL=km9rDxijODaWkk%6h+ z-~`e5KX4i0r0Skpqchx(ap)ZP8(2Tn6@S*H(d!cLC&2UP%A&fMu8rMqgj?sfX5TN2 z*X4hn9j)8J6qzK+nIK064`Jo!;e0>TKn5F!z2I0;jatcC@r7Be`aEe#(M(+aFAZz@ g`lTVCr-r|X1NcuBD1s}Ho!D+7(*t6gA$oOL7&vH*NCSO}?5zow!*U^)ZJg(n z5|6N5Ns<+NI6GzyK;w(9yffz-eYe?&gkD}kpsqb#*!jOOcn-b z%->?yU{%aD!!=74WLh#~9~v(qFC1^! zicuZzC0GQ{COR9=&Sr0V4$CG18e%XSu6Y?eG{Z+Y+!EiWmK?yfQ(Y} zViML8c{jsp1ar=ElMn)1pG>tC;S`_Jg&98?hW^wP7|zLLgOK1(&6I;m40aP=SSPWI zqzrz%EDZK-DezEx1|0V}m{!}fCJrvQCqu;=2b^4Eg70=ZVC{s>VbnV5bi)Si&trt| z<*Xf3V|hRhjs$#4us6V`BxGyySXA>+Q0fdQJdp-UK~Q75{IXwBIDd$0vHlJvzjz~RP(5vp_J3ZKJ9 znInwrZklzmi6>j1+VkX|Z?&A?eRlWNl*O+nf3#xD)fHPH4T=|j?94xJJ8S#MS$4%) z_Nx0;<)dZISC%z@=xjN*?pkd2jd{A2TiNB5#mAQN1>nldh&-3u&ytpr4rIFvjDMZV zb>MU@N)Xzz;EblQ*R`6Rhcm86*n)^FuZyjJjF@M7^CGM^;pWZ7U)2;;0==?krpJ+h z+m8flZa|~R1_Y-QO#qkORqQpe=O1DV;L3@N$hrL2^k&-cyb64U?hRDDout`kv%f9S zQ_>=S(4>OvG_@yd?V1bCxRPPkmH0|{ukb+|ZAl&^*ar1Q%WOic!&D!GV?|!GSdnh{ ze$hg9De_rS97Cn-feeT%9$L_gY-;Sm!C+v>C%5yyo*pzA36RMTr&sd;yi%OY{vKZS z&bPF^TzJh=j>gs`+y@)H-mG)T+r(c)%w7ah5p(5wqEq$7pOxW z!qhhl_b7}tO$=Qu_JqU=H# zSp&{WFRU%K!fz`q?7zTN;YL}W3V-SMu^HD+h_nubqC)u&q|az@Z#nueb@022TojbP zWY^MZL1H#PAfeN0eUCc-f7H_dj}AUtg0`MmkpT@A)kSk9{v}EI<2uE`drLDbwWwzh zlj1JwNm@mBy-zR`(Ul}wyWqhU z6-`#$WpWbMe>bkXyszz}ef-Kkepy!jX5Rp(@h|9k8F7o_!9%5b1Uy18vd95x#NwJR zHF<121h-ZcHu#9ElVC5weu88K)g&u^CEzg$GxDzy$qG zNGn}TA9-ZuICGC++uW!py3IrqYJ3MgtKG~2jjO%5nCKpniPZzFjsFQYHhHX^_Bel+ z;O7Jx1V;!&;C+}%9}ql(peFkI`}zlZP+=d<5TodHv=xfqG43HaSmk9IaIR_$$IZ56 z=x@YCs;lqU!*^ zfW^b^+H4yIKJj%s;l@A;JYAb^w_l_c$8Xdgws*Usrpu8LAGS&f_?I}DbdjuxAJbuL z0i0dvNON4IU?OPBT#4AT&@LrUrbIOuO$aA+7izq7Q7M8S4P`l`RB4_xZ!+zoQEOzn zN9kD9cP}C(9P!vTXEKlKx=V#}u~Ix48`ZN;rq3v!sN_xzXDtpVgcGF<{Ig2)Co?aa zHOZq%;iUgtkyKP9OUjz72(nkuTwU4W>ESxqFkXX!RWg5*t-o< zmms<37{n2F+*^;RdAgTGOS8XdE_+>;QOcWiLt|Z9%JSK!Xend^e_g6=G(KROQ0 zsSuv8&oFqNje)ZIG`L!y$Lhr1w60Hvf2()oOU2RcHtCI)m~MDsyPoOV^`nL%oo5lW zu5Vy(!rAqQyyX7;DngToi9ms=roLn`f1l_gY|(aiij;8uhWl7KJhq{BjBh~V)N$ew z2N*>d{wM*tI~REbMJ~)_O_*OPU3??frbv`(49S5Zj6+`HEGAe=P)V=|p`L#O5w)R% zy#><`T0fD}&M-o7qq}$wk@|Xs3(Hl)Gk1UB!`C4t-mku&5!4Nzk`xJ_eYtZ`!^vDyqN7KRg|u_&;DD zndT=JKc@cuawpg-p$zwLfSV; z!a9O_*s*!n3Zb1|jgtaBftmQJEv=sahWLc^J5D2{j?B(=5ONynXs>PDxby+)(2UUJ z$rnPn11qW-%@+tsxR_YDJGQsNn~k}8ejKhh78mRx_V`X7l+aXt{r*l2>T?b#h2%dD z%bMH`T~ws(nExq(ILSDbo+l6o#x^Q#NARSHS*Ug?C~M2m#r<+X*7ofbyx6pD;|XH^ z0zr*w_jAb?l(aqfFGT+>(PM|WzrQ~qiQT~emFPDFe}{k27wqliH;Hr$)@^ZWY2;<- z-cn#L#CR^Bi=5t)z#QqBPglLX`t?;;y!G!UUh!`FFs&i-!Pdk2)Ly-=XgiZ*QNksU zbxVcy(h}pAib#8NB5Nk4_=f~E0B&`<1maE?bDXsR%{F>qn{iClNb?X=;ug|@&Kf+g zMb7=RmX+)n=vyVWAkx`tGcXn89orLBQ$G*lZI7}6kA=J8;~lFUJFy~LqMfz=3wFBL zsmO+%2BYORbKYiFyfrlMU6MtcMf0y;QR&wR=+k{%l6efgu(vorpU7V#jHGKBd-TRr zLe>?geFJXpy>6u4N;kmB7yB&COA4umx~6riS#wEDc4o%9Sgk}-v>ksgbKHe*&{lOie z9L`F4?BC%XX%nuEJz!yp=ds(|E5;Hi>Tv1*n?XZIIr1Ftc)~nZf;^b@i1z`CrK+{f z9}3}BbkNW1Rd$fKAyHiOL@eQS5{e6KlP6RB^4&xs|I=87^JG!=2tgvj8l0_ap!@HC zQ1w3%RBLTbbDa;4_pUWRLBvCFwRbC<0Cy-aj#iEDL!f;L4}>;pe&L5d3*|9mb_7+STo^!4}P z!vnrZC_$wsz-z!a=1KfLiKOgbHTDE$g%80qV>w$Xu&Smyi~_?Vs;UVC{SxKYK?#ot zzkEPeV}^pEjy~T(u??cNVGNLhtUWz>Vl@YSA7aLx#S$u{+Q@x;ZQ_-SR}qB`^Hx%| zji8;N4DKIK!B?Tq@pY^*GCAI5W-X9%bZcQe@#8^)ipr{~_ka}S+)gyp5XZ*`)yM;W zi96utm)fBy)LK1LwU zT1J6J!lxPv2o5q74aOg)5slJ7Z+|oloFMY!2(w#}xL4wq_9jF4F&jGAmcr<+v6Re`|R%)WGYi?90p|t5nGVThk_=f0n zXjh|GFa*kUjE?JWB*7;qQ(@r5ZuFQdC%(Zp3;Cp?P_PN7C}#c@dWght>K=N04v~{C z_G7qq@=!JxNe1K3A|Fop?`QzwX{_Gkgh!!dtbj;Pf;<8dNG7P%O>lsqpCC*iZkO*+ ziEP6!6NqR%pGsd6d`j>c!F2*LfhA-zKUH^7=^#N8RaY`ht2A%@9P1Z!;x?^a(dj_u z1oQB}{35~;-A%p0WVvO{HC5lLWj)Na@QXc$7*i{|l>`r+S{&nJrWSUq7G6KqnDs@m z-BhTFBO#syHAXpr2W)`zy-;{Mn>`G5r(G4xQ5V%HUK+)K&ya59`$CD^mesv|(m+q3 aia&=9_)jN$;F;5T_BtCYyrm-)-2V%%jE9H- diff --git a/utils/__pycache__/text_to_mic.cpython-312.pyc b/utils/__pycache__/text_to_mic.cpython-312.pyc index c75ce4afef0a1ba61e5bc1049a49db61610a3322..097fc590e0980de7ca710757ef819716369e190d 100644 GIT binary patch delta 8386 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 JI^y3-{|B`YGPnQ$ delta 7496 zcmaJ`30#v`w$IH@0)#~nlqDb_Ve=_&R7DV3RY1k6v^E632tf$=C4i)HppLcM)H*%C zPJFf1PVIB4^i`X-E*)E`UEJ!x6i1D=74%uPV_jO0B>YXrelq^1 z;BN}@ctkN<`vB5S!u}-e?@=TK2-9#N=Sj&jRz7{M#E|E{q#^|Is!-n!wvCY?5($&IwyRjIyhFB43X$icp!MjGAVKbA9g1zz+ayi~ zOclzU(D-hMe~0Rxi4dlSHSW;gn(zVRUw>;tp>axT1K^q^Sa%n<+F)4f6U?-*K@|!G zJ*cSfHrZ`0xT3zKsCQ(!lx*=T?B|r;rLYtg4q^Tf_%!kuB;r0EvH>1Cr|d2sGU6c( zaKfLnLjE%o`2dqZr~ED^a?T{k2|IE_{RS!G^iBjj;mz^)_>|8mhM0bT5Z;6mlo=0 zm|M3>#ZBm1@lOa2U3Q^9r=hV`pDS4G7HhRbSI}TzVs6#XHQT9ga|F*aSxvaQtifv5 zmx^Ya*$zh&BFc$}N8M}^EvCvkGw0?}m)4nDD@|2P96D<0XPRtweRh*zY49itt&L4~ z$B694#=2HLN=3Go#-=)x-O^yy+Z*(JUSDQjW{14QNfR8w{fZP?ZFaG#ipXpZZGlBF z>!+ElR$Ta*{oJZG)8W`(P1EYy+5NIONMw7*8Z!lU& z8+gx`I)tFYfrXdEL|Ib*W=|)DNCeha6YObgN^!5;OLVJ)UFi&N1?t zihE}s?#_9b&ny}=Gi9Isc)qzi-^^zggCZr33*ggWrJIq!{8s^SQpA#(a$lWG~wRsteJR!fM0Jdj_!27=oRyx%}VMh_j z^Ubmu9eTJrVO(&b5Y{pCcFtoGVb=2S=L?3)iiHyB%8${N3MIEEMZGW^rxbIZlGHv3 zF}h%A*QwO&Bri*shg+lJR(|;1Q_x&sP?ZVuP{4z*sldqQLwim-WE2ilEf6AvNFfi( z3tQPj2rU|+Di22|2oJ&Nk3(d`g~4MF)7Xdzq2wuvaWoR~Ki(U2r?+T%r0@tVD;l9S zI)|^52o*2O1QTp3ie{DYNl`wl0{e0kgs#3h^3^_Cild61xJwmV{0{M+0jJ&J(Rve3sfI5!-aP z@yWY*aLzze*CbF@I!1a!0#BBX4f>82$p;DRg`=gXl~;(e54O+N8-Atc0s_kFA}zQ$ z9l;>=C~M4?>KeO9BnCMs=IE1dD{ujaJaVhe+;W#1+!U@xFOU`8QF#xj%@Zh^s~SYXXtSF{J7Pnl_%1v(H#(0b8dQ9x#}7#` zjT=RiU}>_6O3VaYNsoGQwGsW@AaZYUi%{AbTtmK|pgmfQ&TX__p%5s@9*G(q=CEt-KhGHO#yVB0$hJ&og;2->BODW}q8Hax#{63c<3OWWCQC_!g2ccXY&%GSao zO(WP5SkW|+jds6|s60Y@Aj0wHayDV(m=>va9dUSx;ANQ7Iw3%$=6V83reZ0qY#pWC zK>Y;R-I~FsxW8)+lcp}m5s!aKX>M_Lp%KdxE7ymTN<>57=DUG4po0m154Vf>t3bdjR*#vN7`WXD67qOv$a_~M5-Jn zc#|l0QA>;9@iEz!;B}8>j`#}AY$Bl2Uwnk1l)A4G{0{;+Tiv@u$ON^hP4;4Uaw%!4AXPC(_w!_mL;; z3ic{wKby=>LjAKYrUS+5N<$VcZY1HU1kX^ngJ8hYbn1?SHLJsv+}_#nzpM4E3;wz~ zK8bAigz{pF*HOm$raHT&vCh2AEN~YYG+xIXhN$OiCnq4ejX0x${eRxW^%+h$A_iT> zO_lW)yU~t!vysXuv*>bv^xSwE`y2fH{7046c`drzBg%3ov~Bc=ivNvp$xcf~NKH?38=m`W-6i&kTw;tzvy} zY*RwnO(Ol7fJ^#;T3ktuXf_FpMN_@m<~?b(iF)M?MC&}V31YEE2 z)FS0PJ{FtNgtauv2qMNL)f?wOLERhE^mn9*d>^T(<(uf;!XFqMePcMQa$kDmmK5b( z+@3pz3;2lyyidTzlXaMH_;KNUPzv(#G8qOHJ5n)PSMPXBsys<+PD0+>W7;?)Ga1ff zwUSy@1gAI+!JUA;eHOo>(K85lAE|e7nIn84)b4o+yol$|Mwc8Gd)lBiW4pqWdbI8z z-aaS8({p-PYTFg$SSDU0<^ia>0k1PsgzI%DhQwPm&!fj1Y}A#JKjj1p0!9!>z;oh& z%gI*;wbw%zupqE=X*!0&-cKIFj~TuDqjh0IxIF`9^FOB+@;{w2 zRQo$^t3;42$KMv#B3UL|C~0AaVX*Gg*fxG;MU!8zqA3o)={ySXg|oQf0sY149TbPb z? zqmkxnDdy36U-JDY&mxEvi=r>V z3KCgEA}vJey=n0A$O}JlDv|KS=8JR{6uJF>-T+RA=EG6SiF=J+-JJOWXe9$Hv?|<#42wQ0}&FA>1U8e9vxO} z$hsb@3!}~AFnjkp8*TIW;&&$=Xd+g+9&L+gv77q?j~mECgI{N};g82+qquIAT6rG5 zC&Ls$_pwNp;l6V0gbbf+2TsO?=!oPhrv_9567Esu&FN!!%6} z;qQm`cCW1?anz9l8%_^{A3Q<$Le-o))HYCGRFL6+M;ed6T{Ky3RidSlf7TLD5IY|F zSv0K_%yn404yxClCIbH6;zva!PLzYal>)zSeFkn5zA+vRFV|r1X+spnD%aWOgDWfg zgEh;m^;~%IbTk%Pdrl`xStp$RGKDolz*ny+Q%FE6?D;C6*+F{dBtFhhpNV42;O8^@ zgN`C2@8hXIYn!2~Hy%G8-|Ss^-}U5%XZjM^WAJw0J3%LLA$pKo>#a)R(X&&PkK-L+ zi*fB>YzXw6?F_3y;l+5*bGjvDZ-rN#H_pvhK25}FL>vOq|M$0qabzE7#wlxwlCH^gmvqX32txOh4iMSZOHL#A~SCrnwqc23T z5o{(dF|g4u)Ut1ed5}{vUd23mDR8&;zaI6j2F60!B-bj&;#sDvgRv7)r-)j7hV=LY zf(fN|3p8;)au&o&U8m&C%{pDrDOd_C+xZs-)3Kr6vqrk$Kh(vm$~&$;B}-H;z-NJNB0s7- z<5aAh1@PM48*XF-xD-Cja9{gAaS$kDoo3XOQOQ8FF1r!!p|5LRsGL zxZA1KMZjx@B5E}g#F0JC1pFDlo5qe1yh3A}2>2s^5se81iwTa>1m$k=G68>5s7O^F z0mG>EuA~hyhMK$-rm|T~qHY=i&$hf`;qfwo#?lFR1QbzgF2S807b~f2CU6t0S`O5m zNGdc^i@pQ$|6mYTU~823$yP+uGYKXUOeUB@!1wY|V)G7x(^aWu>8Vzn`sYf?4SAMS zQNXTGm&+96uWK}lI(9uQR#DHc7ci+J{kmGJ7?whdufY>m{V_@m-` K3GayU$namwj3*KR diff --git a/utils/__pycache__/tone_presets_manager.cpython-312.pyc b/utils/__pycache__/tone_presets_manager.cpython-312.pyc index 20403ef64b951b8f0c89da44e782a2ba6efc310c..bf32b7557c3d7710f14e1a62775a5ebab1d02611 100644 GIT binary patch delta 204 zcmZ2*nsN4NMy}Jmyj%=GAiZKESArm`Xo|!d$;tVGwTx1e-wJv&N>8>FDrS~hBRhG$ zP%OX98oAZXAk_>Ej0`FAo27+w85tEOcZ%2pl_*Ybv=N>BKtzmHsfHoTY4SlvVP@qu zDw738O<7feB5rVzMA2AgwKeLK4~hn}0_oLEldXm1CtHY#uxbF+`Ak-17M{F-nTJtx pa-rBV@n7u9X<$&K0kpS@UD?3E+#WhPq+6*J4Ok(<0; zD3)J#jr?k6kZJ}7MurrH&CntYH^m|10w>SRGt zQ&u&gh#OoaQ8boWeT~NCgQCH#KzcRPWNRV$$rfTFteQY|K9d!hg(ojy=3&&DTqw3o nrU>M=A`Ku>#jb2%U~Z9O{)=5X4GcExiJ#(S", self.on_window_resize) + # This resize timer helps batch updates during resizing + self.resize_timer = None def create_presets_section(self): """Create the presets section UI with accordion behavior.""" @@ -146,6 +148,9 @@ class PresetsManager: # Configure the scroll region to update when the frame changes self.presets_scrollable_frame.bind("", lambda e: self.presets_canvas.configure(scrollregion=self.presets_canvas.bbox("all"))) + + # Add a binding for the canvas size changes + self.presets_canvas.bind("", self.on_canvas_resize) # Populate tabs and presets self.populate_tabs() # Refresh tabs to show selection @@ -159,10 +164,9 @@ class PresetsManager: """Handler for window resize events to adjust the presets layout.""" # Only proceed if event is from the main window and presets are visible if event and event.widget == self.parent and not self.presets_collapsed: - # Schedule a refresh after a short delay to prevent excessive updates during resize - if hasattr(self, 'resize_timer') and self.resize_timer: - self.parent.after_cancel(self.resize_timer) - self.resize_timer = self.parent.after(100, self.refresh_presets_display) + # We don't need to immediately refresh here, as on_canvas_resize will handle it + # This is because the window resize will trigger canvas resize events + pass def _adjust_row_weights(self): """Adjust row weights to prioritize presets area expansion.""" @@ -313,14 +317,17 @@ class PresetsManager: canvas_width = self.presets_canvas.winfo_width() # Ensure we have a minimum width to calculate with if canvas_width < 50: # If the canvas is too narrow or not yet realized - canvas_width = self.parent.winfo_width() - 30 # Estimate canvas width - + canvas_width = self.parent.winfo_width() - 40 # Estimate canvas width with more margin for scrollbar + # Calculate number of columns (minimum 1, maximum 20) min_card_width = 140 # Minimum width for each card num_columns = max(1, min(20, canvas_width // min_card_width)) + # Log for debugging - can be removed in production + print(f"Canvas width: {canvas_width}, Columns: {num_columns}") + # Dynamically adjust card width based on available space - preset_width = max(min_card_width, canvas_width // num_columns - 8) + preset_width = max(min_card_width, (canvas_width // num_columns) - 10) # Slightly more padding preset_height = 100 # Configure columns to fill available space @@ -715,4 +722,15 @@ class PresetsManager: # Save and refresh self.debounced_save() - self.refresh_presets_display() \ No newline at end of file + self.refresh_presets_display() + + def on_canvas_resize(self, event=None): + """Handle resize events specifically for the presets canvas area.""" + # Only process if presets are visible + if not self.presets_collapsed: + # Cancel any previous refresh timer to avoid multiple refreshes + if hasattr(self, 'resize_timer') and self.resize_timer: + self.parent.after_cancel(self.resize_timer) + + # Schedule a refresh with a short delay to avoid excessive refreshes during drag + self.resize_timer = self.parent.after(150, self.refresh_presets_display) \ No newline at end of file diff --git a/utils/settings_manager.py b/utils/settings_manager.py index d6718ec..375f3c9 100644 --- a/utils/settings_manager.py +++ b/utils/settings_manager.py @@ -87,7 +87,7 @@ class SettingsManager: settings_file = cls.get_settings_file_path() with open(settings_file, "w") as f: - json.dump(settings, f) + json.dump(settings, f, indent=4) @classmethod def update_settings(cls, partial_settings): diff --git a/utils/text_to_mic.py b/utils/text_to_mic.py index 67a9639..1d403f1 100644 --- a/utils/text_to_mic.py +++ b/utils/text_to_mic.py @@ -40,7 +40,7 @@ class TextToMic(tk.Tk): def __init__(self): super().__init__() - self.version = "1.3.5" + self.version = "1.3.0" self.title(f"Text to Mic by Scorchsoft.com - v{self.version}") @@ -57,7 +57,7 @@ class TextToMic(tk.Tk): # Fixed window dimensions for all states - DEFINED ONCE as class constants # These are the ONLY values that should be used throughout the application - self.BASE_WIDTH = 590 + self.BASE_WIDTH = 600 self.BASE_HEIGHT_WITH_BANNER = 860 self.BASE_HEIGHT_NO_BANNER = 700 self.COLLAPSED_HEIGHT_WITH_BANNER = 630 @@ -188,45 +188,59 @@ class TextToMic(tk.Tk): self.menubar = Menu(self) self.config(menu=self.menubar) + # Get current hotkey settings + settings = self.load_settings() + hotkey_manager = self.hotkey_manager if hasattr(self, 'hotkey_manager') else None + + # Format hotkeys for display in menus + if hotkey_manager: + replay_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["play_last_audio"]) + record_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["record_start_stop"]) + stop_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["stop_recording"]) + cancel_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["cancel_operation"]) + else: + # Default values if hotkey_manager isn't available + replay_shortcut = "Ctrl+Shift+8" + record_shortcut = "Ctrl+Shift+0" + stop_shortcut = "Ctrl+Shift+9" + cancel_shortcut = "Ctrl+Shift+1" + # File or settings menu settings_menu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Settings", menu=settings_menu) - settings_menu.add_command(label="Change API Key", command=self.change_api_key) - settings_menu.add_command(label="AI Copy Editing", command=self.show_ai_editor_settings) - settings_menu.add_command(label="Hotkey Settings", command=self.show_hotkey_settings) - settings_menu.add_command(label="Manage Tone Presets", command=self.show_tone_presets_manager) + settings_menu.add_command(label="API Key", command=self.change_api_key) + settings_menu.add_command(label="AI Copyediting", command=self.show_ai_editor_settings) + settings_menu.add_command(label="Keyboard Shortcuts", command=self.show_hotkey_settings) + settings_menu.add_command(label="Manage Tones", command=self.show_tone_presets_manager) + settings_menu.add_separator() settings_menu.add_checkbutton(label="Auto Check for Updates", variable=self.auto_check_version, command=self.toggle_auto_version_check) + settings_menu.add_checkbutton(label="Hide Scorchsoft Banner", variable=self.banner_var, command=self.toggle_banner) # Playback menu playback_menu = Menu(self.menubar, tearoff=0) - self.menubar.add_cascade(label="Playback", menu=playback_menu) - playback_menu.add_command(label="Play Last Audio", command=self.play_last_audio) - - #apply_ai - input_menu = Menu(self.menubar, tearoff=0) - self.menubar.add_cascade(label="Input", menu=input_menu) - input_menu.add_command(label="Apply AI Manipulation to Input Text", command=self.apply_ai_to_input) - + self.menubar.add_cascade(label="Actions", menu=playback_menu) + + # Add keyboard shortcuts to menu items + playback_menu.add_command(label=f"Replay [{replay_shortcut}]", command=self.play_last_audio) + playback_menu.add_command(label="Apply AI Copyedit", command=self.apply_ai_to_input) + playback_menu.add_separator() + playback_menu.add_command(label=f"Start/Stop Recording [{record_shortcut}]", command=self.handle_record_button_click) + playback_menu.add_command(label=f"Stop Recording [{stop_shortcut}]", command=lambda: self.stop_recording(auto_play=False)) + playback_menu.add_command(label=f"Cancel Operation [{cancel_shortcut}]", command=self.stop_playback) # Help menu help_menu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Help", menu=help_menu) help_menu.add_command(label="Check Version", command=self.check_version) - help_menu.add_command(label="How to Use", command=self.show_instructions) help_menu.add_command(label="Terms of Use and Licence", command=self.show_terms_of_use) - help_menu.add_command(label="Hotkey Instructions", command=self.show_hotkey_instructions) - # Add toggle for banner visibility - use the existing banner_var from __init__ - help_menu.add_checkbutton(label="Hide Banner", variable=self.banner_var, command=self.toggle_banner) + def show_hotkey_settings(self): """Show the hotkey settings dialog.""" HotkeyManager.hotkey_settings_dialog(self) - def show_hotkey_instructions(self): - """Show hotkey instructions.""" - HotkeyManager.show_hotkey_instructions(self) def change_api_key(self): """Change the API key using APIKeyManager.""" @@ -401,12 +415,12 @@ class TextToMic(tk.Tk): self.text_input = tk.Text(main_frame, height=5, width=68) # Use white background for text input instead of the system background color text_color = self.style.lookup('TLabel', 'foreground') - self.text_input.configure(bg="white", fg=text_color, insertbackground=text_color, wrap=tk.WORD) + self.text_input.configure(bg="white", fg=text_color, insertbackground=text_color, wrap=tk.WORD, font=("Arial", 10)) self.text_input.grid(column=0, row=5, columnspan=2, pady=(0, 20), sticky="nsew") # Proper spacing # Add a status frame at the bottom of the text input with white background status_frame = ttk.Frame(main_frame, style='White.TFrame') - status_frame.grid(column=0, row=5, columnspan=2, sticky=(tk.S, tk.E), pady=(0, 25)) + status_frame.grid(column=0, row=5, columnspan=2, sticky=(tk.S, tk.E), pady=(0, 25), padx=(0, 5)) # Add right padding to shift the frame inward # Create a custom style for the white frame self.style.configure('White.TFrame', background='white') @@ -1029,6 +1043,7 @@ class TextToMic(tk.Tk): record_shortcut = "+".join(filter(None, settings["hotkeys"]["record_start_stop"])) play_shortcut = "+".join(filter(None, settings["hotkeys"]["play_last_audio"])) stop_shortcut = "+".join(filter(None, settings["hotkeys"]["stop_recording"])) + cancel_shortcut = "+".join(filter(None, settings["hotkeys"]["cancel_operation"])) # Update CTkButton for recording state, keeping shortcuts visible self.record_button.configure(text=f"Stop and Insert", fg_color="#d32f2f") diff --git a/utils/tone_presets_manager.py b/utils/tone_presets_manager.py index 1b992bf..ea0c429 100644 --- a/utils/tone_presets_manager.py +++ b/utils/tone_presets_manager.py @@ -103,7 +103,7 @@ class TonePresetsManager: # Listbox for tones with scrollbar self.tone_list = tk.Listbox(select_frame, height=8, selectmode=tk.BROWSE, - bg="#f0f0f0", fg="#333333", + bg="#ffffff", fg="#333333", selectbackground="#0078d7", selectforeground="#ffffff", font=("Arial", 10)) tone_scrollbar = ttk.Scrollbar(select_frame, orient=tk.VERTICAL, command=self.tone_list.yview) @@ -168,7 +168,7 @@ class TonePresetsManager: # Create the text widget with word wrap and vertical scrollbar self.content_text = tk.Text(text_frame, wrap=tk.WORD, yscrollcommand=v_scrollbar.set, - bg="#f0f0f0", fg="#333333", + bg="#ffffff", fg="#333333", font=("Arial", 10), relief="solid", borderwidth=1) self.content_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) diff --git a/utils/version_checker.py b/utils/version_checker.py index 12ec011..f6ec522 100644 --- a/utils/version_checker.py +++ b/utils/version_checker.py @@ -68,22 +68,28 @@ class VersionChecker: f"Could not check for updates. Server returned status code: {response.status_code}" )) except requests.RequestException as e: + error_message = f"Could not connect to update server: {str(e)}" + print(f"Version check error: {error_message}") if show_result: - self.app.after(0, lambda: messagebox.showwarning( + self.app.after(0, lambda msg=error_message: messagebox.showwarning( "Version Check Failed", - f"Could not connect to update server: {str(e)}" + msg )) - except json.JSONDecodeError: + except json.JSONDecodeError as e: + error_message = "Invalid update information received." + print(f"Version check error: {error_message}") if show_result: - self.app.after(0, lambda: messagebox.showwarning( + self.app.after(0, lambda msg=error_message: messagebox.showwarning( "Version Check Failed", - "Invalid update information received." + msg )) except Exception as e: + error_message = f"Could not check for updates: {str(e)}" + print(f"Version check error: {error_message}") if show_result: - self.app.after(0, lambda: messagebox.showwarning( + self.app.after(0, lambda msg=error_message: messagebox.showwarning( "Version Check Failed", - f"Could not check for updates: {str(e)}" + msg )) def show_update_notification(self, latest_version, download_url, message):