From 83008f44e4a0a449fc37f5a62f858f9d248483a0 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Fri, 20 Jul 2018 16:15:50 +0300 Subject: [PATCH] Show device list in user profile & add option to create 1-1 chat --- resources/icons/ui/add-square-button.png | Bin 965 -> 375 bytes resources/icons/ui/add-square-button@2x.png | Bin 1386 -> 414 bytes resources/icons/ui/paper-clip-outline.png | Bin 596 -> 627 bytes resources/icons/ui/paper-clip-outline@2x.png | Bin 872 -> 1005 bytes resources/icons/ui/settings.png | Bin 1363 -> 761 bytes resources/icons/ui/settings@2x.png | Bin 2573 -> 1263 bytes resources/icons/ui/vertical-ellipsis.png | Bin 830 -> 674 bytes resources/icons/ui/vertical-ellipsis@2x.png | Bin 1041 -> 892 bytes src/ChatPage.h | 2 +- src/MainWindow.cpp | 2 +- src/Utils.cpp | 8 ++ src/Utils.h | 3 + src/dialogs/UserProfile.cpp | 142 +++++++++++++++++-- src/dialogs/UserProfile.h | 24 +++- src/ui/OverlayModal.cpp | 2 +- 15 files changed, 162 insertions(+), 21 deletions(-) diff --git a/resources/icons/ui/add-square-button.png b/resources/icons/ui/add-square-button.png index a4933c16c9097df85f9d165f70a9fab3860f006d..7b6f1b1915828d60228b1673451043b2bf19e8d1 100644 GIT binary patch literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKVlc*v$o<=7B2(}xq7-dhIkxLPB_48Bk|99A$y*y z506MwAhR22OC7#SE^=o*;o8X1Hbnpl}yTA5mC8yHy`7{r`< zwirc2ZhlH;S|x4`y3^z2ff^)1HU#IVm6RtIr81P4m+NKbWfvzW7NqLs7p2dBXCnnv O#Ng@b=d#Wzp$P!kM`V5g literal 965 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}oCO|{#S9Fh z9U#njDSry^7odplSvNn+hu+GdHy)QK2F?C$HG5 z!d3~a!V1U+3F|8Y3;nDA{o-C@9zzrKDK}xwt{K19`Se z86_nJR{Hwo<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9O-#x!EwNQn0$BtHPO|}r3j51k_V##lVOtdm< z7+K{VbX8gt5|gF4T_2Y_sri|md^c%t_S440b9YuhKT}XYt(vpsBjzQi z0&dlAJTcw-2dlGc-z$%3%PFgwUH7<4@SZqbuQ0txtnC5Eo`%^MJ~V!0+P_vg+1lri zjZC>!=$qW1uP^xj*8Qh7r)hGdhHj?U?X*zKsk;jvSl!<^{pw8NC2M8ET8hfwe3Sau zVpZIP(UUgTe~DWM4fMCgO9 diff --git a/resources/icons/ui/add-square-button@2x.png b/resources/icons/ui/add-square-button@2x.png index b2c4a44b8a3e15f47f2f636f5e5174a00fb08745..1aeeb2d5ba482461afbd636df9720678d9de1e25 100644 GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5SkpPy978hhy}fae^MHZ?%K>i> z$CnDaS)MNyWM}R_@A|>G+TKyp#^S;%owdh8bgf_TFrH=tYJ-6dvIQ;vtCqjZe7f44 zxo5BWhP@zXhkwnuzsYgRF?CUxIv{;u)1N2{iL<=Yg2_OhYKdz^NlIc#s#S7PDv)9@ zGBC8zH89sTG6*p=wK6cUGBDCMFak0j^t}Xn9Z5rOeoAIqC2kE9F9%uxHAsSN2+mI{ pDNig)WhgH%*UQYyE>2D?NY%?PN}v7CMhd8i!PC{xWt~$(69CTCa&!Oy literal 1386 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|I14-?iy0V1 zJ3yH6$aRMWKm{q8ArU1JzCKpT`MG+DDfvmMdKI|^K-CNkHWgMtW^QUpqC!P(PF}H9 zg{=};g%ywu64qBz04piUwpEJo4N!2-FG^J~)icpEP_pAvP*AWbN=dT{a&d!d2l8x{ zGD=Dctn~HE%ggo3jrH=2()A53EiLs8jP#9+bb%^#i!1X=5-W7`ij^UTz|3(;Elw`V zEGWs$&r<-Io0ybeT4JlD1hNPYpzh2qfLoMT4D}VzfBF@P1^R}12KsQ5ff{XqezbBf zN=+=uFAB-e&#?nJEi*5>I61K(734r0eRLI2D{b^a?m%)E#M59=ps($?fI49zXvcNu z__ACE2Il#mE{-7;jBjV}&J%VNX%kimVe8t%pvgE(TV{Ke`t7)TST?(7UVOib`Nlm|%U!@hz zFN(!)nR90q^Yp79f}4*_U$)@oB?IA%4|^LQc?(}in^h2V^gORv{Hy~$4zKeM_8+lc zm~-We{}wU(9_wFbIxmak|L^|#F|O79(5?@zGmhNQ3@SdvnYccIHEMcGw8?_Y+y`&J zKE3KZ*G`t0hi@{SjBhO$V|j10-)XVW<7E}mY6~Ra26y`@FZ(Sgl`2)>-kf^qk(p?9 z-wyUwwFR#x$2I+SZcpK7{&D*r*PYY0HoUPsAH>XL)OWU*AA2=rxuf@!EukGJ^26^N zA97qMGe3FC{_F2KXFHwJ*dA#4%z#~x2`Y8})2 zg=ZM@TVGxc%GN*D9m%tCRdV9y_=515qtojC9$xkS#)1F;|D3ujZP9Ba7hVzG`XE$g ziB3%T*{;o65r1EuJA9POWJXOAU!(IivEvi?p9v*9ywx^8ej`E8kjb>d8ov3L%hThD4k8b)%#CIavYvIj;w{gK-2SD{Zl7zo()Y|P z&YHRCcJj)feaUPUx4&eq+$#R~>ORNZsp^i9pr|>Mq)~D>=75d*2LqR#uO82meYEnb z)M1{6h*t@smF8a;oU2&J#>W_Eym8UDt213yl;UmpvcKFv&~V&s;+HwWru(o3)3%5o{CsFn#tX}9OQfRySGoOKF-iVEv+#wE zYo~TBc(d%nlD)PoSaUN<9xqzuJBKsF>GrfmtHbW(NtNh7f1lxa*<+*k+VvdgS>vou zoMiwf`jtIJreTq9)Gb3l{rb~%LAYR(vQHAvKD+;3ES0tMq6^dhuymT{Uq8?vcO6s! Ndb;|#taD0e0stpak2m;rLpy&Vq0YOPbK~zY`?bWer+EEn8@sH8D&@I{04t8lE z#lAqYXh-SRq0l~oAxOdCQ*?K1K}QkAt#q_P*R~HJ1X>D$G>fN;5v_mmx)#rc3+H#w z`SRmlxQDDLxH9z94xFlOqB#<|@Y_ delta 375 zcmV--0f_$d1k?nOi+>Xr8W7VbYXSfO0U}96K~zY`?bJ^zgi#d7@ed{?MJWp@f6B(J z)c8}p238ibv6DAoW1;LU6e*=-qR7gNu#gCmg_UeHo7spIP3Bt2JkNred1fW~p3Uu? zPMzQHo_qP{4^S67cNjHnNLz)Tf*WTJ<>Sc)3*LkTkvADl(0^y&FoHW59xF_cl9thk zSzFNLRuJrIuUdM)OTn`qSQ8XYCv>mNlVF_@MZrd_)a^j-N9_?if)f@6dCjr*$Fk-{ z%nP1U265`8lwQ{A)vl|GB6@L8POub9=LDNoc+lcOkgZQ>UDUp#Q_*(HxpA3T>By8B z%1B5_o6w0>$2iGN{EBxg8cBYQLBX}Gv8bW8MT$|&Dwjz9nC8AuSO1*9o#2z|K9qsl zz53_Z@&U~bwzQgUYA=)E0UQ-EIaD$;Ix;poF*YkOGCD9Y-+ZgnlMwp&5uP~a* z7Y6=L`ups+NN-^9iyS>(r=M<qFrmD9oUNHh`^d0%{~-cO@BM?c#65q5Y1 zJdpkJIu+aTOr>#m45QlF;E5d485oQT#?#&L91EI%J;DNW_JcWF1>-C>*%ldh63U#w z4^_uC+a75qIF#o@CP=fVA>s|*UC5?-m-(ia013tzBSE04Ew8*byC<-uLT%ad+EQLi zW`Om-Dm&calbijoN{khg>&t3c z(T=fQmR@p{J0>raqt~nSRf#h#pQh8L#Pq4(OiN;Y4(Jjh&0Ve&Cl2hg%LenjbMlAm z59FRkqHS?1HIvl>9}+P&IxsjoFgGhOGCD9Yp<#yClLiAH5-~M8FgQ9eH!CnQIxsNM KJU(laHv=*FC~VIF delta 646 zcmV;10(t%I2j~WnjDG+a7L3dx`2YX{Hc3Q5RA}Dqm`z9(Q5462ev~Lek6dK7C@OH( zqGYO_(oTekC=y(?2^a2Da3Mr3TC}dE5D~RVlvXbC10#sQj9dvy=u5C9f~TUAEoSDt z`=)!-_vYT&czBs41oE`S8+b4SV6K`OEUk;>;HbS#m{yHm8#Y6i+w_bjbKN-k}Hjqrh8lETOTIVev zSSHVI>Lko@i8eZD5zjUObLx~QCGmad7PYBmlQi;F(U?_t*WD8Nmo!-ykLhGfbRNXc z^NMqg+s?#8?thEcPP`vpi))uFj^&|-_o8@1nfl5wxj$9G(X$kdZr0K%&Jp8( zUnI|3g{h~K<8*Yj3gZ&1e(w*-_&gUZhy%3CGiRzf6@NK5_^F-TCRca(Vkv+wxtf6A zQ7j9F$??Wpu_O+G(rEKT@|%rqZiK8mGaSTH8h+Q@)F^!6xl4zf$a9PKo0Gf)G4%E=Z2$lO diff --git a/resources/icons/ui/settings.png b/resources/icons/ui/settings.png index 6e013f75a5c053b11fe8b7123632b750988302c2..ba521e27f02bb416701072cb4224fa245935671c 100644 GIT binary patch literal 761 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKVlc*v(n>y^a*G(<8ebEjDAxH<~7?SEZ# zR9UW7LtvtU94D)z%OW?&g$iDC*`~TJ3>NBiS|Q>k)XCzgI!{orwcOF^QDBVHyu$ut zmSx}G?7U-q`OUdM|Le=r)A(oT_SWhgUEX<7iuLZJGu#r-1@*6dV^uk(7O>=Pv))Mw z)&(lR=CbchZewFGl6V@ty78!KEQ89WgIbAEp;a@TEfQu_i{JcK>Q?b1GJZv99`%M&N2lD{l#*vwTa!iK`WNdS|BL6P^iu3O8AN5hSE6_hJvdU zj?7Rr^>(Pyo@(sOJ11=0XN{opl%0Li=cgZ-6QuRr$Jb9Hf6c!0(ne1-?73dd3rvWP zWasp5tYEA)==5hW>!C8<`)MX5lF!N|bSLf61t*T^8m(8S8r!pg)<+rY@mz(9ZQw>T6Hx%nxX zX_dGxT^1k@l2vLQG>t)x7$D3zhSyj(9cFS|H7u^?41zbJk7I~ysWA_h-aKbLh* G2~7ZvBO0^- literal 1363 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 Q8UO$Q07*qoM6N<$f|`>jrT_o{ literal 2573 zcmZ8jc{Cg777rnap<;=>Qr!k4u{G92l$3N(A+4?Uq#7hqqC!#2FtyZDODU;XYAq~a9x0V1afdK%31kT3F zk?%1FCJN%;HRLPr_)Z|y(fTx?{-w$iKM@PIaSa6kepo&*f%$Q(5k7!OCb-aD>}*Z^ zXcV{)k>*Q+Gbq7)Gyq`6FyV(365R*JpafAvO&BQkKM^MU_@InXhy4km2cpzn>>Oa0 zv=9>P6x;x=qmBl{U@)@~;w2MDt25u*`58+6GMyf5fGLFfZ&WNKijpHDF9fS?)T{}JC; znjsE&{130cME_akt44$QoqxX|8vM4ef&u`Dp2k^O5Eufyf{3c~=Vg0eRgw!NjEFDE zZreI~a=+RZ7bp>+B&;j(Xgn5=jK#`A@<|3Imq~79Y%&S=J0PII$Y4fozAoR@_)v9$ zTlcw7k7!T!HjTH6LTPBk6X9Zi-YH%LFRb`f0KsVkOlZJB>e=4CX7X>2YPi#!3A!bH4ME@h$w4-b*$g{wYN~Fc8iJnl4ay}9maOncL`-NYd>g#*G z^@|g=sBAFQ=R`*g%iKlUH(VjY-=T$2oE6xXfIGSOvahX&8LjOcEZw$G49Z?tm@eEt zJn(G4JeV@@W7L)@m+W%W3po8lz|Jokq!(+o^qx!&aT-o>G|XwYtX^mIKg#eJqc>(Vk$jc%Xg5hocN40kDf(%6;_kO#hhK?^&+HV5Qpo z?AhDH<5X+MdSN3VO?BGXTR=hd;)ozazfPCn8$g^CxF(Ti-{(9-$_zBiCoXyCt?N%l z=RT{(C0hfV`#u18zcO!xn;^&EeKu6=cA6;`UWG7Y>+E~sTsh8aK*G~1Rq#}VDM;

