From 54a50c1ff0a47c6315a55f3e31630912cd687e7f Mon Sep 17 00:00:00 2001 From: Adrien Date: Thu, 3 Aug 2023 20:44:53 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20First=20commit=20(=F0=9F=92=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + Cargo.toml | 22 ++ images/add_user.png | Bin 0 -> 698 bytes images/aerobutton_border.png | Bin 0 -> 1928 bytes images/aerobutton_border_down.png | Bin 0 -> 1948 bytes images/brush.png | Bin 0 -> 494 bytes images/button_border.png | Bin 0 -> 1820 bytes images/button_border_disabled.png | Bin 0 -> 221 bytes images/button_border_focus.png | Bin 0 -> 223 bytes images/default-avatar.png | Bin 0 -> 5791 bytes images/directory.png | Bin 0 -> 755 bytes images/letter.png | Bin 0 -> 306 bytes images/logo-msn.png | Bin 0 -> 7385 bytes images/news.png | Bin 0 -> 430 bytes images/settings.png | Bin 0 -> 388 bytes images/status_away.png | Bin 0 -> 6715 bytes images/status_busy.png | Bin 0 -> 6611 bytes images/status_online.png | Bin 0 -> 5743 bytes images/tbc_transfert.png | Bin 0 -> 323 bytes src/app_settings.rs | 29 ++ src/base.rs | 5 + src/components.rs | 4 + src/components/avatar_selector.rs | 77 +++++ src/components/control_window.rs | 467 ++++++++++++++++++++++++++++++ src/components/header.rs | 38 +++ src/components/login.rs | 170 +++++++++++ src/main.rs | 55 ++++ src/matrix_client.rs | 208 +++++++++++++ 28 files changed, 1077 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 images/add_user.png create mode 100644 images/aerobutton_border.png create mode 100644 images/aerobutton_border_down.png create mode 100644 images/brush.png create mode 100644 images/button_border.png create mode 100644 images/button_border_disabled.png create mode 100644 images/button_border_focus.png create mode 100644 images/default-avatar.png create mode 100644 images/directory.png create mode 100644 images/letter.png create mode 100644 images/logo-msn.png create mode 100644 images/news.png create mode 100644 images/settings.png create mode 100644 images/status_away.png create mode 100644 images/status_busy.png create mode 100644 images/status_online.png create mode 100644 images/tbc_transfert.png create mode 100644 src/app_settings.rs create mode 100644 src/base.rs create mode 100644 src/components.rs create mode 100644 src/components/avatar_selector.rs create mode 100644 src/components/control_window.rs create mode 100644 src/components/header.rs create mode 100644 src/components/login.rs create mode 100644 src/main.rs create mode 100644 src/matrix_client.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..869df07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..67ae498 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "beau-gosse-du-92" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = "0.3.2" +sir = { version = "0.3.0", features = ["dioxus"] } +dioxus-desktop = "0.3.0" +# matrix-sdk = { version = "0.6.2", features = ["js"] } +matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", branch = "main" , features = ["js"]} +anyhow = "1.0.71" +url = "2.4.0" +tokio = "1.29.1" +dirs = "5.0.1" +ctrlc-async = "3.2.2" +tracing-subscriber = "0.3.17" + +[build] +target = "x86_64-unknown-linux-gnu" diff --git a/images/add_user.png b/images/add_user.png new file mode 100644 index 0000000000000000000000000000000000000000..f13708a68cad30e6bad8155f922b4e6a8597eb24 GIT binary patch literal 698 zcmV;r0!96aP)5r00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0#8XqK~y+TjZ!~o z6Hyp{W4DG*p$I7=7^-L?fkvua1{-2&G)wRXu_42GQlytEdZEJ|NZ}BnZ}WnvmxAWV zl7m7$$j~be9un~lLT|jyxAl#;eZG6m(5cN2KEC(yzVG+_Md$Hke^oYqZ<6ifCcV46 zio$Y6#VAD$-G zmy%&>@-{RG!axMjghJMt5%WpyR4~Th(Q@ae-}I{daO$FWlar(?OttQ65R(|1d^34B z3u;&gIj9OEpZYM^ADp6VjjX%!W|38Ki3g??=)81OXv^0j;sh44MEP=176dY{nDC43 zfA0TF$FP8Ms62an)?9lh15)9HK= zgFJ@}lF&jyDdba~+O1Yg9goM1@gOhuMCODg(Cv1A7K_E{j%;07uYbhYANGgzU~mxe gTfmYe@dOC{2a`&ReU@?%?EnA(07*qoM6N<$f|}kuZU6uP literal 0 HcmV?d00001 diff --git a/images/aerobutton_border.png b/images/aerobutton_border.png new file mode 100644 index 0000000000000000000000000000000000000000..1f1c38834f5f5e1151835cd1529cfac2cc906b90 GIT binary patch literal 1928 zcmbVNZ)_7~7{5)&1`!+s6P$#che3>7?@zDY?$VBJ?OeOq(Us1vF_7Kv-nPfuyW{S< zcAJ~BfeJChi2VIBvMI(7Y=&e60yyU|#1Qoh7(^u~8b3@N2~j35}3l2!bs2dfWl{E;8?eMezB`*S!t!wOI9pbOc#;-n?`6zqsrf z1j+kd3N{*zzLz;ciCcJ4X$F>5T!m-^acoSfywCy+v>8Ms*@;b@8NpCVbYcxQAL&zF zAS!vGn5=UtCzjUB!L_+fU}zd*v^cQ}(;(XD z^P?_B1E|en#|4V9p(U(^vRfIJ-GI_0RZ5Vh1ZBl3JI9b5O{19$gVr=L%mv&pWo*GO zCl)mfl_Q8`GHFR#Es7Q)D3)ajk|t;xhX`D6lMOzF%lg_`4Q`+dnxq<%BBQ28zFA2a zP7E@gaUrf|)yjG%OfX%le^5CNbo2~7Z1t&rwg(;Jm@X@EBr zEvP85*+ltgDWfiznHUyb-yq4NlGIQ2MVi3@*N(-taC*XQHBvTpFQ0K9G|2IFIqB#|TOFwKSm zgEMS%3C@R^Qk=Dw2)LCJ056IZ8)n&AdAA}Y%qp0b7oj{;B3cD2&)_0Yia1FzB+k;5 z-IQlbMV?`J*i>dVp#4pn1iO%rJ+dCNH`AItk`5Ewmg%0&V0&g2lhAac&cAi|t)k*1mZH4HA6p7j-COhD{-f~t4=E&%_^E&YRImT| z)#Q$X(c#xS{=Rfj7|Gdp=YVy(>D|yjWv^X$x+`^L-A<~kx`6$pcloQGV>P3bE0NQ; z924vI^ba4Cp5IVYU!N#^oM>_gSB5U0INMPF)QZY$p`(|#B`z~xeK3A^0O<(Ty+1HG zzIA!Wxrzy!ZT(Kv`{bWr>BQ|PIqJ?^nZd-D6w zP3>;I9&1Cdo+(dk+3S7p35S2xn>TVtI}SbP#TJWo;#$uI;$5JpxpL55I_*+mV0Xo$M3nX;;2mPXK~wwqoY zG0nS>(n@L-qYx$(Ffs!)l6Fv*OF5tlC6y|fFwDSeP!oX@obGGG;Cirv+OjVDl zYOzA`C51oZv!Br$AA8Xh@ah zX!aqfGeWZh#R@d{02Eb?1WfS1U`Z6Bs-6PKXE_C8kkphIj+G)Q_|&ATBg2TD^Zxyy z&)2A{Q8|eYjBs5o77X|}n&&uzanL!sp^y+%3==3K4Ent|ijPBpLj%DZTSb#W{q0TvQG;9NwMWyLn6 z&do-pqWnv`jBX)FKCvF_Zd&Cd)XN4+Y_@QFmcUhoSyIMw6(a!Ax(Qxfv`PRX2KjAy zmn?4w2Hw)I}a>wAxTUHRQut%bnfVvWjrj2d!zT0i#8!g+m3Y)=`7Lcg=OeW-DtB`fDPd zpL;ij8V*yF*52sfvZ!Kd>)t)5%Jfmwk}KCts)$|muUH#!@458sj z@z$8R8$PzrJ9}nh<*^eV{JHq26^WCcKlXL^&A8fG{>uET_U>NWWyjdgb<~9Fx-XiN z9pBdsCE>ZHOYN&>l7}?Uz_xi^+^*|e15G;?AG!PbtG5@N+go;V(U-U81ReH){eyP~ zv!85hdB1n->_bogvheh{qpN0C&3eau*5SYN*@o~H*fQ;)eQ5dxXa7w3pV2?`%`xL2 zU7_}zoj?yfbvZk0>d?`9`-OL>)K02@c@1{FuWwY-^!FxDZEktAXeo6qdL QX8k{dfd>Ds+LfLE0?9y?`2YX_ literal 0 HcmV?d00001 diff --git a/images/brush.png b/images/brush.png new file mode 100644 index 0000000000000000000000000000000000000000..c5e2ff4cc1ed989ac2562efce96ea13e106c9437 GIT binary patch literal 494 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0fR|IK~y+TosTg{ z!$1^<|FMH$6@+fatvCq#x>zV^2f>0% zaY;eJfP)<~cI)`OYj2dK`oZJ4`~UyFclZyE<4B!OXG>iFhG7^=5CmbX)tc05HCsF{ z2AiDj^?G3xMP!;LX`1#Tq{U!UeIB-LoAzXRS}vClgp^F9(WvsU=XsRR=SkOfM@Y#y zhnrh(?_beiFd#)ys8Xps2`Q1(Z3*?qv%rlc7%|-=@A@B41C@Ne1^qPap@| zaaSf$)1qNrr>>c$8yQmxCWt1Lrqqv2%zFzxDv=A%eFAF kjr!~?u%`!>{#=ZU2L{=h zOqMl?i`ht6lYyQ9+CflEO=xp^Anqvz?2h)?8FDrV>wfY|*b6 zSMq(w5QJ*A8m=l~;uZx-*L6XZ1zF}Pg7@mS4{E&a4R#q4*n_U+_!hC*fDz=$ydUGJ z(zXi~r$=jhoiNdW2{qsdQdkUJ>H;&F^`VtY5AFFA3)D(S?;VM~T;0LK6!yrx3-QDP zw*A4bF$8;ioq4z1@)SV3l|7)M2gEejbVs;*%O^L#{=BD`KuHC~rRL`RyIFDPovq-c)j&O;4Dbq-z>4hozwMsSN6F%JOKM>z%W71V7&y zl`Xbapay`!xrlKvC@(uR4Y;8%f*<3*a1jTEAAH~k)1 zSYQ3disb)Q-w7@(0lSE4s};DwA0cQ;?bHbW&01^iwg%RP)2$KIcq!aO6^c#3{ZEfuH^QR6E|2X|e?As?c&B9`FsQ=RYm%e*lzg)ZV89de8 zJbn7b?A3qP%=pibefY9FTDyGU#!n%*ynJ%(t>l--)`a1GjnLv&arDt2u0HtCo=4)L zr{0VO97-;^o z1&1E~J-O%WMq}d4`BXDG_}n{tn@daaS9TtM_3w*~zH7T0`GbF5zw*_u1BO3TOD_>5)e(zMlKL@4CO7n3jfyfrp33gxpu%;`$PDHWddHR8%jY z-H~*-?Y|fs8_)c@zlm2uLzf-d$ipvh_ox2RAyzgq0rn?Om1SjJJS{VsnS4ZMx3Km| zS!KOgv2bx)(Di@-MsHpQ<90FC|7z3r|Nke}dFq7moE-&?kF306Ll^&lzkk0g1KT?1 V-4?IsG6UVq;OXk;vd$@?2>^rbRr3G< literal 0 HcmV?d00001 diff --git a/images/button_border_focus.png b/images/button_border_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..83f333f5408079fe6056303d9277722e8e8e099a GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{1|(OCFP#RYmU+53hFJ6_|M~yl{_w(X|9{)p z-#G2SnUI{GuEDn@al_^5i7AYdJN_LBZEND-X5;2%^)5PVTln~3;RH+j`oDk9KM36T z;C~;t`M>%f9}hD<$tp7RusB^$w^?cQg+5t zgVI`z)nAU(Vv^Tpn%8Na+iRcMZK2(9q}_9;-*c$nc&p%ft>JsG;eD~8U69vUhty1Oz(ZK4KvJAKPn0BIt0sQY zfV1R^x#fnp=6$l{X`tLXVyuq5=TCpnDQLKZwBt!?yC;CsP-?r7z2{7P%1ULpErQgN zzUYUx<%qcEOm@d9fYL-{vwE=Nfwbh4zv*?X;cuwll)vaMgw>S5>6XFjc(3DgtKpWw z=}L6MIBK<*!Rm3U;V*>LnZoIq!Rd;+<}ifSn#1aw!s%k1+ec=$oy6;##Os{H>Y&E! ziMi)#q~9@HqoT;{F@@Eo$?K%a?54`?q{{6!alM$r>!{1^s?6=E%Un&C{B-$RVmM}x{vlGs_C z+(?z)Qk>#VnBY{L;z^d@mcr^-p5a=c;!Bs`U7_Nk$nIUDPV5< zOqkzbqT^zu(^rsk;3?_#CpXQ<|Bspf2|=WeX$TA<{y(eZGr=CjlBajoZY zt>|*D=&sQ5w$<`=uH|*G=wXY+T8PDVvFK%!%xjy|xz_S|vgvQ5+IzFxR1Ph`Z~EyX=X(>|cbxT6?!wpW}+W>{@lNR&1z^z3gb0(2l?D zkH74Z!0nX6?w7;vnZ@p($M2-e@CmlH!~g&jHAzH4RCwBjmc-Gc`Y?t$*0dWmk|zJ2S~t*^iS7w8J;@`Vc*&YwSj z?%dh4XHTC#eFpT|r=Na8+3XqrKZyS`XaDaW+`n)0cLenLUuOKz5q|`HMgtguy`#Sk z@R$IIzdgVf;OplCKCuBh9Q>c5|5Jwo^#gkUONGwaDntU%0AkPh+ZsRuknul$i2nB- z3)D;e=?d8Zw7)&z699B{^w~T3KPCPMc=V7CaOaLgg>F4Bz-gw%0BCQw*)#sn2JwI3 z9KgN<|LX6+`2hhwq5iOG%^?1L0R}eUwqt?pT71?%z(vZ*zOMmHgC9S9Xtx9$?3n^R zx5YGI4I|pVzri*D8UH=!31n9w=KyE=16-um*xC2@*UtZb{}Su%9dro{TArt zw6;|T=g$+{{2~5av1pS{r`PLsI&E6CR3PRmB1iu6<@Y16IQb6};3DyUr|Ng67=QTDUz(tDGYv3XS_?5Q(m40TX595FD9$TuSpWQ(48PCct4M1s20%Bh^5PVI zny8E?xt42irvX3w^i{wAAOU`)9+CMDw)D!P?V0^eAwI58DK6>m?zu^;yCmP32u+@+ zG=u`+%P+tG{)hhrJNw&p007_yo{x}2E_(Q6_2zKPw8oVDlJ1)~@7}%pZ@BLET*~jz zN?{twax1V00Ql)Y75xPoP@x~G`}d(54GwxKNvA#xd-lQ~d>iN+QYK7Gw+nFhX3wRP{LYRwX`&>)%+PSGwuwZT z68jv$?c2D;-*Hwi>s!`1@j`(%!v?r}^JY&^&!tP{K+r`Cc{yrJOMUBxy#Eq`g020w zJ*4*ze%IUk&9^Lx?^{J_89e|X=IGzk4H3FJU^M`s;{5})&2)rT^g2kM4&rr?c?AI2 zbHAn`w|nh$>xPGd?=2C>b#;SjPrtfLin}`76OR{3Wafrr^{u;+FnQX+p+sG|0)(%T zK_Il?#f{M{7K<+~O6-KC+)c)h5xToeuI6{P>!QovQb3#QYn!1+P@|y%m%sP|8A!Qh zr*Cd}1S-uIGe54g7W<_t`|jW_bAujld)}UBBT` z*K+KAv*e?W{HqA)xykh4Qh71XBcYhDtk~68qqp}BA?h4#RTnN`3>w1d%dhI|>yPa+ z`yTJ;x=JE2Ex2@*B-kWOlE@5oP@^VNqiI6}kU$t$2nBTQ%K3|p&9yZ(2kLSqqV|sB ztCueI`IlTR&hIqp(xeL|3Uk9=m`58L^Rk}pQ#hnL_~@P*R-Vm2A`Q?9{1Kr%xYgJKCq%#@zrou*)pt^2#>p+B-Va z0nwG7p5EEsu1kx83h@<6vvqHEeQj%VV`1uvAw(TP0@Uf$$%A|Bl$yPvsj0c9#iCYl z#bqj;J~_Fw6YZ1X-bH&{So9X$yQp(3c0mN#@e0@Ncam+S066k79HE~cZu^jk0jw)* z+`YTG_Si0ia-Kw7q|)l!jU6jj!ryaxUE*=kLa~IaKtMxFb$v}`W8ptZaZemQapI_> zs6&Sl@$tS7KX4QRnp*2ytY&47L|hgXrvpT?5&fg3Wec%F05CM{#V#~XJG#f_xaX*? z3S_|4VbGDoZ67#mTK0zBO_jCPyDUgZ;=t*dNN#}P)~l>2DF6Z})n_Xg3lJZN)eP4(V}id>n3AF!}UD2@8)qi7NQi2(jN3MKkmth-w3o3cN2 zls#bI!M69_rR4~SjcDA^)LdH+1gMh2n;Vc+R3^poivuKl3}CLX5J1iDwF4^LXG87V zZ}WEo{G$*eG`H3qXnEgSVOGn$`2k{18Qi=lAs`3+tyZhW+E88F_`x8u0rtE*lu{!a zVJQ^UlxFR%vlw#KiX5)5cwtczFF?X3{tXRvR*R*swE3O)1{E1G1x`D6zKdT2gk7kt ztTmOk>}mjlQkKJ(@RE4G68=2mUx)tIs+zao8$xJ8?Hoi5U|nI}?q(!ZXCVQ~1f7sb zxH&9!B-E#_p#geOSKYkh-RB4ZJ9g5S69gVuq{_;I8dG%@$q=cO$rLdEBhAoXsDFi_ zqOQ7j%e&77>>wJHv2!O)fFe~_HCQVQ26H5&P$-p%FdN_j1$t-a^8wp;Y~Nw0owjQy zVWuvQ34=CQS7lnQ6&28F8SEPY0TQk^tm9m>waWAk6L)7{CrOQMuXj@0w>tnFV3+|2 zHKkQ`Fn)8SQo-g4qtmo;Qb7`Tp3>X^<9Gb^fkHr^2Kd9%+K8CS`YJ0-BABK;4(xg4 z&t(Ce$PHDsTbw^af2yw>0NA!|+xEf4{LYqj*+3}GtjI-w0UQj**WgG{i52F$(szdV zkiDp_{TleITh^IMO)(L9VWukFwtYGBcp&H!vRX0=@*?sIOj#Q(xw0ItxQN5?Q<$s5CM~WsmDaA?LOz8b+U7XM9e;<%-?vk5 z+O!o(n>TNUf3|Ji4t0CyZBtgJ#hjaK$ts9hyci0VmATw%F>X3t}Q-3bHm@muHn0 z0Ae%wEHhH4s`Udll{Bg__0o6?zBoy^mTI<*MlVBKI)M0y-cC>hx)xxx*#_tn4cTDYsN_o|aBP`3CK!|wQJhwX z0&inVO0r(JNf@AB9u^h`jm|1H6>L~Lz=JNwo75YBePiHzsU{0Q3f$nYNikn-smPtj z6KS*rkPI^F69xR-teEhayjd}(($Z2>Wz5=v03vGDDmwstyB;2?(-Zjd#*~bV^!yZ~ zPF}`kDdF6o%MnJYG&Hs4Y09L)hT&w7J)=hLt z2+;m*HT}O(h)99mMR==Yaw5$;7@23lJ*9^MJ65=#5nvg2qrQR`rR7 z|8I6!mby%zzIt^zA(R6mBOUsx6>)rhyuEY0ydVWj=H<;3$m2CytyaWSXPFA7$1EP^ zWQ9UN-vi%R6&qtp;KmtKVCQlyB# ztUwohLT_|iMXj)jVXvJvJu9+EXG}?7UA)>(86*WLQJbjML`SRQZX?D0NlnuLbN=nM>8Tobus8c%p5N?3=M!kLwnX^V%6e%l>I+Y+N(`7nD zm|^FJ&ns3@OKI8ONS)}Csa~jou_eQ2)AKWkR^x?FzyJ!a1X@_3WqO@Pz>ah+2#c9j zILyg!1?BL1)nBs1T|;w35FXbQ5Wtcqtfo<~XT1J;dU`URYWOPzqStFglHBDkVc~fZ zuMP%S)c?a+2oUKfk0%=gj4yd536fziNU_X_|BFJJ$*Oy@eSkhV|okpV)cpD5Z;S*;K zpR@oB7c5`^E0$987c2k<(bA=DBAspl zRA|X7@$u2BxHy$cE|-f0{$8P>E&v!ldH($QbKqJqAG06;UqB3K1x%sfNN=%#5L7VJ zHSuX_Py%L7p>X)bUkf4QRdW0i;ldm19hBgTfJrmvfacFxf3`ZoHGJ0a;ghD!u@NA|e2Tmx zh(*I@xdaD!`S^!$;OG(xNeWQ3mV_V^(nw|{RzFHEkCI18(OoD2e;!*FI(|9=CPM_; z7CFp!5N19EaCP^bC*koBLB}B7h>jAS%zSj ziNhyNn*1tdN1#X=(&%@md9&ec}4RImR==7a}m4` z_8hUl-#8yOdrVNmgz&{k7)F8SPy|A~@WLFXO2a0)j0g&x=gsDh8wUt~P6&teLM~Uu zY2xBEaK**N$II!mi-@_9!&wN!A1C3my<}?l@nN$j0pKNy)(ar=L?dD+PH+nfWC6j) z2M~T(DY%V5Lr4MhF^)793kQXVeVfAx2?_BJ@$-Y>d(ZPyszb-qHJbA0K7x&dg^GA_ zy!+@tmY0_|gy4^5iMQ z{!Gi3gYOduua6Ix%ZC24Sb?6S(cc{b!x1oJ_SD%^rvhX)>GYgAFU%SC z^7KC;ASlSglO{m7p-kia#*U>kF#aKP#bEEtojH?@?r@JWW=x=`2l$7&1&^N)P5>`W zojP?kNrC=kuFiPb1puL;qk=p=N4b3Kvz(q&9Ltg`+_RQGP9sqOzcQ-e;@e}AS zPeH)c*`U4^F>N9M+}uZw9OdCb5ZDOFz@162YXNRJFe!Ox4Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0*FaOK~y+Tg^@96 z)ld|MGj?ltmx2_#`GyW}%pmv%hb*mclAy~Sqf<(Ucaeg(iw%gHLXixmWRXUwlIrk+ zBE*`~P!%sN@>1K{3w@;l=_A|kNnSv(P!Ak9_i)d5{&SA@uL0T!0P^lQu-gQ_nrCM{ z4)pZ;%S8h^V>nte@_k$U{xKW&f6mLn;Zrp@TFRC5P^bWd{>Sb5`$aq7Urh@YqR6A6 zQ>-!%RdJOg!0Aq}{(jNU`){%$PpiUQ`Bdm44sD7lSHuMHF*yA6KR|?>x@M_^G~$SS zivW@Uq>P}K0}cpK%9aiRMAe-+HY_iK2z_J(e*gK|@yx@S>uh=IT3zuzzl`9L+e51mw4v_L_ZC;@h4!lwO{gtK1n$PufM#0Q~@rrkt9is?)DmA l-&q$QYA@q8$|XrM`3Hx^O2k6sBVhml002ovPDHLkV1jA2RR910 literal 0 HcmV?d00001 diff --git a/images/letter.png b/images/letter.png new file mode 100644 index 0000000000000000000000000000000000000000..6d10b8e5bd3fbea7636ec46e0e32f30f6807b632 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Q-ATjv*HQS0}CIJFFn$_B*1w#nvnJX^N^) z=blYMoom*(D5+1Jyu;d#OZx7MO;>c3Ejb(C%hm0^Z=TC@-A5`z&7iSUbghTdw5|w^ zqfT0K%ANvF7DwC`JXcK=JH5H|O@5-Y)&_Aou}Ak-=uGf$WVfuzZRqJ}x>sq}nwsQj@O1TaS?83{1ORa>ZrA_- literal 0 HcmV?d00001 diff --git a/images/logo-msn.png b/images/logo-msn.png new file mode 100644 index 0000000000000000000000000000000000000000..9590615475e63b007cf528fe1786209aa25f1330 GIT binary patch literal 7385 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 DdKsOf literal 0 HcmV?d00001 diff --git a/images/news.png b/images/news.png new file mode 100644 index 0000000000000000000000000000000000000000..1063df2ff3704c9c69e51a8fd7f487e761fbc111 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4bGk}jv*HQYbWUzw-^YtO*~QT8Wwi#>OFsl zc{ZIc^IY7(KuLMxL=P1sq3yNh?~6<>zxLU0^qFVFgmm-WA^$fm6Ug9FZZ&+ozQTX; zgR(n(+w3|O{2I6A{uaC!DYmDxLHogi=BX#Y$DC!c3_oa?tt*+lPb^~XiB*p8&R&?z z`s~ugcjtvJ-|hUe^REtvg+2RzSFa*nR*k96dU+zk5#mx4wuZYUWyNs+xE(F*?YMez z&V{Jp;OiQHLppx^EiQlSt|(!+Nhjdeg^h1lWJ+1>lX(#knxgRNOe=%(UDoY-%S)G< zZq{Kv%`WuoLx6w*FQfY@XbzFVV@(`8E(JC4 z=se(=#QKEGBKeqvFB@;2#)fMXAKLd$>@Tm->Iv#m>R0~sIkq9R`Fi}P>7k+T*}8qF UBt`Za0K=HU)78&qol`;+0PyUpFaQ7m literal 0 HcmV?d00001 diff --git a/images/settings.png b/images/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..6a23c2ba6705539e0e5e27f47795b4251a15779a GIT binary patch literal 388 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 K@$Cg{?Ee7n6cpJ2 literal 0 HcmV?d00001 diff --git a/images/status_busy.png b/images/status_busy.png new file mode 100644 index 0000000000000000000000000000000000000000..471ff6b7f9d838ed4cf8a5b764998092e31f51d5 GIT binary patch literal 6611 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 literal 0 HcmV?d00001 diff --git a/images/status_online.png b/images/status_online.png new file mode 100644 index 0000000000000000000000000000000000000000..dd53972613883cc7148060c0ea2565556e3d227b GIT binary patch literal 5743 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 literal 0 HcmV?d00001 diff --git a/images/tbc_transfert.png b/images/tbc_transfert.png new file mode 100644 index 0000000000000000000000000000000000000000..4ec8570333091c9e1c92a0bd5289f4ba070256a8 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!5f|~jv*HQcPFhCYH|>1tz=mo=xfI|(c_3D z^F$97DRZGtmq&d^xBldCdvvV#H(NO0ozNMqTVKtzOniTSdwG46{iTn)CU@QvuCd71 zmzk##l-*Qm8G1+6D>@+8+sm4xeLmN0(a>EgnOR*|kF_&Qn4KbKV8X3+tH;kuIa6AG z6U%`UCk|$Wg?+0`*DG$Ap{2ZsQ-OVlVZ&klg$kGD8PvWrJ{COAkgoTdaS`(l<$?+U zJPz-T!SeR}*`D?yZe)jRj@{ P{m9_y>gTe~DWM4fFcfn< literal 0 HcmV?d00001 diff --git a/src/app_settings.rs b/src/app_settings.rs new file mode 100644 index 0000000..b0122ca --- /dev/null +++ b/src/app_settings.rs @@ -0,0 +1,29 @@ +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::{Arc, Mutex}; + +use crate::matrix_client::MatrixClient; +use crate::matrix_client::Requester; + +#[derive(Debug, Clone)] +pub struct AppSettings { + // pub matrix_client: Option>>, + // pub matrix_client: Arc, + // pub matrix_client: Rc>, + // pub matrix_client: Arc, + //pub matrix_client: Arc>, + pub requester: Option>, +} + +impl AppSettings { + pub fn new() -> Self { + Self { + // matrix_client: Arc::new(MatrixClient::new()), + //matrix_client: Arc::new(Mutex::new(MatrixClient::new())), + requester: None, + // matrix_client: Arc::new(Mutex::new(MatrixClient::new())), + // matrix_client: Arc::new(MatrixClient::new()), + // matrix_client: Rc::new(RefCell::new(MatrixClient::new())), + } + } +} diff --git a/src/base.rs b/src/base.rs new file mode 100644 index 0000000..adcb1f6 --- /dev/null +++ b/src/base.rs @@ -0,0 +1,5 @@ +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Info {} + +// pub type ProgramStore = Store; +// pub type AsyncProgramStore = Arc>; diff --git a/src/components.rs b/src/components.rs new file mode 100644 index 0000000..ce11cfa --- /dev/null +++ b/src/components.rs @@ -0,0 +1,4 @@ +pub mod avatar_selector; +pub mod control_window; +pub mod header; +pub mod login; diff --git a/src/components/avatar_selector.rs b/src/components/avatar_selector.rs new file mode 100644 index 0000000..0d1d534 --- /dev/null +++ b/src/components/avatar_selector.rs @@ -0,0 +1,77 @@ +use dioxus::prelude::*; +use sir::css; + +pub fn AvatarSelector(cx: Scope) -> Element { + let selector = css!( + " + position: relative; + //left: 35%; + height: 100%; + aspect-ratio: 1; + " + ); + + let picture = css!( + " + position: absolute; + height: 75%; + aspect-ratio: 1; + + bottom: 17.5%; + right: 18%; + " + ); + + cx.render(rsx! { + div { + class: "{selector}", + svg { + view_box: "0 0 100 100", + linearGradient { + id: "avatar-gradient", + x1: 1, + y1: 1, + x2: 0, + y2: 0, + stop { + offset: "0%", + stop_color: "rgb(138, 191, 209)", + } + stop { + offset: "60%", + stop_color: "rgb(236, 246, 249)", + } + }, + filter { + id: "avatar-shadow", + feDropShadow { + dx: 2, + dy: 2, + std_deviation: 3, + flood_opacity: 0.5, + }, + }, + rect { + width: "90", + height: "90", + rx: "12", + fill: "url('#avatar-gradient')", + filter: "url('#avatar-shadow')", + stroke: "grey", + }, + // rect { + // x: "7.5", + // y: "7.5", + // width: "75", + // height: "75", + // fill: "transparent", + // stroke: "grey", + // }, + }, + img { + class: "{picture}", + src: "./images/default-avatar.png", + }, + }, + }) +} diff --git a/src/components/control_window.rs b/src/components/control_window.rs new file mode 100644 index 0000000..17df33e --- /dev/null +++ b/src/components/control_window.rs @@ -0,0 +1,467 @@ +use dioxus::prelude::*; +use sir::{css, global_css}; + +use crate::app_settings::AppSettings; +use crate::components::avatar_selector::AvatarSelector; +use crate::components::header::Header; + +pub fn ControlWindow(cx: Scope) -> Element { + let app_context = use_shared_state::(cx).unwrap(); + println!("app_context={:?}", app_context.read()); + + // TODO: Use @extend once implemented (https://github.com/kaj/rsass/issues/65) + global_css!( + " + .aero-button { + height: 50%; + min-height: 16px; + aspect-ratio: 1; + background-color: transparent; + border: 2px solid transparent; + background-size: contain !important; + margin-right: 1%; + } + .aero-button:hover { + border-image: url(./images/aerobutton_border.png) 2 round; + } + .aero-button:active { + border-image: url(./images/aerobutton_border_down.png) 2 round; + } + + .button { + height: 50%; + min-height: 16px; + aspect-ratio: 1; + background-color: transparent; + border: 2px solid transparent; + background-size: contain !important; + margin-right: 1%; + } + .button:hover { + border-image: url(./images/button_border.png) 2 round; + } + .button:active { + border-image: url(./images/button_border_down.png) 2 round; + } + + .flex-right { + margin-left: auto; + } + + .user-info { + position: relative; + height: 75%; + width: 99%; + top: -75%; + left: 1%; + aspect-ratio: 1; + z-index: 1; + display: flex; + flex-direction: row; + align-items: center; + + .avatar-selector { + height: 100%; + aspect-ratio: 1; + } + + .info-container { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + height: 100%; + width: 100%; + + .user-id { + height: 30%; + width: fit-content; + display: flex; + text-align: begin; + align-items: center; + + .user-name { + display: inline-block; + width: fit-content; + color: white; + margin: 0; + } + + .user-status { + display: inline-block; + color: #B9DDE7; + width: fit-content; + //margin-left: 1%; + //padding-left: 1%; + } + } + + .user-message { + width: fit-content; + height: 30%; + display: flex; + text-align: begin; + align-items: center; + margin: 0; + color: white; + } + } + } + + // From https://codepen.io/zoomodesign/pen/yNbVVZ + .contacts { + height: 72%; + width: 100%; + background-color: white; + font-size: 8pt; + + &.active { + .arrow { + transform: rotate(45deg) translate(-5px,-5px); + &:before { + transform: translate(10px,0); + } + &:after { + transform: rotate(90deg) translate(10px,0); + } + } + ul { + opacity: 0; + } + } + + .header { + height: 2%; + width: 98%; + display: flex; + flex-direction: row; + align-items: center; + cursor: pointer; + margin: 0; + margin-left: 1%; + padding-top: 1%; + font-weight: bold; + } + + ul { + height: 100%; + margin: 0; + overflow: hidden; + opacity: 1; + transition: 0.4s ease; + } + + li { + list-style-type: none; + height: 2%; + margin: 0 auto; + cursor: pointer; + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + + img { + height: 100%; + aspect-ratio: 1; + } + } + + .arrow { + width: calc((100%/1080)*10); + aspect-ratio: 1; + display: inline-block; + transition: 0.4s ease; + margin-top: calc((100%/1080)*2); + margin-right: 2%; + text-align: left; + transform: rotate(45deg); + float: right; + &:before, &:after { + position: absolute; + content: ''; + display: inline-block; + width: 100%; + height: 15%; + background-color: #000; + transition: 0.4s ease; + } + &:after { + position: absolute; + transform: rotate(90deg); + top: -5px; + left: 5px; + } + } + + .contact { + list-style-type: none + margin: 0 auto + text-align: left + cursor: pointer + } + } + " + ); + + let root = css!( + " + width: 100%; + height: 100%; + + background-color: #ECF6F9; + font-family: \"Tahoma\", sans-serif; + + border: thin solid #707070; + border-radius: 8px; + box-shadow: 0 0 5px #00000050; + " + ); + + let header = css!( + " + height: 10%; + width: 100%; + " + ); + + let title_bar = css!( + " + height: 60%; + width: 100%; + background: + linear-gradient(180deg, #7DC5E3, #3883A3); + " + ); + let user_info = css!( + " + height: 40%; + width: 100%; + background: + linear-gradient(180deg, #00658B, #0077A6); + " + ); + let contacts_nav = css!( + " + height: calc(31/1080*100%); + background: + linear-gradient(180deg, #00658B, #0077A6); + " + ); + + let contacts_nav_inner = css!( + " + margin-left: 1%; + margin-right: 1%; + height: 100%; + display: flex; + align-items: center; + " + ); + + let search = css!( + " + height: calc(38/1080*100%); + width: 100%; + + border-bottom: thin solid #e2eaf3; + " + ); + + // TODO: Remove following div + let search_inner = css!( + " + height: 100%; + width: 98%; + padding-left: 1%; + display: flex; + flex-direction: row; + align-items: center; + " + ); + + let search_input = css!( + " + height: calc(23/38*100%); + width: 100%; + margin-right: 1%; + border: thin solid #c7c7c7; + box-shadow: inset 0 0 calc(3/1080*100%) #0000002a; + font-size: 8pt; + + padding-left: 1%; + " + ); + + let footer = css!( + " + height: 10%; + " + ); + + let show_contacts = use_state(cx, || false); + + let contacts_active = if **show_contacts { "active" } else { "" }; + + cx.render(rsx! { + div { + class: "{root}", + + div { + class: "{header}", + + div { + class: "{title_bar}", + }, + + div { + class: "{user_info}", + }, + + div { + class: "user-info", + + div { + class: "avatar-selector", + AvatarSelector {}, + }, + + div { + class: "info-container", + + div { + class: "aero-button user-id", + p { + class: "user-name", + "SUPER USER" + }, + p { + class: "user-status", + "(Busy)", + }, + }, + + div { + class: "aero-button user-message", + p { + "My message", + } + }, + }, + }, + }, + + div { + class: "{contacts_nav}", + div { + class: "{contacts_nav_inner}", + + button { + class: "aero-button", + style: "background: url(./images/letter.png) center no-repeat", + }, + button { + class: "aero-button", + style: "background: url(./images/directory.png) no-repeat center", + }, + button { + class: "aero-button", + style: "background: url(./images/news.png) no-repeat center", + }, + + button { + class: "aero-button flex-right", + style: "background: url(./images/brush.png) no-repeat center", + }, + button { + class: "aero-button", + style: "background: url(./images/settings.png) no-repeat center", + }, + + }, + + }, + + div { + class: "{search}", + + div { + class: "{search_inner}", + + input { + class: "{search_input}", + placeholder: "Find a contact...", + r#type: "text", + }, + + button { + class: "button", + style: "background: url(./images/add_user.png) no-repeat center", + }, + + button { + class: "button", + style: "background: url(./images/tbc_transfert.png) no-repeat center", + }, + }, + }, + + div { + class: "contacts {contacts_active}", + + p { + class: "header", + onclick: move |_| show_contacts.set(!show_contacts), + span { + class: "arrow", + }, + "Online (4)", + }, + + // TODO: Test overflow + ul { + li { + img { + src: "./images/status_online.png", + }, + p { + "Contact AAAAAAAA -", + }, + p { + style: "color: darkgrey;", + "i'm sad all day until i get to talk with friends, online friends that is", + }, + }, + li { + img { + src: "./images/status_busy.png", + }, + p { + "Contact BBBBBB -", + }, + p { + style: "color: darkgrey;", + "i'm sad all day until i get to talk with friends, online friends that is", + } + }, + li { + img { + src: "./images/status_away.png", + }, + p { + "Contact CCC -", + }, + p { + style: "color: darkgrey;", + "i'm sad all day until i get to talk with friends, online friends that is", + } + }, + }, + }, + + div { + class: "{footer}", + }, + }, + }) +} diff --git a/src/components/header.rs b/src/components/header.rs new file mode 100644 index 0000000..3c71131 --- /dev/null +++ b/src/components/header.rs @@ -0,0 +1,38 @@ +use dioxus::prelude::*; +use sir::css; + +pub fn Header(cx: Scope) -> Element { + let header = css!( + " + height: 100%; + width: 100%; + display: flex; + + img { + height: 100%; + } + svg { + fill: white; + } + " + ); + + cx.render(rsx! { + div { + class: "{header}", + img { + // src: "./assets/live-logo2.png" + src: "./images/logo-msn.png" + } + svg { + view_box: "0 0 100 10", + text { + y: "55%", + dominant_baseline: "middle", + font_size: "5", + "Windows Live Messenger", + }, + }, + } + }) +} diff --git a/src/components/login.rs b/src/components/login.rs new file mode 100644 index 0000000..dd857dd --- /dev/null +++ b/src/components/login.rs @@ -0,0 +1,170 @@ +use dioxus::prelude::*; +use sir::css; +use std::str::FromStr; +use std::sync::Arc; + +use crate::app_settings::AppSettings; +use crate::components::avatar_selector::AvatarSelector; +use crate::components::header::Header; +use crate::matrix_client::{LoginStyle, MatrixClient}; + +pub fn Login(cx: Scope) -> Element { + let app_context = use_shared_state::(cx).unwrap(); + println!("app_context={:?}", app_context.read()); + + let login = use_ref(cx, || Login::new()); + + let empty_placeholder = String::from(""); + + let root = css!( + " + width: 90%; + height: 98%; + + display: flex; + flex-direction: column; + align-items: center; + + padding: 5%; + padding-top: 2%; + + background: linear-gradient(rgb(138, 191, 209), rgb(236, 246, 249) 10%); + " + ); + + let header = css!( + " + height: 5%; + width: 100%; + " + ); + + let body = css!( + " + height: 50%; + width: 50%; + max-width: 400px; + + display: flex; + flex-direction: column; + justify-content: center; + + padding-bottom: 3%; + " + ); + + let footer_buttons = css!( + " + width: 100%; + + padding-top: 5%; + + display: flex; + justify-content: center; + " + ); + + let avatar_selector = css!( + " + height: 30%; + width: 100%; + " + ); + + let run_matrix_client = move |_| { + to_owned![app_context, login]; + + let homeserver_url = login.read().homeserver_url.clone().unwrap(); + let username = login.read().email.clone().unwrap(); + let password = login.read().password.clone().unwrap(); + + cx.spawn(async { + let requester = MatrixClient::spawn(homeserver_url).await; + + requester.init(); + requester.login(LoginStyle::Password(username, password)); + + let context = app_context; + context.write().requester = Some(Arc::new(requester)); + }); + }; + + cx.render(rsx! { + div { + class: "{root}", + + div { + class: "{header}", + Header {}, + }, + + div { + class: "{body}", + div { + class: "{avatar_selector}", + AvatarSelector {}, + }, + + p { + "Matrix homeserver:" + }, + input { + id: "input-homeserver-url", + r#type: "text", + name: "homeserver URL", + value: "{(login.read().homeserver_url.as_ref().unwrap_or(&empty_placeholder))}", + oninput: move |evt| login.write().homeserver_url = Some(evt.value.clone()), + }, + + p { + "E-mail address:" + }, + input { + id: "login-input-email", + r#type: "text", + name: "email", + value: "{login.read().email.as_ref().unwrap_or(&empty_placeholder)}", + oninput: move |evt| login.write().email = Some(evt.value.clone()), + }, + p { + "Password:" + }, + input { + id: "login-input-password", + r#type: "password", + name: "Password", + value: "{login.read().password.as_ref().unwrap_or(&empty_placeholder)}", + oninput: move |evt| login.write().password = Some(evt.value.clone()), + }, + + div { + class: "{footer_buttons}", + input { + class: "button", + onclick: run_matrix_client, + r#type: "submit", + value: "sign in", + }, + }, + }, + }, + }) +} + +#[derive(Debug)] +struct Login { + homeserver_url: Option, + email: Option, + password: Option, +} + +impl Login { + fn new() -> Self { + let login = Self { + homeserver_url: None, + email: None, + password: None, + }; + login + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b66ce5d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,55 @@ +#![allow(non_snake_case)] +use dioxus::prelude::*; +use dioxus_desktop::Config; +use sir::{global_css, AppStyle}; + +pub mod app_settings; +pub mod components; +pub mod matrix_client; + +use crate::app_settings::AppSettings; +use crate::components::control_window::ControlWindow; +use crate::components::login::Login; + +mod base; + +fn App(cx: Scope) -> Element { + use_shared_state_provider(cx, || cx.props.clone()); + + global_css!( + " + body { + height: 100vh; + width: 100vw; + margin: 0px; + padding: 0px; + outline: 0px; + font-family: Tahoma, sans-serif; + } + #main { + height: 100%; + width: 100%; + }" + ); + + // let window = dioxus_desktop::use_window(cx); + // let dom = VirtualDom::new(ControlWindow); + // window.new_window(dom, cx.props.clone()); + + cx.render(rsx! { + AppStyle {}, + // Login {} + ControlWindow {} + }) +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt::init(); + + let app_settings = AppSettings::new(); + + dioxus_desktop::launch_with_props(App, app_settings, Config::default()); + + Ok(()) +} diff --git a/src/matrix_client.rs b/src/matrix_client.rs new file mode 100644 index 0000000..c5ee1df --- /dev/null +++ b/src/matrix_client.rs @@ -0,0 +1,208 @@ +use dirs; +use matrix_sdk::{ + config::SyncSettings, + room::Room, + ruma::events::room::{ + member::StrippedRoomMemberEvent, + message::{OriginalSyncRoomMessageEvent, RoomMessageEventContent, SyncRoomMessageEvent}, + }, + Client, Error as MatrixError, +}; +use std::fmt::{Debug, Formatter}; +use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; +use std::sync::{Arc, Mutex}; +use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; +use tokio::task::JoinHandle; +use tokio::time::{sleep, Duration}; + +use crate::base::Info; + +#[derive(Debug)] +pub enum LoginStyle { + // SessionRestore(Session), + Password(String, String), +} + +pub struct ClientResponse(Receiver); +pub struct ClientReply(SyncSender); + +impl ClientResponse { + fn recv(self) -> T { + self.0 + .recv() + .expect("failed to receive response from client thread") + } +} + +impl ClientReply { + fn send(self, t: T) { + self.0.send(t).unwrap(); + } +} + +pub enum WorkerTask { + // Init(AsyncProgramStore, ClientReply<()>), + // Init(ClientReply<()>), + Init(ClientReply<()>), + //Login(LoginStyle, ClientReply), + Login(LoginStyle, ClientReply<()>), +} + +impl Debug for WorkerTask { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + match self { + WorkerTask::Init(_) => f + .debug_tuple("WorkerTask::Init") + .field(&format_args!("_")) + // .field(&format_args!("_")) + .finish(), + WorkerTask::Login(style, _) => f + .debug_tuple("WorkerTask::Login") + .field(style) + // .field(&format_args!("_")) + .finish(), + } + } +} + +fn oneshot() -> (ClientReply, ClientResponse) { + let (tx, rx) = sync_channel(1); + let reply = ClientReply(tx); + let response = ClientResponse(rx); + + return (reply, response); +} + +#[derive(Debug)] +pub struct Requester { + pub client: Client, + // pub matrix_client: MatrixClient, + pub tx: UnboundedSender, +} + +impl Requester { + pub fn init(&self) { + println!("Requester.init BEG"); + let (reply, response) = oneshot(); + + self.tx.send(WorkerTask::Init(reply)).unwrap(); + + println!("Requester.init END"); + return response.recv(); + } + + pub fn login(&self, style: LoginStyle) { + println!("Requester.login BEG"); + let (reply, response) = oneshot(); + + self.tx.send(WorkerTask::Login(style, reply)).unwrap(); + + println!("Requester.login END"); + return response.recv(); + } +} + +#[derive(Debug)] +pub struct MatrixClient { + initialized: bool, + // client: Client, + client: Option>, + sync_token: Option, + load_handle: Option>, + sync_handle: Option>, +} + +impl MatrixClient { + pub async fn spawn(homeserver_url: String) -> Requester { + let (tx, rx) = unbounded_channel::(); + + let client = Client::builder() + .homeserver_url(&homeserver_url) + .build() + .await + .unwrap(); + + let mut matrix_client = MatrixClient { + client: None, + initialized: false, + sync_token: None, + load_handle: None, + sync_handle: None, + }; + matrix_client.client = Some(Arc::new(client.clone())); + + tokio::spawn(async move { + matrix_client.work(rx).await; + }); + + Requester { client, tx } + } + + async fn work(&mut self, mut rx: UnboundedReceiver) { + println!("MatrixClient.work BEG"); + loop { + let task = rx.recv().await; + println!("task={:?}", task); + + match task { + Some(task) => self.run(task).await, + None => { + break; + } + } + } + + println!("MatrixClient.work END"); + + if let Some(handle) = self.sync_handle.take() { + handle.abort(); + } + } + + async fn run(&mut self, task: WorkerTask) { + println!("Run({:?}", task); + match task { + WorkerTask::Init(reply) => { + assert_eq!(self.initialized, false); + self.init().await; + reply.send(()); + } + WorkerTask::Login(style, reply) => { + assert!(self.initialized); + reply.send(self.login_and_sync(style).await.unwrap()); + } + } + } + + async fn init(&mut self) { + self.initialized = true; + } + + async fn login_and_sync(&mut self, style: LoginStyle) -> anyhow::Result<()> { + let client = self.client.clone().unwrap(); + + match style { + LoginStyle::Password(username, password) => { + let resp = client + .matrix_auth() + .login_username(&username, &password) + .initial_device_display_name("TODO") + .send() + .await?; + dbg!(resp); + } + } + + self.sync_handle = tokio::spawn(async move { + loop { + let settings = SyncSettings::default(); + + let _ = client.sync(settings).await; + } + }) + .into(); + + println!("User connected to the homeserver"); + Ok(()) + } +}