pI$ag(J{XnA;EaF zP*?X&Q8W|{3GoogLYB&26k8RT2EOS|-!5Z+koOpnS26wi9B6WX&`=(*Y}s7Y`*hO2 zCZ)SG%Eq-GQS{09V&blh4sda--S1tJZFV}=WSkmXb2(!@?ZUu?aPuWb-kj5@%#hZ{ zUkD`9h&`CRufJEktT;u{=nGTm);ssuVc6RMKTw&O9poQeFE*_o80H8mnaH5e3MuEc`YfnTU#$%}6-_~8VqzYT! zcbFn?WN@=TOSen4mtW&T9)sh%hrjv?H6>C3qh0do#%3?=V47cLq@_5SBIwzG3kpae zO$2}hax>u>ig@NeNYHEA`B5d-#!L=%DDDOO8+zt}8gF7TR{`{;^EeWfc#qdV-)iLH zYi&xMNFB1D>22a=8T$sr(MvapUFdZaQFGA8WkuE``)8BVQb!Jy-aix7HH866oe5{< zOIM_29V46>xSO?N~A@)Ng*v(^`2UX42yuwD?wk z)$G|l$!*CA27VVG6gHU@8}Fp8o(@nVNZ(0$AZ@2Kk{+GU##gpL7Vof6KCFhqG{|jv z$HGEZsK-^yMj5)vb#rXouum|MjSkfVuX;MaL@TwjsbK2vl#fu-d=;E z(V;3fN9|BO5O3{qy(B{X*u9-AoQ!)qjvEywmRQc&Mo^tdU>sBvb`$@(>U5PxU3moy-iOw+7MLgM_1c-dlNgI@pvWwUu)NMvaO(QVv|>jjxMS!I75BpTe(~1a7Oe}C@PZEU3z}|jZUS@(T>sOJy;dEvc6o5(`L@?O}upGjNn!#qKt7mPre!eiF!p%dW zTfB1#Bln?Pw0LW{Ix|9g7hHOGs8Jr+rZi_U;gTbhvoPlTBUwr&PNLK>{8-}_xysLv zr`?e3KJro(Fn&pi7pYiQkp6Nq*%@wh)NgsG#j;(#J%;*bp)fa>{p6Nd(=A$eT}2Vz zuD)y$^pJw8Rvq+cdW&h7z$B)=`=bK}V?vdm%`bqGj(Aa6AqmS14=vwnrRMY%{osEAEJa5f# z*uHp+h|icv;%WzN#I+!u(N*r9fEm+omU?n_?pV36jhF-1+Sy8+(r{yY+#8h1yq9F~ zPT+o>RE#`_>><#?9*T?ScvubVP74rHMI78ijt@rJ2s`|&qeu)#JR6$5Cd`qefO3Lv z1G%da#1|IPna2xXG(XL;_1lf=yV%)$ie$^ROJ&v6C)cv>W4Ri5`w*PiV`WaQLtGTF z-aC_pufm-Ps}|Gj+_C9Hr~N)R6(s!A38h}|Xw#xVNs4Ye`u6ZZJ&g_E0=B4qlpQJzSWAxO8y4LB5?8!E#)g+%I(=st(8J54k8Mul6oc)1uXO3%hUUV zJR`~x3Xfl9A7|#V%$!wqC0nlEOnHRL{A~ziseWP&(1E~Yh!zH%-vIAUJI{Do9s7DC T7iE!n@JGX8?XBuhd&mD5SK5cA diff --git a/resources/icons/ui/vertical-ellipsis.png b/resources/icons/ui/vertical-ellipsis.png index 5ce9d78f26a1fc9d0cf445e10c2d458e45114f0f..6b3a36e36a9e6a6bd6e9eb1e5cc909f7046654c8 100644 GIT binary patch delta 390 zcmdnTwup6tN)SuBqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6@fg!CBxDSXAU3H+#A`hD30_o$AfkV8G$hd;G({k21Es-1-Y^kL5)qDCBzbOrB8J#-)@z z{b>7Ix!bE{*Bhqib8(b}?QYp7RYI$gMX7_^Z_~)??bkofx?`=xXoVZVS`)Z*3 O89ZJ6T-G@yGywp|%#2(B delta 548 zcmZ3)x{qywiZWwykh>GZx^prw85kHi3p^r=85jgNfH30;^{*ie42&rg%Pz-P=oc5!lIL8@MUQM!#jnu^JD8O`eN9AB0Tw6ECH#W5s;^K7_b-XRA86-UoiB3CA6 zOn5Od=+oR9<@$xsI4fCLA2DibXap?~5nP~h=0ruRZj4R#-Oe79Pjk!5^7nk2`!r6! zPci7(gZ0Yq4Z}p3L*kq2K31KRFg*I&d#83vMJN~N-+az|Y{kTj)2B}Tz&xGTf@%MO+~$}cqBYE^Ew`?& zsOtadoP6#f-=Edie*gTJ#abQsp2lRiEB(ij8peM+en&3P`OEW%?XTyF>Yl)0p7Sf- zh<_{2N^#k~F#q?`R*~MPuDlw@*DQLO1GcwbHlVC`k>US9<~vzH_vD&R`uOIy!IgEB zb<5snu?KE4jb#Q}uyx%p!>Yzc(I4-ChKe4Qxcc+v*W>xN={-`C7ju8KoXV-^>Iqa< z&T_C!6YZ7kk=k%1rg;Tp>U9mN&+?`P8_s-jxVU6}3D| diff --git a/resources/icons/ui/vertical-ellipsis@2x.png b/resources/icons/ui/vertical-ellipsis@2x.png index 9af0c042684fe607641381b415a36f11601a145e..4f28066b1e6357ef69b15abece3455583ac59908 100644 GIT binary patch delta 610 zcmbQp@rP}KN)SuBqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6@fg!CBxDSXAT8dOcknLn;{G&OCVbkO5Dtru(x5mSu??$C8+iC9s^!IUxDTrF!L*q_2Y4 zyXG%_A^!L8q+i*SZoS;_d3&(nr}mI?Y{KE{>Ops z+RhH!FJ(2JUw?SJHb=#(&kFT_+m>-3o)tgqo2kHsdWYLrzWG-FFYDudzadE`V?l0~ z9K(j&>rLHumz~-Fdfw9Gw@m(*%HCS`%#e8&+kvuoj0~RVqLQ~PGrY`f5U4cQX+PV^ z8)rUU=@igd>ffr)F@w`Pa$&XM7T1Flx5*sSnb6t5(E&zB6c@Oh_!!Ahwj<<*_P;Mj z16~zbd}-{cKR$8BK5hZ&ULf(oC#YXFVb{d9b8Hw4(tr0{J7QwXAgp>x^Go)Gp0hgs zb2%D=euY#t39OR{vdoD)S|q|KC;&z;dK-ikkE?Utco>wp{>No;=ar`)USL;}b5HuE z=a6FpBn}vR+D>bD>9(!t6T^WyZ;hjbFMnb1nc|_d{K9%iBeTsmrAjPbFM}U)I_*f( dsI~mV$ds5b_o6bx5SS_$JYD@<);T3K0RRl&{bT?D delta 760 zcmeyvHj!h3iZWwykh>GZx^prw85kHi3p^r=85jgNfH30;^{*ie42&rg%Pz-P=oc5!lIL8@MUQM!#jnu^JD8O`eN9AB2pz`*3@>Eakt!T2`X+l$#zptq}{v0=fE z6K*jT4CRr##6Jo&i5EZ2bvc?JsyNSh-jB89A)_VIkJD)ii#bCH$dZWOB(_U9j zDO)X=_9^a>8@t5%Bg>igv$fA?D`hWm4$hL2S!&7i&A#EewnFWB|Gj?kMJBn+PyA!` z5WOwGoWIsL_wbaz(`(w=#SaK>VBTKvZ_^tv zN37xf&!Ec>1d2C^IXw1=ZeBc#p(cOÐ?EOW8Xb_wuwb#Dy&ile@^cb;@_4>${ju zzDY^REULeEjj5&s?&A+R>#vwtcoj>$d0%I2vSU-d#W}<4Z_93cVNUZ@DLZsau0!Xg z0Kao%fP%<}r3WIy8zoQ0-JZR8&(X8dcQ2h>|HZ2I#qBLS|2MXLjcahfrD|WkJpc0X zN9|mHS07YdmUx#jI_b$DMqWO{Sz8&B67-oB8`7pvT`|?Y#6kDz-Xpzy263Fdd)wIB zBbJr2XUJq`7la5u2vw`_I=iAHT+^@?`&7DPYoO@O1TaS?83{1ON&|RYCv& diff --git a/src/ChatPage.h b/src/ChatPage.h index 6a70acf4..f032901a 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -80,6 +80,7 @@ public: public slots: void leaveRoom(const QString &room_id); + void createRoom(const mtx::requests::CreateRoom &req); signals: void connectionLost(); @@ -159,7 +160,6 @@ private slots: void dropToLoginPage(const QString &msg); void joinRoom(const QString &room); - void createRoom(const mtx::requests::CreateRoom &req); void sendTypingNotifications(); private: diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 35bfba86..fe63456a 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -317,6 +317,7 @@ MainWindow::openUserProfile(const QString &user_id, const QString &room_id) userProfileModal_ = QSharedPointer(new OverlayModal(this, userProfileDialog_.data())); + userProfileModal_->setContentAlignment(Qt::AlignTop | Qt::AlignHCenter); userProfileModal_->show(); } @@ -394,7 +395,6 @@ MainWindow::showOverlayProgressBar() progressModal_ = QSharedPointer(new OverlayModal(this, spinner_.data()), [](OverlayModal *modal) { modal->deleteLater(); }); - progressModal_->setContentAlignment(Qt::AlignCenter); progressModal_->setColor(QColor(30, 30, 30)); progressModal_->setDismissible(false); progressModal_->show(); diff --git a/src/Utils.cpp b/src/Utils.cpp index 2247c2b7..97e13c9b 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -2,11 +2,19 @@ #include #include +#include #include using TimelineEvent = mtx::events::collections::TimelineEvents; +QString +utils::localUser() +{ + QSettings settings; + return settings.value("auth/user_id").toString(); +} + QString utils::descriptiveTime(const QDateTime &then) { diff --git a/src/Utils.h b/src/Utils.h index 8f9b7cff..10b5ee2b 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -15,6 +15,9 @@ namespace utils { using TimelineEvent = mtx::events::collections::TimelineEvents; +QString +localUser(); + //! Human friendly timestamp representation. QString descriptiveTime(const QDateTime &then); diff --git a/src/dialogs/UserProfile.cpp b/src/dialogs/UserProfile.cpp index 1da293a5..34f81fa3 100644 --- a/src/dialogs/UserProfile.cpp +++ b/src/dialogs/UserProfile.cpp @@ -8,6 +8,8 @@ #include "AvatarProvider.h" #include "Cache.h" +#include "ChatPage.h" +#include "MatrixClient.h" #include "Utils.h" #include "dialogs/UserProfile.h" #include "ui/Avatar.h" @@ -17,10 +19,25 @@ using namespace dialogs; constexpr int BUTTON_SIZE = 36; -DeviceItem::DeviceItem(QWidget *parent, QString deviceName) +DeviceItem::DeviceItem(DeviceInfo device, QWidget *parent) : QWidget(parent) - , name_(deviceName) -{} + , info_(std::move(device)) +{ + QFont font; + font.setBold(true); + + auto deviceIdLabel = new QLabel(info_.device_id, this); + deviceIdLabel->setFont(font); + + auto layout = new QVBoxLayout{this}; + layout->addWidget(deviceIdLabel); + + if (!info_.display_name.isEmpty()) + layout->addWidget(new QLabel(info_.display_name, this)); + + layout->setMargin(0); + layout->setSpacing(4); +} UserProfile::UserProfile(QWidget *parent) : QWidget(parent) @@ -34,6 +51,7 @@ UserProfile::UserProfile(QWidget *parent) banBtn_->setIcon(banIcon); banBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2)); banBtn_->setToolTip(tr("Ban the user from the room")); + banBtn_->setDisabled(true); // Not used yet. ignoreIcon.addFile(":/icons/icons/ui/volume-off-indicator.png"); ignoreBtn_ = new FlatButton(this); @@ -42,6 +60,7 @@ UserProfile::UserProfile(QWidget *parent) ignoreBtn_->setIcon(ignoreIcon); ignoreBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2)); ignoreBtn_->setToolTip(tr("Ignore messages from this user")); + ignoreBtn_->setDisabled(true); // Not used yet. kickIcon.addFile(":/icons/icons/ui/round-remove-button.png"); kickBtn_ = new FlatButton(this); @@ -50,6 +69,7 @@ UserProfile::UserProfile(QWidget *parent) kickBtn_->setIcon(kickIcon); kickBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2)); kickBtn_->setToolTip(tr("Kick the user from the room")); + kickBtn_->setDisabled(true); // Not used yet. startChatIcon.addFile(":/icons/icons/ui/black-bubble-speech.png"); startChat_ = new FlatButton(this); @@ -59,21 +79,34 @@ UserProfile::UserProfile(QWidget *parent) startChat_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2)); startChat_->setToolTip(tr("Start a conversation")); + connect(startChat_, &QPushButton::clicked, this, [this]() { + auto user_id = userIdLabel_->text(); + + mtx::requests::CreateRoom req; + req.preset = mtx::requests::Preset::PrivateChat; + req.visibility = mtx::requests::Visibility::Private; + + if (utils::localUser() != user_id) + req.invite = {user_id.toStdString()}; + + emit ChatPage::instance()->createRoom(req); + }); + // Button line auto btnLayout = new QHBoxLayout; + btnLayout->addStretch(1); btnLayout->addWidget(startChat_); btnLayout->addWidget(ignoreBtn_); - // TODO: check if the user has enough power level given the room_id - // in which the profile was opened. btnLayout->addWidget(kickBtn_); btnLayout->addWidget(banBtn_); + btnLayout->addStretch(1); btnLayout->setSpacing(8); btnLayout->setMargin(0); avatar_ = new Avatar(this); avatar_->setLetter("X"); - avatar_->setSize(148); + avatar_->setSize(128); QFont font; font.setPointSizeF(font.pointSizeF() * 2); @@ -90,10 +123,26 @@ UserProfile::UserProfile(QWidget *parent) textLayout->setSpacing(4); textLayout->setMargin(0); + devices_ = new QListWidget{this}; + devices_->setFrameStyle(QFrame::NoFrame); + devices_->setSelectionMode(QAbstractItemView::NoSelection); + devices_->setAttribute(Qt::WA_MacShowFocusRect, 0); + devices_->setSpacing(5); + devices_->hide(); + + QFont descriptionLabelFont; + descriptionLabelFont.setWeight(65); + + devicesLabel_ = new QLabel(tr("Devices").toUpper(), this); + devicesLabel_->setFont(descriptionLabelFont); + devicesLabel_->hide(); + auto vlayout = new QVBoxLayout{this}; vlayout->addWidget(avatar_); vlayout->addLayout(textLayout); vlayout->addLayout(btnLayout); + vlayout->addWidget(devicesLabel_, Qt::AlignLeft); + vlayout->addWidget(devices_); vlayout->setAlignment(avatar_, Qt::AlignCenter | Qt::AlignTop); vlayout->setAlignment(userIdLabel_, Qt::AlignCenter | Qt::AlignTop); @@ -107,6 +156,10 @@ UserProfile::UserProfile(QWidget *parent) vlayout->setSpacing(15); vlayout->setContentsMargins(20, 40, 20, 20); + + qRegisterMetaType>(); + + connect(this, &UserProfile::devicesRetrieved, this, &UserProfile::updateDeviceList); } void @@ -121,13 +174,7 @@ UserProfile::init(const QString &userId, const QString &roomId) AvatarProvider::resolve( roomId, userId, this, [this](const QImage &img) { avatar_->setImage(img); }); - QSettings settings; - auto localUser = settings.value("auth/user_id").toString(); - - if (localUser == userId) { - qDebug() << "the local user should have edit rights on avatar & display name"; - // TODO: click on display name & avatar to change. - } + auto localUser = utils::localUser(); try { bool hasMemberRights = @@ -141,6 +188,75 @@ UserProfile::init(const QString &userId, const QString &roomId) } catch (const lmdb::error &e) { nhlog::db()->warn("lmdb error: {}", e.what()); } + + if (localUser == userId) { + // TODO: click on display name & avatar to change. + kickBtn_->hide(); + banBtn_->hide(); + ignoreBtn_->hide(); + } + + mtx::requests::QueryKeys req; + req.device_keys[userId.toStdString()] = {}; + + http::client()->query_keys( + req, + [user_id = userId.toStdString(), this](const mtx::responses::QueryKeys &res, + mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("failed to query device keys: {} {}", + err->matrix_error.error, + static_cast(err->status_code)); + // TODO: Notify the UI. + return; + } + + if (res.device_keys.empty() || + (res.device_keys.find(user_id) == res.device_keys.end())) { + nhlog::net()->warn("no devices retrieved {}", user_id); + return; + } + + auto devices = res.device_keys.at(user_id); + + std::vector deviceInfo; + for (const auto &d : devices) { + auto device = d.second; + + // TODO: Verify signatures and ignore those that don't pass. + deviceInfo.emplace_back(DeviceInfo{ + QString::fromStdString(d.first), + QString::fromStdString(device.unsigned_info.device_display_name)}); + } + + std::sort(deviceInfo.begin(), + deviceInfo.end(), + [](const DeviceInfo &a, const DeviceInfo &b) { + return a.device_id > b.device_id; + }); + + if (!deviceInfo.empty()) + emit devicesRetrieved(deviceInfo); + }); +} + +void +UserProfile::updateDeviceList(const std::vector &devices) +{ + for (const auto &dev : devices) { + auto deviceItem = new DeviceItem(dev, this); + auto item = new QListWidgetItem; + + item->setSizeHint(deviceItem->minimumSizeHint()); + item->setFlags(Qt::NoItemFlags); + item->setTextAlignment(Qt::AlignCenter); + + devices_->insertItem(devices_->count() - 1, item); + devices_->setItemWidget(item, deviceItem); + } + + devicesLabel_->show(); + devices_->show(); } void diff --git a/src/dialogs/UserProfile.h b/src/dialogs/UserProfile.h index 8d5b9c5f..ad01c650 100644 --- a/src/dialogs/UserProfile.h +++ b/src/dialogs/UserProfile.h @@ -7,6 +7,15 @@ class Avatar; class FlatButton; class QLabel; class QListWidget; +class Toggle; + +struct DeviceInfo +{ + QString device_id; + QString display_name; +}; + +Q_DECLARE_METATYPE(std::vector) namespace dialogs { @@ -15,10 +24,10 @@ class DeviceItem : public QWidget Q_OBJECT public: - explicit DeviceItem(QWidget *parent, QString deviceName); + explicit DeviceItem(DeviceInfo device, QWidget *parent); private: - QString name_; + DeviceInfo info_; // Toggle *verifyToggle_; }; @@ -34,12 +43,15 @@ public: protected: void paintEvent(QPaintEvent *) override; +signals: + void devicesRetrieved(const std::vector &devices); + +private slots: + void updateDeviceList(const std::vector &devices); + private: Avatar *avatar_; - QString displayName_; - QString userId_; - QLabel *userIdLabel_; QLabel *displayNameLabel_; @@ -48,6 +60,8 @@ private: FlatButton *ignoreBtn_; FlatButton *startChat_; + QLabel *devicesLabel_; QListWidget *devices_; }; + } // dialogs diff --git a/src/ui/OverlayModal.cpp b/src/ui/OverlayModal.cpp index 41e07a91..30ebdf5c 100644 --- a/src/ui/OverlayModal.cpp +++ b/src/ui/OverlayModal.cpp @@ -29,7 +29,7 @@ OverlayModal::OverlayModal(QWidget *parent, QWidget *content) layout_->addWidget(content); layout_->setSpacing(0); layout_->setContentsMargins(10, 40, 10, 20); - setContentAlignment(Qt::AlignTop | Qt::AlignHCenter); + setContentAlignment(Qt::AlignCenter); content->setFocus(); }