From 38d61374a5a2d136dbd4dfe80cf70eb40ce96b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:41:10 +0200 Subject: [PATCH 01/25] new mensa menu icons --- .../assets/animations/rive/animations.riv | Bin 2195400 -> 2250363 bytes frontend/lib/components/menu_card.dart | 26 +++++- sonstiges/menu/arrows.svg | 16 ++++ sonstiges/menu/currywurst.svg | 82 ++++++++++++++++++ sonstiges/menu/dessert.svg | 42 +++++++++ sonstiges/menu/pasta_meat.svg | 47 ++++++++++ sonstiges/menu/pasta_veggie.svg | 38 ++++++++ sonstiges/menu/plate.svg | 45 ++++++++++ sonstiges/menu/saettigung.svg | 22 +++++ sonstiges/menu/saettigung2.svg | 41 +++++++++ sonstiges/menu/salad.svg | 40 +++++++++ sonstiges/menu/salad2.svg | 54 ++++++++++++ sonstiges/menu/vegetables.svg | 79 +++++++++++++++++ 13 files changed, 530 insertions(+), 2 deletions(-) create mode 100644 sonstiges/menu/arrows.svg create mode 100644 sonstiges/menu/currywurst.svg create mode 100644 sonstiges/menu/dessert.svg create mode 100644 sonstiges/menu/pasta_meat.svg create mode 100644 sonstiges/menu/pasta_veggie.svg create mode 100644 sonstiges/menu/plate.svg create mode 100644 sonstiges/menu/saettigung.svg create mode 100644 sonstiges/menu/saettigung2.svg create mode 100644 sonstiges/menu/salad.svg create mode 100644 sonstiges/menu/salad2.svg create mode 100644 sonstiges/menu/vegetables.svg diff --git a/frontend/assets/animations/rive/animations.riv b/frontend/assets/animations/rive/animations.riv index 30878585ee0d8bbb0dde94fce2f6ca7eee836422..85e80866e502d72f6f8e7e22489da808a9caa90e 100644 GIT binary patch delta 61804 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%0ATFsDTm6r4ffIqvVM)SL%tYxm8satu+ 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

`TC-Dzdh_JL!Zi3n45a$?d)*VGjhF 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 H1!4JrRvKN> delta 6780 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 ? 'hin&weg' : widget.title == 'KombinierBar' ? 'Kombinierbar' - : 'Default', + : widget.title == 'Sättigung I' + ? 'saettigung i' + : widget.title == 'Sättigung II' + ? 'saettigung ii' + : widget.title == 'Gemüse I' + ? 'vegetables' + : widget.title == 'Salat I' + ? 'salad i' + : widget.title == 'Salat II' + ? 'salad ii' + : widget.title == + 'Dessert I' + ? 'dessert' + : widget.title == + 'Pasta' + ? 'pasta meat' + : widget.title == + 'Pasta vegetarisch' + ? 'pasta veggie' + : widget.title == + 'koeriwerk' + ? 'currywurst' + : 'Default', stateMachines: ['State Machine'], ), ), @@ -93,7 +115,7 @@ class _MenuCardState extends State ), ), SvgPicture.asset(widget.cardIcon, - width: 15, height: 15), + width: 20, height: 20), ], ), ), diff --git a/sonstiges/menu/arrows.svg b/sonstiges/menu/arrows.svg new file mode 100644 index 0000000..e92a4bc --- /dev/null +++ b/sonstiges/menu/arrows.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/sonstiges/menu/currywurst.svg b/sonstiges/menu/currywurst.svg new file mode 100644 index 0000000..acd12f3 --- /dev/null +++ b/sonstiges/menu/currywurst.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sonstiges/menu/dessert.svg b/sonstiges/menu/dessert.svg new file mode 100644 index 0000000..521616f --- /dev/null +++ b/sonstiges/menu/dessert.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + diff --git a/sonstiges/menu/pasta_meat.svg b/sonstiges/menu/pasta_meat.svg new file mode 100644 index 0000000..17a7862 --- /dev/null +++ b/sonstiges/menu/pasta_meat.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/sonstiges/menu/pasta_veggie.svg b/sonstiges/menu/pasta_veggie.svg new file mode 100644 index 0000000..a41690b --- /dev/null +++ b/sonstiges/menu/pasta_veggie.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + diff --git a/sonstiges/menu/plate.svg b/sonstiges/menu/plate.svg new file mode 100644 index 0000000..88bdc4a --- /dev/null +++ b/sonstiges/menu/plate.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + diff --git a/sonstiges/menu/saettigung.svg b/sonstiges/menu/saettigung.svg new file mode 100644 index 0000000..5274f88 --- /dev/null +++ b/sonstiges/menu/saettigung.svg @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/sonstiges/menu/saettigung2.svg b/sonstiges/menu/saettigung2.svg new file mode 100644 index 0000000..92ded5e --- /dev/null +++ b/sonstiges/menu/saettigung2.svg @@ -0,0 +1,41 @@ + + + + + + + + diff --git a/sonstiges/menu/salad.svg b/sonstiges/menu/salad.svg new file mode 100644 index 0000000..fccffcc --- /dev/null +++ b/sonstiges/menu/salad.svg @@ -0,0 +1,40 @@ + + + + + + + + + + diff --git a/sonstiges/menu/salad2.svg b/sonstiges/menu/salad2.svg new file mode 100644 index 0000000..f8e530a --- /dev/null +++ b/sonstiges/menu/salad2.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + diff --git a/sonstiges/menu/vegetables.svg b/sonstiges/menu/vegetables.svg new file mode 100644 index 0000000..2bee170 --- /dev/null +++ b/sonstiges/menu/vegetables.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + From fc0dcd28090325a9c553aba76a90c1b70a53483b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:51:32 +0200 Subject: [PATCH 02/25] meat fix --- .../assets/animations/rive/animations.riv | Bin 2250363 -> 2250744 bytes frontend/assets/icons/menu/meat.svg | 7 +++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/assets/animations/rive/animations.riv b/frontend/assets/animations/rive/animations.riv index 85e80866e502d72f6f8e7e22489da808a9caa90e..d75e4452fdfcf45401e5e23faae9711dacb9efce 100644 GIT binary patch delta 19340 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 Zsd>EASniwt#kHqx7(_J0k@S=#^r delta 19184 zcmZ`>30zdw{=au%L=g}Lm0`Je1_U*CN8DvL+|j2wi(85bqn2B0>+=N_mX?`XafHm! z)ZB8(1x=F~FmnNyG|e=l&CHjY|H{`h%m4Rx&YfZKy~pQs=gaT>mh(Hmv!A>CzHO2G z$CgEMVUb*Xrk+83+l$be3QXEfZ>-t|z#6M*+{l}gwH>EV@32Q~d$Z1M*mY1(|kG+&Q zpr*RIA7p>mLG}`h-EC^lD)JRu(@SKbD2!4Q2S`$(h0XUWt>QkUT$=G*WFa84x4lXR z`(lqNmbIUvv|<0QHpZ~iUS%kAPEn@I3)rolrasI!MR|boD=jI>g5p(?-<>JST-I=! zGJ&1gZHi&%rz&08>XSyLJa3v}k|VeiS9NTJS82&AP8w5~?-8Z61yBAu#5c)cULmvR z_M4KC1+4#B$79K#8V$NP!`SLm#<=iz!?I;|_)(=h8*>_7E_+nzDKBFFM-btO(-lkV z`3S9ex8!UYR$nxL?gWd)P(&EYtjsrE+17WrUJEwlv}l)5i7tv*fjJjSzXh3ZhcMan z8A|)4y3pU!oUN%|Y(bXq>si!3Q$N;eCZhWD48_9Un5ifsp%VpXl{1wG8=tQ8mo=HC z*jcJQHNO1uSxRqtV3ySHO<5;dC5vQZvMlv_S&qn=^mP6lV^`wHQkLMLorUnsA~6h! z+<;Vmd$y7lBd;pYEKm%F_%OW`eZEOEN6d4bqaDw|N`$_YOCO=vWp;;wLhFrypOBA)>l$vR6NTL;n#op{Du(F^^injI+A&Uj>+PoJpEKC&|0a1*A$w>Z$rjwIZl$@zhjDS*2$B zBXasZ{NcaPl9+wz7KW8($5S_Y##i&FakGwXwoAF%jW@yZ3dAX9XKh5(Ocla_;@N$>-Yi&?6M; zqjLJ+a(<*xpQ{Ts0&L&`PE05*d6)cu+wXR4Z}0QWdvO)Hl!(CZ@f&KYbNtTbwFwoj z)AMasw?94I>Nz~Ph%zJzeI=asRZt}lt8mp+PY+>uy;(N*Yu}!-cy70RTcn%K7pRnn zY|iZu!NH6N)>+*suf-EK?`0w3^^T?5{+j(`rIOgNv}BA0W&VV{vr5oA1}?ZaEHz21|(6dHE2Fs zP(gS)YQ^VX(4?lqlYgaJcoPhbvuX0hf-Kj8XO38dk!y{}g;&D8ofV>2)KqUFwbqEs zRx0LbzkACO1-+%`c*?#tnt{ZN;1^9+lBU|~wOEqaYD3Id_?`DE+WTCSUwzT)wjVm5 zI{p;3t=(+=vD3;{N399_QHs|JM$re}XmEWvh_k(e%K9Bd4 z_X0*xdRXGM50R1*YHi2l^y_zd$37oyZF00Eh1<}vy>>*;%-dZzL@Cw>H@8~dk)F8} zrArj0ZfyGwOk3Sp-!cvp1QZJB`2kNHD`38WRRVkha#nMZnF5xsR$8__u6fc-|9L&1 z;%zZr?2VpFJa_Rth*MpjN>2cNJ6P>Y%R|SjXK; zOV!O?^T1-Z9gQubQncx}uCC64MGrdxE!o3<7O-JAr;Z8uNkGgVp4eHyfwi2v%%ON4 zC-w@~7Xt1IP|8s-4=Y>8VR$*0oGsw4&{Nj)MC*E`WrT2a2AfD}Ggyng9C`{ED`38W znD;oZivXv9Cjpv~Ct2Bh$n;6Jk62H#O9JkR#Ik)nvCjq$69habpv{LoafpEF0+tBq zyiqZYdlF4Mi3Wkre&@0;pRRDFjSI7(-PQ!-{zXU|DJ>aokCCJZY9k9}UK5LC^!q3~ zI>+;V_ix3Wt)5plDAZ{dvG+GBsaOh~0_YaWZ03H&M7R`)fDcvCE+JpX4y!qwCVZr{YYO*Zoi$LDQ$cfIvaEwj%Z8hUxh?FWgGz$Dg*AO2*0!*c zgB%VB_)5Urg6Df*NhmlSG;}#6CSGrUJ9=?ripd_btk;*z7+V~6bl?V+f-EiRMpeGv zFUXqeCRBfid;#Gel_2%@0M|m}S_6%QDI)I;unD%;Yo+~y*=2fl*4sg%N>GS5zlkneJIlW7l zE|L_l55v_MmjRaurnLLV%?v9R;Y}q4%XW>3=ESZ&i)`S;aKe0d zx{VbKR0p#czf+RrL*@V6rerr|H%6;bvX%AqE15CJ!Wv0Ei~C1Pz8CucB(oR%N}EhM z+UqU0p>OHzQn+3hkBP+6oPH32<6-GKcA1uha&%4gcA7b4lG3wUztXaRR9D%sh()&y z*Eg)ET2oK8jHIGTs&PH36CqNPw3ghsYlBowJ*kr+Qkdn*4a%{NzG*$NQz2rQx=HLh z8H;DDDwUSwXaW8@<#3h~Th>$kG(^?w-DE@OZbsfF#$$P7X-+@XG(x0k0R*XVl1gE* zRXiM$w3iZNDbZL@^|KJw(vpwKx27bOR!{0&h!obK^8A0ky#?IS7l5rm^{ zJ+aS2#3bpBU=6fqC*Uo@;q}g>d6(zVsh;W=A*!V%uaXqypzm5w>f-%UX7fD?Z6>oG z;^DxigbLb(RD0G_{W3(AyHQ#aMpAw1NnH++((3)+ltETKsjot$Bxwuf_$8#;=xz1H zYD2`Zm7+4;AY<9=FL;Y^)Knj#%DYO51M8`N6QXK1zeiF(k<^fSQs0J1@rEEtpOe%u zHv40xH^wEr7{#`t$XeDGF4WMn-<-viLZl=qml~tg zMv85ypUfxeJhtR8yvf7lm`w}n>9krNT;Xcf>p~U=>O4#ko%y!ThpAGdu=(_fg*-oB zp>(sk9j&B`xwgesb!urqyOxIa1~i|LHYf~Tes0TbPNE#M{qBoV$kJ1FDwYE_&DW6cC2}gK7h0sATQ8d~Vv=YUp z^20)GpxEvF2+27g70Vhd7KM;DbQ^t6DlS5ZXi(5JZL6pNv$-)@ZXeV}poL$tl!t^0 zNThQFUNa)*V4xY(sv4m^%0p{5_o2kw){wl2oeMTX%hxAVrNp+@xq|wmjYx)#+gb%- zloff>VrGT5-Q-ae8CylV<{ziZY*atA1;hL${FX>+L#VcvPBpbb+xLaYTPeMaeFj_J7IoPslJqBvL!dT34M34HQUjG&?!wM^4WHGIV1Zkm;5=xrQztoWx z#I<21CoGha1q4P@0g17I7nD>2Tny2)DHkehAyZ&JDmhT!s$ zQU?l}*hqA=+Y9dQ%CarARRDqgvwP*1wjqyagrD?!Rsf$)oKr)wZ#gGSbI9%Z)tN6KJ@PjPmfEDD5nbcCz+{W z#tR%A0=xni3D_dwB%pJsCFjD~>nyGt6F#Jog_lXMKdM9PT2CXv8d?(^Wu`9>=cBCm z7qEYnJtUwIkO)!qnAYfQ{k0axZ{3j60ipDnkp3MoD%7yJ$-y_T!R~gJtYI*qgA;c` z?*i$6^6?;p-K>=S22>+7vS_>E=V8)k9`#~cRz8`f)89rUp!B44D_(?m|z;gLj zism&cBe=9w$4ZrR`Jzy8+1Fp9Wn5$T0NI+sn`H23TOeXZnn4UoWbh^#{Mj$ogp?+B z0Rb+{y$pjl*|V3G*4TK34sySdzk2;`3T_F_1MU3*avu!?XMKXKslH3(8yX4sX|O#= zgDuy^x~H_HISsZTsbWBO&`7innuQWLSwL()Y;Dk#VT)SyX3aGGpw(RmItjZGmfo`Y zQ86^*9s}(mchb=Od>Hrog)rE{CaI=+J$VfhM_T09!XSByxKT8Db8f7y0A+lhJmGXh z8rRorWNAq+D;!y;k;scm!88){4V5Aw?DZa|iT~}OsRTbVZb4;&Wo-vB#V<%&V`yF$ z5F1-z3+Q4h)m9?E)=00nK-eO;xwM|#9ug$`(OM)~BPA)@kDT7nlwq2LGbozS<=oPe z9l?w(0G#GgZ|v7oeM5*_uJX|P!%%J?ot1UoWGT1na<>Bc9b`<6y} zy)RPx;tO8RJxVKz=QXa`97cdJ& zHaayCzK}!4w26RpfJ9p)QVI(HLX9sjNMh?u^LD^#*$=lCX(V=FWH|>L4iu>Xq5hU^ zVOrOU_-|Tp4)6&QZJ68A$eQX)B+MI|h!%0@`UASisit~9Rq`z?qt4-e9xbELge`O` zbP&feRbh0nv;oJNkK1u>%aXrUjPhaD?^`9U08cT{@wE<@9#=zLbc`K?t0}H{TrF`W z;!43~#Fd6C16NyI?QwO&)fHDJuAaF1;L5^f!$rs7191((H4N8CTuxjbTw`%{c?dtb zxF+NJg^t93Bv*c;pXcdJeL4NCp`R-HIUL3guD}yP?Y~pT{_lq^4wtX_PC3^iQlmx1wpHjM}o9Mjw+M$Z~{++ zlvVy{ym}zIp(c>UI;EeH=NWFs zaWiF8QyoLMT29!Vd%W!}u6x6@bbdnMy%KeQHq+BoldNY;($tm)a{ehA^|spGryHq0 z&lk%TZj~Jr?9!40ba$oDexI*5gpt@*+=$l;snU{>HuufWZG4{R1~=g)W!6@zDNUbH zYOqy-UE_C7{VOiZ^+%U2Hg~I9i_f$C`UxRe1VQ+;UceCn*8pAg7^cUQ_F=oT==Wrw zYvFrOh%kDu^shpndCczK_V9}pbz$tA&TUOd7p`3yScL*yvAf&+k<3@ZBF7~{YP*oC zseX^{Dc!r@RxP9oP=JyrDGE^zCuQXd)EHcYTB)I{!+q|(&$2wl4jg8S7Ey$;@yZy7 zbHT~3KG)w{B?r=ts47DjM}3zubmXJTz3m;&Zyc?CuDJs*Tiv6_>Mgub-87R=QKRYS zaQ^t@f(kCe)A2wGsXpv*pX#?M%cDHmS=8UI3?7AZ0)7{e*qSHy6)>T-+ENvbxNCys zD{>$LL+$R|-^(qY+)XF`Obnf z2VMV+xo34h@qZnxo}m%^F_Erpt&l$~;HrSgw%k^G0mB8%2Ee4*yp(*C9L|SV_wu3JNrlU(+qAYjb4}YV zt`GLlqF4-Jx$O~)A?zt3Tq@vzfXf_;J7`5bK>h2bO6T@$j6OzUr$rMia>@B3A-`V05dqf(M0Mh}Itmy8fJsd7=($(^R^?1<-q7lb zm^0Su&U>b)!lUmvQxxJ2A-_k!=K}5sNbbx{W(mjzP}NtXCzcvsu5wPC8Rv7I>$U|C z&^$TX;`u)PfH1jM$R8GPRX}7HZmYe3;R0p@c)`=Dv9+#pPX0E`hpo#PtNZt6i!GkH z*%O7yT|)kxfZqiqcI77f3YZ|E5I`oq6R5c)Ryt?4iSfCLkHcL|e+ zg!~l&4b7^lXGpVmwwavmbN#g#Px1vi#ZsKu&?R1=WdG>8Ef3)qIl2+_IMu@fY*j{QKabu6+w zhYkWp2$(CNSin93mjv7sklKUm^%pQzz$*f_3OFs`R{<@1a)sUk9uiO};9UWS1^g%= zsux%2B;Y{-j|*5KV84LN0_5IYp_PDv0v-|Ys(|eR&Iq_Iz|e>5^%XD?U|vV(bI;Rb z8VBso=)NgF*Ul9SX>Q?+Tw=_&yAys3^LaL`!Ojm1woB-r7jQ>FN?&f<3P^;mBt1a7 z@iyn4^Qk`mR3q1&-=|xTTZak3&Ss`a%_YbyOuv$jLQCR#u8znZJZ*iZjKIR^;?6 z8!2EOzys-0!`dp?{;)FS?wqh%_%bot(8D@p)rU-QkX{+=`F~Pd*hYyHE8Tdu$mjX? z!*-O_pX@s2@h6M5aWD&T1KL8Vbj+)yWb!*-T8wqg-XoW2XGPW)FDAxFKew^krX~yu z&BOVx-Fk~l-f^+6@Gs#grf>zh$?uPWG|$~nB<}MLeX5(!^VU@pdGr#K?QrEK)=I!Y zKmkdcF`Loxfivt6i_gVFrPqT|Q;m7j>&2pyljfZuYpU~X*m`}V3!GqM@xRfS9U~Q9 zbs#9q#Np0zSl#&tR%Pbp6giNk7g{)=ypnc^oLfWO4F&Wh6R}IuXG=XxF9jX31P2y3A%E|08UP$oUm(=e62OM*?bT_u5TP9Ye8OF7Bn44wNgn1LdKOWi<3Q^;!%b5szjsw zUYBltzZIPa=%OXxZU_82Nq$udzp7yDN~bE6D2<{4k{)${@(FU2xL)2U`K>#UQsHA1 zjUUJ_kmj9FIIy@$as)`bqcz#m=+csZk)JJs(o?BQ$8gi^dVe0Qn)#+|w2cGg)Cu9# zN%EpQ^@Vg21zD4G648;i({TuK4WAI%kir4dY#v~TQ~c&2NUwJ;ky(^035%yc$7&=F zFzGyKFV`JP9r{!1R_PjBlKw%FP7NyOQZH*jwFFyI;Wmo&V80;Y7I80glARo&wqVx= zsJ#r~IHg!d#~179r<{H&>E{INJ5WuMb!_xNbvAqSE?yt{e4uKP)5{YEspoW={2+$j zHo>gth#7S7C_U_y5kKpNE%xU0gZgZjp81(_54PyUCK*=-OB<@DHs2~s$(G6;sTSL= zKNn=-?2v$s9jYpFV`lWKEo0l@5x{gQ9dGP(8olf-=^iT^s*YiiIjSWlz>-IkaW)`F zRaz!N9FGq=`ew`G*+EBSc6k5J>~s#^b6K9Fw&|USbb9$J5+=I<+X1@{pc|Qz!Cc=Y z5_FK>pp&{f`aToKVuq=sk}^aNcv`X7owg2<2?#5S&7K*i+L8?BG^AGPcpk_bw#zC( zbjAx!9}ZKyW@>Nqgo$^1_&E=bYV<4Q*fRNQM96uLj*f72D`ed&Ij`I_T&;;@%ExL{ z7+&~ce~wmFc_K?0qkf>gF4qNrvwefEgA^7XF>3a-nKSd}=p)&`2C0kLvt!ki#K>5j zt67@T4{lUSd(n8~`1wveiyf>c%kga15e{X8ID7R%5Ov_2E;}A7%a@uko0%c=59ooyo=}nt9y(cY|^{rOxs#csnrY{5c zjzdeibH)Eh14^;lw3Mq?m+g8C#~ zOE1d$4s793#H4ppu}3YVq+Z9YJpIhL12)5xqvqQl{Ayf^b<{`0 zJ+u-X%#Ke`t#UStny9A953Yxi4Z!xi4Z!xi4Z5F4c`<%O|SlqzAQ# zjYUwT=xv|3b;PXLw3$Y}@vL^D8b2xIc$x;iR=DVRxj(K!xJKa`kLREpcfzd+8~%w4 z{F98QrgLqbvXQLiBvp-!L^=&<&tx;}Bpj0TXVWIB$<6*lT-Z$>32}^;7$aw52Hcw58QhVrm z;i1)wP0FhmRV~ww?6o{KQw|!voTpAp`>&;}7l+;y>TYaRJ}S&irsLSrd^JUm<8x$u zplqldK1afVMD|0z+S3@c5{IgZnmlXHoczi2jMHb$nk|CD9zl^~f>KG)OlJGMY7hAV z);LE^m(!@+mXPK#Vp|SHFNHljOzoFwFt^jHh|jZBNtouimG)EBQEc-Rb#!9DJmyf! z-~nhX)=5ibM_;zYi&CVr`BT+t1^nI92%7RD#FQs)Ven~EPs!oZz_(<1CEjGkEe}37 z$~+}V;$gkO{E1mLoOBv!ruglWjr^_(H`qY3N^*FUQPcDDF;7mxP*?u=vuaHeUgw6E zxbfnerY?(f$(dWxm>- zJ+oEK;eu$2nr`h@bp&>jFdRmAbi}-W-%GwcOHpE}eB3s5NrdTt-r5Pg4$LCU)lPIT z$GRpvQpz2T*B->ZoB`!(dS+P2lpIyE*%#9^> zh;fLm%2ktC!d|Qi!dT{BHD7MTE)o^aTLJrRulig(FJFC^v)Ie~uu2(TzG@T0%hMn@M9oaXB)#j|guRg~n`c-3br8fn`{*J@i|P)rHSOuVYgS5qH_xu#eSl>8OF)i>QG?D*`nj z@mXR2daEO5R&}-muU_le>W|U$_3Yk0wS7T@XA{DfdlN zNC{3;clcrlDZy##nQU6@G+3&OSgZ>hZR`T`O#?6b&{{qM7dB{WkML=E)AM^h#fO0g z6u{J^z;G5F=%6cfVcj}+L#0HpGl$hyaziFps&R4y7WIj`iG_7fjf;uQnKpM`KGvDW zF150*{QM{Cz%bmr)aDo+>v$YPYAdY@b^Y6mHT>HrRE0fuTs;&MV9BFtj$i|-Ra2dM zB+IK-d$G)FHJ8spVkksXGT&#JB{9K$1%vgc|y%#El#5M?mwZ9>(~tb#$qT7$8?tjG!lyF z@Hds}GZ;ImW<1aUIyC&zwjvow+lrJxM598P?AS@QUqWbiL8GHW@ZyxKr_|jBX1u1h zWyk)ZMzPC3s#ezGSv9?hHgIrFd=r3KwyA3Q%4=%pDAw?{DW?33+v?CyBfJ)C+sxa2 zS*tw7NFSqE!Ui5Qn%K`rjUM*JQDY0;-2_&)%k%)7dd%oz-f2pU1_tgY>yWRgx~~na zaF3}4d+@l?^k2UrG5ff2bm*rdSo3OQIxF)kX}UWJY;_*KaMqF)B0iT5+g{2AXv3;flw%{z{k$%=VAbJmdd!iXk(l;vDduNTq+wplQr2W>- z0@~*sLT>yUKQsC-v2Uj-9ogF-m{N2bo3SO+6c_t?2Ld@;;|r#>)k)Vy&1#g>g8se6095B9D)lM6#ScrWE>$NON6HQ|8ZC z;#l<_*u1&NG=@zpH@S2-4QyMDQDq0qO|x-xqHw=SWy#Z(X7a1d^r#Y#mpWr+Dc#tn zy{23?c%LbsMeak^whv8|Od@Vl(8!pH(`DWd~m!l#e=Qn%#<-ZkoC= z{|(cGa@S2$RyZ5;t0{xM{)_1_EBMv)bQ%q@<51=Ev3`w;JZDE)=mR5xB*y~3gBgFs z(AN1k(--0JEu7h&Rg;|LBB(HoHFchH7j;MqHq1I+H$Ez1($jdMUnj{FD&_yUZMvav ztc_@7pFMHcWR%yGv%99fN;KaIHPdg^(L}_?C#4QbNVdFI`CC6Ly#X)rGoTg|Z}qb> zJKLU=+LnEvlxlPr)6okp4%X4PS$619!s$q%!=0zFANW8wV0rC)JE&c92+7|U4G5I| z^iZe(k!)OYYAbmMD@;yp>BcJb{wydZBn#svYp4ZI*2`kl*eRg`M6&D2sU6rzJltBa z>%VwCc=py%4PJAXI=C!e9=D;}r_WZk<>!Y0=qD`P5RIplPd+B=+be#g5Ou z@PF~`AiU$LIF@T9-?xaVEGYcnW!ch{)YO7Kx&hL51Ck($a*;vkUCyrxDpq_?ig!}9Bn)bHaWwGjt{ K3cKV + + M0.8,54.4C0.8,44.8,21.1,33,21.1,33c1.3-0.8,27.2-16,52.8-16c7.2,0,17.7,2.9,24.5,6c10.3,4.7,20.7,17.4,20.7,26.7 + c0,12.1-22.9,23-41,23.7c-6.2,0.3-12.4,1.8-18.3,4.7c-15.5,7.6-34.9,7.5-46.1-0.4c-7.6-5.3-12.9-13.5-12.9-22V54.4z"/> From 6592de19f62689b7e1731c95f2ac9b3d95af4ecf Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:55:20 +0200 Subject: [PATCH 03/25] fix score time calc --- .../mobilelearning/models/quiz/QuizForm.java | 1 - .../quiz/socket/LiveQuizSocketTest.java | 48 +++++++++++++++---- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/quiz/QuizForm.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/quiz/QuizForm.java index e4dc9f2..3b10461 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/quiz/QuizForm.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/quiz/QuizForm.java @@ -471,7 +471,6 @@ public Integer getParticipantsAnsweredCorrectly(ObjectId id) { if (result.getGainedPoints() > 0) { count++; } - break; } break; } diff --git a/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java b/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java index 8dcae2c..63486aa 100644 --- a/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java +++ b/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java @@ -940,15 +940,17 @@ public void testScoreAndResult() throws DeploymentException, IOException, Interr List courses = Helper.createCourse("Prof-1"); Course course = courses.get(0); - // make 1 prof and 1 student + // make 1 prof and 3 students MockUser prof = Helper.createMockUser("Prof-1"); MockUser student1 = Helper.createMockUser("Student-1"); MockUser student2 = Helper.createMockUser("Student-2"); + MockUser student3 = Helper.createMockUser("Student-3"); // call the get courses endpoint for each user to update the course-user relation given().header("Authorization", "Bearer " + prof.getJwt()).when().get("/course").then().statusCode(200); given().header("Authorization", "Bearer " + student1.getJwt()).when().get("/course").then().statusCode(200); given().header("Authorization", "Bearer " + student2.getJwt()).when().get("/course").then().statusCode(200); + given().header("Authorization", "Bearer " + student3.getJwt()).when().get("/course").then().statusCode(200); // get course and quiz form id String courseId = course.getId().toString(); @@ -958,6 +960,7 @@ public void testScoreAndResult() throws DeploymentException, IOException, Interr SocketClient profClient = new SocketClient(); SocketClient studentClient1 = new SocketClient(); SocketClient studentClient2 = new SocketClient(); + SocketClient studentClient3 = new SocketClient(); // connect the prof to the quiz form Session profSession = ContainerProvider.getWebSocketContainer().connectToServer( @@ -1010,17 +1013,34 @@ public void testScoreAndResult() throws DeploymentException, IOException, Interr Thread.sleep(100); Assertions.assertTrue(studentSession2.isOpen()); + Response response3 = given() + .header("Authorization", "Bearer " + student3.getJwt()) + .pathParam("courseId", courseId) + .pathParam("formId", formId) + .body("alias-student-3") + .when() + .post("/course/{courseId}/quiz/form/{formId}/participate"); + Thread.sleep(100); + Assertions.assertEquals(200, response3.getStatusCode()); + Session studentSession3 = ContainerProvider.getWebSocketContainer().connectToServer( + studentClient3, + URI.create("ws://localhost:8081/course/" + courseId + "/quiz/form/" + formId + "/subscribe/" + student3.getId() + "/" + student3.getJwt()) + ); + Thread.sleep(100); + Assertions.assertTrue(studentSession3.isOpen()); // check if the quiz has now participants - Assertions.assertEquals(2, courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().size()); + Assertions.assertEquals(3, courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().size()); // check if the prof received the "PARTICIPANT_JOINED" messages and got the right amount of participants Assertions.assertEquals("PARTICIPANT_JOINED", LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 1)).action); - Assertions.assertEquals(2, LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 1)).form.participants.size()); + Assertions.assertEquals(3, LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 1)).form.participants.size()); Assertions.assertEquals("PARTICIPANT_JOINED", LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 2)).action); - Assertions.assertEquals(1, LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 2)).form.participants.size()); - Assertions.assertEquals("FORM_STATUS_CHANGED", LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 3)).action); - Assertions.assertEquals(0, LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 3)).form.participants.size()); + Assertions.assertEquals(2, LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 2)).form.participants.size()); + Assertions.assertEquals("PARTICIPANT_JOINED", LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 3)).action); + Assertions.assertEquals(1, LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 3)).form.participants.size()); + Assertions.assertEquals("FORM_STATUS_CHANGED", LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 4)).action); + Assertions.assertEquals(0, LiveQuizSocketMessage.getByJsonWithForm(profClient.getMessageQueue().get(profClient.getMessageQueue().size() - 4)).form.participants.size()); // change the form status to "STARTED" and check if it was set profClient.sendMessage(""" @@ -1052,16 +1072,26 @@ public void testScoreAndResult() throws DeploymentException, IOException, Interr } """.formatted(course.getQuizForms().get(0).questions.get(0).getId().toString())); Thread.sleep(100); + studentClient3.sendMessage(""" + { + "action": "ADD_RESULT", + "resultElementId": %s, + "resultValues": ["2"] + } + """.formatted(course.getQuizForms().get(0).questions.get(0).getId().toString())); + Thread.sleep(100); // check that the result was added - Assertions.assertEquals(2, courseService.getCourse(courseId).getQuizForms().get(0).questions.get(0).results.size()); + Assertions.assertEquals(3, courseService.getCourse(courseId).getQuizForms().get(0).questions.get(0).results.size()); Assertions.assertEquals("2", courseService.getCourse(courseId).getQuizForms().get(0).questions.get(0).results.get(0).values.get(0)); Assertions.assertEquals("2", courseService.getCourse(courseId).getQuizForms().get(0).questions.get(0).results.get(1).values.get(0)); + Assertions.assertEquals("2", courseService.getCourse(courseId).getQuizForms().get(0).questions.get(0).results.get(2).values.get(0)); // check that the score was updated Assertions.assertEquals(15, courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().get(0).getScore()); Assertions.assertEquals(14, courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().get(1).getScore()); + Assertions.assertEquals(13, courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().get(2).getScore()); // let the prof stop the question profClient.sendMessage(""" @@ -1080,7 +1110,8 @@ public void testScoreAndResult() throws DeploymentException, IOException, Interr Assertions.assertTrue(LiveQuizSocketMessage.getByJsonWithForm(studentClient1.getMessageQueue().get(studentClient1.getMessageQueue().size() - 1)).userHasAnsweredCorrectly); Assertions.assertEquals("CLOSED_QUESTION", LiveQuizSocketMessage.getByJsonWithForm(studentClient2.getMessageQueue().get(studentClient2.getMessageQueue().size() - 1)).action); Assertions.assertTrue(LiveQuizSocketMessage.getByJsonWithForm(studentClient2.getMessageQueue().get(studentClient2.getMessageQueue().size() - 1)).userHasAnsweredCorrectly); - + Assertions.assertEquals("CLOSED_QUESTION", LiveQuizSocketMessage.getByJsonWithForm(studentClient3.getMessageQueue().get(studentClient3.getMessageQueue().size() - 1)).action); + Assertions.assertTrue(LiveQuizSocketMessage.getByJsonWithForm(studentClient3.getMessageQueue().get(studentClient3.getMessageQueue().size() - 1)).userHasAnsweredCorrectly); // let the prof start the next question profClient.sendMessage(""" @@ -1126,7 +1157,6 @@ public void testScoreAndResult() throws DeploymentException, IOException, Interr // close the websocket connections profSession.close(); studentSession1.close(); - } @Test From d5ca6a49389d41d4a6249990a2adda95ac4e3948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:08:29 +0200 Subject: [PATCH 04/25] new icons --- .../assets/animations/rive/animations.riv | Bin 2250744 -> 2259732 bytes frontend/lib/components/menu_card.dart | 60 ++++++++++++------ 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/frontend/assets/animations/rive/animations.riv b/frontend/assets/animations/rive/animations.riv index d75e4452fdfcf45401e5e23faae9711dacb9efce..aebaf227cbc89cc99852a0dc678fd7773364b7fa 100644 GIT binary patch delta 11424 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 H&k+6}sBfF- delta 4795 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 ? 'hin&weg' : widget.title == 'KombinierBar' ? 'Kombinierbar' - : widget.title == 'Sättigung I' - ? 'saettigung i' - : widget.title == 'Sättigung II' - ? 'saettigung ii' - : widget.title == 'Gemüse I' - ? 'vegetables' - : widget.title == 'Salat I' - ? 'salad i' - : widget.title == 'Salat II' - ? 'salad ii' + : widget.title == 'Gemüse I' + ? 'vegetables' + : widget.title == 'Salat I' + ? 'salad i' + : widget.title == 'Salat II' + ? 'salad ii' + : widget.title == 'Dessert I' + ? 'dessert' + : widget.title == 'Pasta' + ? 'pasta meat' : widget.title == - 'Dessert I' - ? 'dessert' + 'Pasta vegetarisch' + ? 'pasta veggie' : widget.title == - 'Pasta' - ? 'pasta meat' - : widget.title == - 'Pasta vegetarisch' - ? 'pasta veggie' - : widget.title == - 'koeriwerk' - ? 'currywurst' - : 'Default', + 'koeriwerk' + ? 'currywurst' + : widget.description + .toLowerCase() + .contains( + 'penne') || + widget + .description + .toLowerCase() + .contains( + 'nudel') + ? 'pasta' + : widget.description.toLowerCase().contains( + 'potato') || + widget + .description + .toLowerCase() + .contains( + 'kartoffel') + ? 'potato' + : widget.description + .toLowerCase() + .contains('reis') + ? 'reis' + : widget.description.toLowerCase().contains('pommes') + ? 'pommes' + : 'Default', stateMachines: ['State Machine'], ), ), From 5ba827dce0c1d962916a56e195b22736e23e4673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:09:16 +0200 Subject: [PATCH 05/25] new svgs --- sonstiges/menu/pasta.svg | 34 ++++++++++++++++++++++++++++++++++ sonstiges/menu/potato.svg | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 sonstiges/menu/pasta.svg create mode 100644 sonstiges/menu/potato.svg diff --git a/sonstiges/menu/pasta.svg b/sonstiges/menu/pasta.svg new file mode 100644 index 0000000..1b27255 --- /dev/null +++ b/sonstiges/menu/pasta.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + diff --git a/sonstiges/menu/potato.svg b/sonstiges/menu/potato.svg new file mode 100644 index 0000000..9177dcb --- /dev/null +++ b/sonstiges/menu/potato.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + From 50a44615ecfc5aec35adbad84376bdf53f0ed9f3 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:48:11 +0200 Subject: [PATCH 06/25] encode moodle login --- .../helper/moodle/MoodleInterface.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java index 8db219e..498d492 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java @@ -1,5 +1,9 @@ package de.htwg_konstanz.mobilelearning.helper.moodle; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -7,9 +11,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.ArrayList; -import java.util.List; - /** * Moodle service that returns moodle courses of a user. */ @@ -35,8 +36,9 @@ public Boolean login() { // get the token from // https://moodle.htwg-konstanz.de/moodle/login/token.php?username=USERNAME&password=PASSWORD&service=SERVICESHORTNAME CloseableHttpClient client = HttpClients.createDefault(); - HttpGet request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/login/token.php?username=" - + this.username + "&password=" + this.password + "&service=moodle_mobile_app"); + String unencodedUrl = "https://moodle.htwg-konstanz.de/moodle/login/token.php?username=" + this.username + "&password=" + this.password + "&service=moodle_mobile_app"; + String encodedUrl = URLEncoder.encode(unencodedUrl, "UTF-8"); + HttpGet request = new HttpGet(encodedUrl); MoodleTokenResponse tokenResponse = mapper.readValue(client.execute(request).getEntity().getContent(), MoodleTokenResponse.class); this.token = tokenResponse.token; From ffa49a4a66aa667eeaf1c34e8863be1096cd9dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sat, 8 Jun 2024 21:29:21 +0200 Subject: [PATCH 07/25] scrollable quiz --- frontend/lib/pages/quiz/attend_quiz_page.dart | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/frontend/lib/pages/quiz/attend_quiz_page.dart b/frontend/lib/pages/quiz/attend_quiz_page.dart index 4d2f120..4bd21c8 100644 --- a/frontend/lib/pages/quiz/attend_quiz_page.dart +++ b/frontend/lib/pages/quiz/attend_quiz_page.dart @@ -567,7 +567,8 @@ class _AttendQuizPageState extends AuthState { return Scaffold( appBar: appBarWithProgress, - body: Column( + body: SingleChildScrollView( + child: Column( children: [ Padding( padding: @@ -672,34 +673,48 @@ class _AttendQuizPageState extends AuthState { style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w700), ), + const SizedBox(height: 10), + (!_form!.currentQuestionFinished && !_voted) + ? SizedBox( + height: 55, + width: buttonWidth, + child: ElevatedButton( + style: ButtonStyle( + elevation: MaterialStateProperty.all(6.0), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14.0), + ), + ), + backgroundColor: MaterialStateProperty.all( + Theme.of(context).colorScheme.surface), + foregroundColor: MaterialStateProperty.all( + Theme.of(context).colorScheme.primary), + ), + child: + const Text('Senden', style: TextStyle(fontSize: 20)), + onPressed: () { + if (_value == null) { + return; + } + var message = { + "action": "ADD_RESULT", + "resultElementId": element.id, + "resultValues": [_value], + "role": "STUDENT" + }; + _socketChannel?.sink.add(jsonEncode(message)); + setState(() { + _voted = true; + }); + }, + ), + ) + : Container(), + + const SizedBox(height: 20), ], - ), - floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: (!_form!.currentQuestionFinished && !_voted) - ? SizedBox( - width: buttonWidth, - child: FloatingActionButton( - backgroundColor: Color(0xFFEDF5F3), - foregroundColor: Theme.of(context).colorScheme.primary, - child: const Text('Senden', style: TextStyle(fontSize: 20)), - onPressed: () { - if (_value == null) { - return; - } - var message = { - "action": "ADD_RESULT", - "resultElementId": element.id, - "resultValues": [_value], - "role": "STUDENT" - }; - _socketChannel?.sink.add(jsonEncode(message)); - setState(() { - _voted = true; - }); - }, - ), - ) - : null, + )), ); } else { _showErrorDialog(_fetchResult); From 0f09daf1da6e74aff1d6ca1d86a5c41628097497 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sat, 8 Jun 2024 21:59:34 +0200 Subject: [PATCH 08/25] stress test --- .../quiz/socket/LiveQuizSocketTest.java | 187 +++++++++++++++++- 1 file changed, 182 insertions(+), 5 deletions(-) diff --git a/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java b/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java index 63486aa..660eca0 100644 --- a/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java +++ b/backend/src/test/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketTest.java @@ -1,26 +1,27 @@ package de.htwg_konstanz.mobilelearning.services.quiz.socket; -import static io.restassured.RestAssured.given; - import java.io.IOException; import java.net.URI; -import java.util.List; +import java.util.ArrayList; import java.util.Date; +import java.util.List; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; import de.htwg_konstanz.mobilelearning.Helper; -import de.htwg_konstanz.mobilelearning.SocketClient; import de.htwg_konstanz.mobilelearning.MockMongoTestProfile; import de.htwg_konstanz.mobilelearning.MockUser; +import de.htwg_konstanz.mobilelearning.SocketClient; import de.htwg_konstanz.mobilelearning.models.Course; import de.htwg_konstanz.mobilelearning.models.Result; import de.htwg_konstanz.mobilelearning.models.quiz.QuizForm; import de.htwg_konstanz.mobilelearning.services.CourseService; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.TestProfile; +import static io.restassured.RestAssured.given; import io.restassured.http.ContentType; import io.restassured.response.Response; import jakarta.inject.Inject; @@ -1527,4 +1528,180 @@ public void testResultDownload() { } } -} + + @Test + public void stressTest() throws InterruptedException, DeploymentException, IOException { + + Integer AMOUNT_OF_STUDENTS = 50; + + // create & get course + List courses = Helper.createCourse(); + Course course = courses.get(0); + + // get course and quiz form id + String courseId = course.getId().toString(); + String formId = course.getQuizForms().get(0).getId().toString(); + + // create 1 prof and 500 students + MockUser prof = Helper.createMockUser("Prof"); + List students = new ArrayList<>(); + given().header("Authorization", "Bearer " + prof.getJwt()).when().get("/course").then().statusCode(200); + + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + MockUser student = Helper.createMockUser("Student" + i); + students.add(student); + + // call the get courses endpoint for each user to update the course-user relation + Thread.sleep(100); + given().header("Authorization", "Bearer " + student.getJwt()).when().get("/course").then().statusCode(200); + } + + // create a websocket client for the prof and the students + SocketClient profClient = new SocketClient(); + List studentClients = new ArrayList<>(); + for (MockUser student : students) { + SocketClient studentClient = new SocketClient(); + studentClients.add(studentClient); + Thread.sleep(100); + } + + // connect the prof to the quiz form + Session profSession = ContainerProvider.getWebSocketContainer().connectToServer( + profClient, + URI.create("ws://localhost:8081/course/" + courseId + "/quiz/form/" + formId + "/subscribe/" + prof.getId() + "/" + prof.getJwt()) + ); + Thread.sleep(100); + Assertions.assertTrue(profSession.isOpen()); + + // set the form status to "WAITING" and check if it was set + profClient.sendMessage(""" + { + "action": "CHANGE_FORM_STATUS", + "formStatus": "WAITING" + } + """); + Thread.sleep(100); + Assertions.assertEquals("WAITING", courseService.getCourse(courseId).getQuizForms().get(0).getStatus().toString()); + + Thread.sleep(1000); + + // make the participate requests for the students and connect them to the quiz form + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + given().header("Authorization", "Bearer " + students.get(i).getJwt()).pathParam("courseId", courseId).pathParam("formId", formId).body("alias-student-" + i).when().post("/course/{courseId}/quiz/form/{formId}/participate").then().statusCode(200); + Thread.sleep(100); + } + + Thread.sleep(5000); + + Assertions.assertEquals(AMOUNT_OF_STUDENTS, courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().size()); + + // connect the students to the quiz form + List studentSessions = new ArrayList<>(); + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + Session studentSession = ContainerProvider.getWebSocketContainer().connectToServer( + studentClients.get(i), + URI.create("ws://localhost:8081/course/" + courseId + "/quiz/form/" + formId + "/subscribe/" + students.get(i).getId() + "/" + students.get(i).getJwt()) + ); + studentSessions.add(studentSession); + Thread.sleep(100); + Assertions.assertTrue(studentSession.isOpen()); + } + + // change the form status to "STARTED" and check if it was set + profClient.sendMessage(""" + { + "action": "CHANGE_FORM_STATUS", + "formStatus": "STARTED" + } + """); + Thread.sleep(5000); + Assertions.assertEquals("STARTED", courseService.getCourse(courseId).getQuizForms().get(0).getStatus().toString()); + + // make the students submit their answers + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + studentClients.get(i).sendMessage(""" + { + "action": "ADD_RESULT", + "resultElementId": %s, + "resultValues": ["2"] + } + """.formatted(course.getQuizForms().get(0).questions.get(0).getId().toString())); + Thread.sleep(100); + } + + Thread.sleep(15_000); + + // check that the results were added + Assertions.assertEquals(AMOUNT_OF_STUDENTS, courseService.getCourse(courseId).getQuizForms().get(0).getQuestions().get(0).getResults().size()); + + // check that the score was updated + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + Assertions.assertTrue(courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().get(i).getScore() > 9); + } + + // let the prof stop the question + profClient.sendMessage(""" + { + "action": "NEXT" + } + """); + Thread.sleep(5000); + + // check that the currentQuestionIndex is 0 and the currentQuestionFinished is true + Assertions.assertEquals(0, courseService.getCourse(courseId).getQuizForms().get(0).getCurrentQuestionIndex()); + Assertions.assertTrue(courseService.getCourse(courseId).getQuizForms().get(0).getCurrentQuestionFinished()); + + // check that all students got the "CLOSED_QUESTION" message + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + Assertions.assertEquals("CLOSED_QUESTION", LiveQuizSocketMessage.getByJsonWithForm(studentClients.get(i).getMessageQueue().get(studentClients.get(i).getMessageQueue().size() - 1)).action); + Assertions.assertTrue(LiveQuizSocketMessage.getByJsonWithForm(studentClients.get(i).getMessageQueue().get(studentClients.get(i).getMessageQueue().size() - 1)).userHasAnsweredCorrectly); + } + + // let the prof start the next question + profClient.sendMessage(""" + { + "action": "NEXT" + } + """); + Thread.sleep(1000); + + // check that the students got the opened and closed question message and that it contains the correct result + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + // Assertions.assertEquals("CLOSED_QUESTION", LiveQuizSocketMessage.getByJsonWithForm(studentClients.get(i).getMessageQueue().get(studentClients.get(i).getMessageQueue().size() - 2)).action); + // Assertions.assertFalse(LiveQuizSocketMessage.getByJsonWithForm(studentClients.get(i).getMessageQueue().get(studentClients.get(i).getMessageQueue().size() - 2)).userHasAnsweredCorrectly); + Assertions.assertEquals("OPENED_NEXT_QUESTION", LiveQuizSocketMessage.getByJsonWithForm(studentClients.get(i).getMessageQueue().get(studentClients.get(i).getMessageQueue().size() - 1)).action); + } + + // add a wrong result to the quiz form + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + studentClients.get(i).sendMessage(""" + { + "action": "ADD_RESULT", + "resultElementId": %s, + "resultValues": ["1"] + } + """.formatted(course.getQuizForms().get(0).questions.get(1).getId().toString())); + Thread.sleep(100); + } + + Thread.sleep(5000); + + // check that the results were added + Assertions.assertEquals(AMOUNT_OF_STUDENTS, courseService.getCourse(courseId).getQuizForms().get(0).questions.get(1).results.size()); + Assertions.assertEquals("1", courseService.getCourse(courseId).getQuizForms().get(0).questions.get(1).results.get(0).values.get(0)); + + // check that the score was updated + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + Assertions.assertTrue(courseService.getCourse(courseId).getQuizForms().get(0).getParticipants().get(i).getScore() < 16); + } + + // close the websocket connections + profSession.close(); + for (int i = 0; i < AMOUNT_OF_STUDENTS; i++) { + studentSessions.get(i).close(); + } + + } + + +} \ No newline at end of file From 96e931971a21fbec7c87d5838a2b96a3c91b4ba9 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sat, 8 Jun 2024 22:19:56 +0200 Subject: [PATCH 09/25] add logs --- .../models/QuestionWrapper.java | 2 + .../services/quiz/socket/LiveQuizSocket.java | 76 +++++++++++-------- .../quiz/socket/LiveQuizSocketMessage.java | 9 ++- 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/QuestionWrapper.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/QuestionWrapper.java index e320fb8..b37ab56 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/QuestionWrapper.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/QuestionWrapper.java @@ -48,9 +48,11 @@ public Boolean addResult(Result result) { // check if the user already submitted a result for (Result r : this.results) { if (r.hashedUserId != null && r.hashedUserId.equals(result.hashedUserId)) { + System.out.println("User already submitted a result for this question."); return false; } if (r.userId != null && r.userId.equals(result.userId)) { + System.out.println("User already submitted a result for this question."); return false; } } diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java index ea9c5c3..2489c1b 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java @@ -57,6 +57,10 @@ public class LiveQuizSocket { @Inject StatsService statsService; + private void log(String message) { + System.out.println("LiveQuizSocket: " + message); + } + /** * Method called when a new connection is opened. * User has to either (student & participant of the session) or owner of the @@ -81,6 +85,7 @@ public void onOpen( // userId from Jwt has to match userId from path if (!jwtService.getJwtClaims(jwt).getSubject().equals(userId)) { connections.remove(session.getId()); + log(String.format("User %s not authorized (jwt does not match userId)", userId)); session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "User not authorized")); return; } @@ -88,26 +93,26 @@ public void onOpen( // check if course, form and user exist Course course = courseRepository.findById(new ObjectId(courseId)); if (course == null) { - System.out.println("Course not found"); + log(String.format("Course %s not found", courseId)); session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "Course not found")); return; } QuizForm form = course.getQuizFormById(new ObjectId(formId)); if (form == null) { - System.out.println("Form not found"); + log(String.format("Form %s not found", formId)); session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "Form not found")); return; } User user = userRepository.findById(new ObjectId(userId)); if (user == null) { - System.out.println("User not found"); + log(String.format("User %s not found", userId)); session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "User not found")); return; } // check if user is student of the course if (!course.isStudent(userId) && !course.isOwner(userId)) { - System.out.println("User is not a student of the course"); + log(String.format("User %s is not a student of the course %s", user.getUsername(), course.getName())); session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "User is not a student of the course")); return; } @@ -116,7 +121,7 @@ public void onOpen( Boolean isParticipant = form.isParticipant(userId); Boolean isOwner = course.isOwner(userId); if (!isParticipant && !isOwner) { - System.out.println(String.format("User %s is not a participant or owner of the form", user.getUsername())); + log(String.format("User %s is not a participant or owner of the form", user.getUsername())); session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, String.format("User %s is not a participant or owner of the form", user.getUsername()))); return; } @@ -126,6 +131,7 @@ public void onOpen( // add the connection to the list SocketConnection socketMember = new SocketConnection(session, courseId, formId, userId, type); + log(String.format("User %s connected as %s", user.getUsername(), type)); connections.put(session.getId(), socketMember); // send a message to the owner to notify that a new participant has joined @@ -275,6 +281,7 @@ private void broadcast(LiveQuizSocketMessage message, String courseId, String fo // send the message String messageString = messageToSend.toJson(); + log("SEND: " + messageString); connection.session.getAsyncRemote().sendObject(messageString, result -> { if (result.getException() != null) { System.out.println("Unable to send message: " + result.getException()); @@ -287,20 +294,31 @@ private Boolean evaluateMessage(LiveQuizSocketMessage quizSocketMessage, String // evaluate action if (quizSocketMessage.action == null || quizSocketMessage.action.equals("")) { - System.out.println("Action is null"); + log("Action is invalid"); return false; } if (quizSocketMessage.action.equals("FUN")) { return this.fun(quizSocketMessage, formId); } + + log("RECEIVED: " + quizSocketMessage.toJson()); // if the user is not an owner or participant, return User user = userRepository.findById(new ObjectId(userId)); - if (user == null) { return false; } + if (user == null) { + log(String.format("User %s not found", userId)); + return false; + } Course course = courseRepository.findById(new ObjectId(courseId)); - if (course == null) { return false; } - if (!course.isOwner(userId) && !course.isStudent(userId)) { return false; } + if (course == null) { + log(String.format("Course %s not found", courseId)); + return false; + } + if (!course.isOwner(userId) && !course.isStudent(userId)) { + log(String.format("User %s is not a student or owner of the course", user.getUsername())); + return false; + } if (quizSocketMessage.action.equals("CHANGE_FORM_STATUS")) { return this.changeFormStatus(quizSocketMessage, course, formId, user); @@ -319,37 +337,36 @@ private Boolean evaluateMessage(LiveQuizSocketMessage quizSocketMessage, String private Boolean changeFormStatus(LiveQuizSocketMessage quizSocketMessage, Course course, String formId, User user) { - System.out.println("Change form status"); - // user must be owner of the course if (!course.isOwner(user.getId())) { - System.out.println("User is not owner of the course"); + log(String.format("User %s is not owner of the course", user.getUsername())); return false; } // evaluate formStatus if (quizSocketMessage.formStatus == null || quizSocketMessage.formStatus.equals("") || FormStatus.valueOf(quizSocketMessage.formStatus) == null) { - System.out.println("Form status is invalid"); + log(String.format("Form status %s is invalid", quizSocketMessage.formStatus)); return false; } // get the enum value of the formStatus FormStatus formStatusEnum = FormStatus.valueOf(quizSocketMessage.formStatus); - System.out.println("Form status enum: " + formStatusEnum); // get the form QuizForm form = course.getQuizFormById(new ObjectId(formId)); if (form == null) { - System.out.println("Form not found"); + log(String.format("Form %s not found", formId)); return false; } // change the form status form.setStatus(formStatusEnum); + log(String.format("Form status of form %s changed to %s", formId, formStatusEnum.toString())); // if it is set to NOT_STARTED, remove all results if (formStatusEnum == FormStatus.NOT_STARTED) { + log("Clear results and participants of quiz form"); form.clearResults(); form.clearParticipants(); form.currentQuestionIndex = 0; @@ -361,6 +378,7 @@ private Boolean changeFormStatus(LiveQuizSocketMessage quizSocketMessage, Course // if it is set to STARTED set the timestamp if (formStatusEnum == FormStatus.STARTED) { + log("Set start timestamp of quiz form"); form.setStartTimestamp(); } @@ -370,8 +388,7 @@ private Boolean changeFormStatus(LiveQuizSocketMessage quizSocketMessage, Course // update the userstats of the participants and the global stats if (formStatusEnum == FormStatus.FINISHED) { - System.out.println("Update user stats for quiz form"); - System.out.println(form.getParticipants().size()); + log("Update user stats and increment completed quiz forms"); this.userService.updateUserStatsByQuizForm(form); this.statsService.incrementCompletedQuizForms(); } @@ -385,25 +402,23 @@ private Boolean changeFormStatus(LiveQuizSocketMessage quizSocketMessage, Course private Boolean addResult(LiveQuizSocketMessage quizSocketMessage, Course course, String formId, User user) { - System.out.println("Add result"); - // evaluate resultElementId if (quizSocketMessage.resultElementId == null || quizSocketMessage.resultElementId.equals("")) { - System.out.println("Result questionwrapper ID is invalid"); + log(String.format("Result element ID %s is invalid", quizSocketMessage.resultElementId)); return false; } // evaluate resultValue if (quizSocketMessage.resultValues == null || quizSocketMessage.resultValues.size() < 1 || quizSocketMessage.resultValues.get(0).equals("")) { - System.out.println("Result value is invalid"); + log("Result values are invalid"); return false; } // get the form QuizForm form = course.getQuizFormById(new ObjectId(formId)); if (form == null) { - System.out.println("Form not found"); + log(String.format("Form %s not found", formId)); return false; } @@ -411,7 +426,7 @@ private Boolean addResult(LiveQuizSocketMessage quizSocketMessage, Course course System.out.println(quizSocketMessage.resultElementId); QuestionWrapper questionwrapper = form.getQuestionById(new ObjectId(quizSocketMessage.resultElementId)); if (questionwrapper == null) { - System.out.println("Element not found"); + log(String.format("Questionwrapper %s not found", quizSocketMessage.resultElementId)); return false; } @@ -420,14 +435,14 @@ private Boolean addResult(LiveQuizSocketMessage quizSocketMessage, Course course Result result = new Result(hashedUserId, quizSocketMessage.resultValues); Boolean wasResultAdded = questionwrapper.addResult(result); if (!wasResultAdded) { - System.out.println("Result was not added (user probably already submitted a result)"); + log(String.format("Result for user %s was not added", user.getUsername())); return false; } // check if the score of the user has to be updated QuizQuestion question = course.getQuizQuestionById(questionwrapper.getQuestionId()); if (question == null) { - System.out.println("Question not found"); + log(String.format("Question %s not found", questionwrapper.getQuestionId())); return false; } if (question.getHasCorrectAnswers()) { @@ -457,18 +472,16 @@ private Boolean addResult(LiveQuizSocketMessage quizSocketMessage, Course course private Boolean next(LiveQuizSocketMessage quizSocketMessage, Course course, String formId, User user) { - System.out.println("Next"); - // user must be owner of the course if (!course.isOwner(user.getId())) { - System.out.println("User is not owner of the course"); + log(String.format("User %s is not owner of the course", user.getUsername())); return false; } // get the form QuizForm form = course.getQuizFormById(new ObjectId(formId)); if (form == null) { - System.out.println("Form not found"); + log(String.format("Form %s not found", formId)); return false; } @@ -476,6 +489,9 @@ private Boolean next(LiveQuizSocketMessage quizSocketMessage, Course course, Str List events = form.next(); courseRepository.update(course); + log(String.format("NEXT produced events: %s", events)); + log(String.format("Current question index: %d; Current question finished: %b", form.currentQuestionIndex, form.currentQuestionFinished)); + // for all events, send a message events.forEach(event -> { LiveQuizSocketMessage outgoingMessage = new LiveQuizSocketMessage(event, form.status.toString(), null, null, form); @@ -486,8 +502,6 @@ private Boolean next(LiveQuizSocketMessage quizSocketMessage, Course course, Str } private Boolean fun(LiveQuizSocketMessage quizSocketMessage, String formId) { - - System.out.println("Throw paper plane"); quizSocketMessage = new LiveQuizSocketMessage(quizSocketMessage.action, quizSocketMessage.fun); diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketMessage.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketMessage.java index 8ed94e0..8db0acc 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketMessage.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocketMessage.java @@ -6,6 +6,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; + import de.htwg_konstanz.mobilelearning.helper.ObjectIdTypeAdapter; import de.htwg_konstanz.mobilelearning.models.quiz.QuizForm; @@ -45,10 +46,10 @@ public LiveQuizSocketMessage(String message) { this.fun = quizSocketMessage.fun; this.form = null; - System.out.println("Action: " + this.action); - System.out.println("Form status: " + this.formStatus); - System.out.println("Result element ID: " + this.resultElementId); - System.out.println("Result value: " + this.resultValues); + // System.out.println("Action: " + this.action); + // System.out.println("Form status: " + this.formStatus); + // System.out.println("Result element ID: " + this.resultElementId); + // System.out.println("Result value: " + this.resultValues); } public LiveQuizSocketMessage(String action, Fun fun) { From dd70c41c1f5ac3db4550f178b9c2765f921aed67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sat, 8 Jun 2024 22:22:23 +0200 Subject: [PATCH 10/25] participants voted feedback & quiz --- .../pages/feedback/feedback_result_page.dart | 34 ++++++++++++++++--- .../lib/pages/quiz/quiz_control_page.dart | 6 ++-- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/frontend/lib/pages/feedback/feedback_result_page.dart b/frontend/lib/pages/feedback/feedback_result_page.dart index 5000eab..d9c1d96 100644 --- a/frontend/lib/pages/feedback/feedback_result_page.dart +++ b/frontend/lib/pages/feedback/feedback_result_page.dart @@ -315,6 +315,11 @@ class _FeedbackResultPageState extends AuthState { ); } + var values = 0; + if (_results.isNotEmpty) { + values = _results[0]["values"].length; + } + return Scaffold( appBar: appbar, body: Stack( @@ -440,11 +445,30 @@ class _FeedbackResultPageState extends AuthState { right: 0, child: Container( color: colors.surfaceVariant, - child: Text( - "${_form.connectCode.substring(0, 3)} ${_form.connectCode.substring(3, 6)}", - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), + child: Row(children: [ + Expanded( + child: Text( + "${_form.connectCode.substring(0, 3)} ${_form.connectCode.substring(3, 6)}", + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + )), + Expanded( + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Abgestimmt:"), + const Icon(Icons.person), + Text( + "${values}/$_participantCounter", + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.right, + ), + ], + ), + )), + ]), ), ), ], diff --git a/frontend/lib/pages/quiz/quiz_control_page.dart b/frontend/lib/pages/quiz/quiz_control_page.dart index 3140c6d..402d757 100644 --- a/frontend/lib/pages/quiz/quiz_control_page.dart +++ b/frontend/lib/pages/quiz/quiz_control_page.dart @@ -699,9 +699,6 @@ class _QuizControlPageState extends AuthState { color: colors.surfaceVariant, child: Row( children: [ - Expanded( - child: Container(), // Empty container to take up space - ), Expanded( child: Text( "${_form.connectCode.substring(0, 3)} ${_form.connectCode.substring(3, 6)}", @@ -713,8 +710,9 @@ class _QuizControlPageState extends AuthState { child: Padding( padding: const EdgeInsets.only(right: 8.0), child: Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, children: [ + Text("Abgestimmt:"), const Icon(Icons.person), Text( "${values.length}/$_participantCounter", From 24c041b3fc63db8f2ce508bac02b382d981b0039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sat, 8 Jun 2024 22:50:37 +0200 Subject: [PATCH 11/25] empty string instead of 0 if fulltext answer is empty --- frontend/lib/pages/feedback/attend_feedback_page.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/lib/pages/feedback/attend_feedback_page.dart b/frontend/lib/pages/feedback/attend_feedback_page.dart index 889ef28..40f7bae 100644 --- a/frontend/lib/pages/feedback/attend_feedback_page.dart +++ b/frontend/lib/pages/feedback/attend_feedback_page.dart @@ -124,6 +124,9 @@ class _AttendFeedbackPageState extends AuthState { case QuestionType.single_choice: _feedbackValues[element.id] = 0; break; + case QuestionType.fulltext: + _feedbackValues[element.id] = ""; + break; default: _feedbackValues[element.id] = 0; break; From 5b2ec9c7c38377e1eba129c833c4e39250f06f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:16:18 +0200 Subject: [PATCH 12/25] show answer options while question is running --- .../quiz/single_choice_quiz_result.dart | 20 ++-- .../lib/pages/quiz/quiz_control_page.dart | 98 +++++++++++-------- 2 files changed, 69 insertions(+), 49 deletions(-) diff --git a/frontend/lib/components/elements/quiz/single_choice_quiz_result.dart b/frontend/lib/components/elements/quiz/single_choice_quiz_result.dart index 9b5fb3b..45774fa 100644 --- a/frontend/lib/components/elements/quiz/single_choice_quiz_result.dart +++ b/frontend/lib/components/elements/quiz/single_choice_quiz_result.dart @@ -6,12 +6,14 @@ class SingleChoiceQuizResult extends StatefulWidget { final List results; final List options; final String correctAnswer; + final bool questionFinished; const SingleChoiceQuizResult({ super.key, required this.results, required this.options, required this.correctAnswer, + required this.questionFinished, }); @override @@ -88,9 +90,12 @@ class _SingleChoiceQuizResultState extends State { child: Text( optionDerivation.option, style: TextStyle( - color: correctAnswer ? Colors.green : colors.onBackground, - fontWeight: - correctAnswer ? FontWeight.bold : FontWeight.normal, + color: widget.questionFinished && correctAnswer + ? Colors.green + : colors.onBackground, + fontWeight: widget.questionFinished && correctAnswer + ? FontWeight.bold + : FontWeight.normal, fontSize: 20, ), ), @@ -103,8 +108,9 @@ class _SingleChoiceQuizResultState extends State { "${optionDerivation.count}", style: TextStyle( color: colors.onBackground, - fontWeight: - correctAnswer ? FontWeight.bold : FontWeight.normal, + fontWeight: widget.questionFinished && correctAnswer + ? FontWeight.bold + : FontWeight.normal, ), ), ), @@ -117,7 +123,9 @@ class _SingleChoiceQuizResultState extends State { value: optionDerivation.normalizedPercentage, backgroundColor: colors.secondary.withOpacity(0.1), valueColor: AlwaysStoppedAnimation( - correctAnswer ? Colors.green : colors.tertiary, + widget.questionFinished && correctAnswer + ? Colors.green + : colors.tertiary, ), ), ), diff --git a/frontend/lib/pages/quiz/quiz_control_page.dart b/frontend/lib/pages/quiz/quiz_control_page.dart index 402d757..619e7cf 100644 --- a/frontend/lib/pages/quiz/quiz_control_page.dart +++ b/frontend/lib/pages/quiz/quiz_control_page.dart @@ -604,52 +604,64 @@ class _QuizControlPageState extends AuthState { fontSize: 20, fontWeight: FontWeight.w500), textAlign: TextAlign.center), const SizedBox(height: 16), - if (_form.currentQuestionFinished == true) - if (_showLeaderboard) - Center( - child: Container( - constraints: - const BoxConstraints(maxWidth: 800), - child: Card( - child: Padding( - padding: const EdgeInsets.all(8), - child: QuizScoreboard( - scoreboard: _scoreboard), - ), - ), - )) - else - Card( + if (_showLeaderboard) + Center( + child: Container( + constraints: + const BoxConstraints(maxWidth: 800), + child: Card( child: Padding( - padding: const EdgeInsets.all(16), - child: element.type == - QuestionType.single_choice - ? SingleChoiceQuizResult( - results: values - .map((e) => int.parse(e)) - .toList() - .cast(), - options: element.options, - correctAnswer: - element.correctAnswers[0], - ) - : element.type == QuestionType.yes_no - ? SingleChoiceQuizResult( - results: values - .map((e) => - e == "yes" ? 0 : 1) - .toList() - .cast(), - options: const ["Ja", "Nein"], - correctAnswer: - element.correctAnswers[0] == - "yes" - ? "0" - : "1", - ) - : Text(element.type.toString()), + padding: const EdgeInsets.all(8), + child: QuizScoreboard( + scoreboard: _scoreboard), ), ), + )) + else + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: element.type == + QuestionType.single_choice + ? SingleChoiceQuizResult( + results: + (_form.currentQuestionFinished == + true) + ? values + .map( + (e) => int.parse(e)) + .toList() + .cast() + : [], + options: element.options, + questionFinished: _form.currentQuestionFinished, + correctAnswer: + element.correctAnswers[0], + ) + : element.type == QuestionType.yes_no + ? SingleChoiceQuizResult( + results: + (_form.currentQuestionFinished == + true) + ? values + .map((e) => + e == "yes" + ? 0 + : 1) + .toList() + .cast() + : [], + options: const ["Ja", "Nein"], + questionFinished: _form.currentQuestionFinished, + correctAnswer: + element.correctAnswers[0] == + "yes" + ? "0" + : "1", + ) + : Text(element.type.toString()), + ), + ), ], ), ), From f20a833cee6796e0c88945a032649c61ee638171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:59:15 +0200 Subject: [PATCH 13/25] hin&weg & kombinierbar neues icon --- .../assets/animations/rive/animations.riv | Bin 2259732 -> 2276017 bytes sonstiges/menu/hin&weg.svg | 50 ++++++++++++++ sonstiges/menu/kombinierbar.svg | 64 ++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 sonstiges/menu/hin&weg.svg create mode 100644 sonstiges/menu/kombinierbar.svg diff --git a/frontend/assets/animations/rive/animations.riv b/frontend/assets/animations/rive/animations.riv index aebaf227cbc89cc99852a0dc678fd7773364b7fa..39011487107d9c4a03dc5f915d1e20eb766abfc0 100644 GIT binary patch delta 35450 zcmaidd0QdFUDz7TPs#{g}sva8){&RcX-iHd#+pWqE`8#J6T=&^XHT95xfSSC> zce;9ak?%aUbdm33b=6^it{S-5m#2Du?eC)Ei+w)TeOI7!m;B(Xovdzy=Ucv#8%CvF zu)7=nSnpBuZuNCl&wm>HwveiSHDiNpS$YR%2QE^6M*zJQv01mF`l z`zEQ2kNSJAy~UTSmfnK*`8xysRrD5LfqLu~-x=yY7X9L|f4Dk+i|-1x=^MXKUH*+f zTh)FXxI(=i^9@pCD}6VsZ!015MaLlNo=ON3KjuF}-L*5|Q@g(LgVe3QT9vae&{>UN zg50G`P?@S-fgE-95?>GX(h}c8>h7hGV8T*gNIkLC_gY`6L`|AhaI|GrhEU}NsOfhe zr_K-ROm*G2{z2-ZJ%M~RbQwzTsPfHJH!Sn@QXeey6{+g)An>c7A@_%6zIAHXZ4k2> zkF=F}>h*nr3)S4)eZ9Jet&vv9iYQOIHR3)`nlF?etsI$|o zFcBQZm&~_xZYe9;(Y<>&wqqOW*RH=BZT|Kj-V2{#d$K z&3?{z4&aBM^R4Y6q+H&XHUAEeclzvE)34nJj0w;CdVBs}chmE}b8|CM(y}^xk9mp) z4H~32z2!Th>`8^))w^%|`g$Iz`{8Y0L3U`>DbyyXC>@R($CNhdk=)kA0_i^khb(Ya>~fl~!zJc+=EFAN#sa_GC6SJ|D@dt?}@s zH>b8HKa|S{L}^SfN>iVmw9>sS`cNb*7;H_fHYr$5Nmxyd>xq>~toADV6JOVuClj)g z>whD7nUzxXZ%IXi!51lpFzA$mwLJ-|sc{{#z9y}l6s-4>u!6yR$Z-d-PWN_AL3=+5 zEgF3)lGW7MnbLMs??PIr!?HH=Wd>gs@-i4aNrewiDY`qUXfU{x741lAhooTbNx~92 zYHQMoHB8OhCF(Hk{v#QTOewlIsi7Jqaxse1d3)NNlX?zuPn(+TF4~=F4BD6#c>!O+#m~EUOq;Rx!HH_{?B% zQ36s$>rv*ClrsNt*^Ngxyf*=MP`jI^D|lPWOAPR^AzT z(P()jAM(Y^7fwGjUeW)@FGkAyrp8f`{HDg)@zPx#$JCeg8v4md%L{zV8c6*7xL^sS zUf$#D6q}J344xUuhqsal06C}_Cy>#=i zoxm>JX`VAF)Xq579d^~Np5N>1+K0v?$YE^^!C-q5>gOV({ZV&y7|1XW5(TYj*fj94 z1oXKroJtu+g!j?tiLj#v*C0Tg7RGi7xsv47)_fV4_rwotL(%QNFAh4rBU=5#Er6C) z&EleUM{ib~@7G0WHeqQOW2IsJUTP5E=j)o!8d!X}AsLw!Jc?{+!?MC*WUpuTwonQ! zzF#h)sQ#ZDZS3RA%2Sc${dgm{<&OYse59Oqnbh3uh2VE;X}oW0Y;<%ynb7Pob;i!6 z8zj$)!4a@{*pbv2IUNMw$El_I3J}u9?>dRn=Xc#Svh2!kAB;3E#OuA^!`@R5KC8k| zod!ef;mKeyc)S^`k1;#ql2}g?(48p*5UxzL!!k}T#+>bmA`8XILa#G`tx_1VnQ|ZWeJs z2`!LaZrEy)Ea$c~CWBZW#f%sLj) zARA^~EE$eQM>m5Z+GE76(SDMEIat;_;y9q-7;rs1j!=+XfP(A@agY>X<_rZuLBM@6 zA|=7n_uOph6sV;`;%gCtJq7*K>lM&q7a7AM08J+lf(|k?Uyu0yU+G0?5>9uB zKzviV+3K0?J??=GwDNw-(o@)FtK#KDn%cxGLSH=2G5K5d-T_~s=UeryPP+b6p!0Qd zxlSr|@~BSU*2$MT>2OdA4A9A?I=Nma>vZzEPCnC#=SwNj3rRPKg+Y$(IU`c~w}x=M z?3(#G^xEI5sbBi?Al8i<`vE{2`*Hf%7tBZ?W=ZUKHQF(Q2B*lr?V!Qe=(_g&N_daf z$t<0$(#dm3&QI1;>HM`-p|Y2DUlc|Y89lB|gTOo4TUK&(z;GfVVJq)i)&5_gy;k+t z$t6g-0UJG2e8fm6;+e$ityOpa3)Nez9@p60baF^19S=d0WKN}x?|m35>-}9gNs>p> zU~n)G%gRZVHyp?aRcxQ}Yu54+buG$!9#MDcNE< zD)F-Q)2wJ#M16kP*TeI)dYgz(t1orZ;jlmhbaJUqu1De!c}e~8FzWY`dWCr}sa-nx zSto%bzC!z@G>AUj^~#MSsLn73+YVIFOX?~hq2w|o=f9K&4|5~UdAr+E7xn6MlBri2M&YnysiWAE0+9EHJXG^# znz)#+)QWF?1)i_e6G%pV#pbn&op|z2H*~v`dizR@m$?!lB3B|UPS~3X9#L(+^A(IZ zLfoSXjSK%}aQPP~9U&jdMcgX6U~9pQbgsJUJ6|8n44Zvow)Z>A>-C;u>sf{4c?K4G6OI&70|)r7WVP+L~PYW`Jx4fM*#H?aVak1A-T8p$v#Yn6+?_qtUnN`5tshn!E zO<|BGa&KxAWhJ+^<}WVe!7O`@5zDd;#=-bktm4t6W{lO=Oyg2lkdEXLUB^eM5zO%{ z>j9Pq2oJ}mxZi-$=xuIzEV;X3$ zgJCpUYd|a}&_pEe17l7(fbD>=MS_-#e4NI2nhRn|&SBmW+LM4-D-4Jk94U|E^yJa> z7*xHVv=9ZDD*nj$baY&UuwkKPz^2CCL>6Py+G6g4gi{urni?0gk&hwj+IdpjF-$nb zHL%TCd)kuDWwZ@gyuH3Sx3*^OzkPns+bZyHU(cAVl;?QUtQ@Zwzc%=_$1e-NPWa{E z*A>5R_!Z#i$FC=Tz47adUqAc?;CD8DgYg@J-!S|};upbh6n+=tHx|EN;dcpsrTA6g zcNuFT|6?10MtkMA;B(jV}4`sdhz zSg;?v44#aP`7>uNc++FGwkq!~X=7EcDmk3~PfuIx=n8lFKCrx?Z!Xtj{l!qv8O7)V zdb~(iS1vE;n$NzzoSplO20d6nhn#MwtJTQ%q^l>E7XoJ;TFJfWoNU*$Kz8}lp zJ}n_-j_5M2R}=(<@>Uvpw}w)#>Xr5XafYTGSs|1s0c#NZ;pgO^olF`0VUG*Rab%+W z<~JT2S#kfthjr;cqZs6B(#a8>bh<-c26a-VlRxOBMklZ9WX~O@)?JH1{qe9~)1c>- z8f2~%LIZSi$x1;E1{17EVKK)^SuNAZw>sH>p-rB_Y`t2iv;U&An;IKv!M2pHui#`! zSbeT}q^}ZXH8pl^0M?^i4Z&FI3N&JsD60%uK6ZILWLaU!neyx*vNI(*Xu?c!bplGUbJmhHjxF)$#9KrmR6fLwMQMr>&!|JJ2@+%2?5>SQVs z5n-MlLrW`e?-J7HMU8Xalr3?wdQ9WLt&@W~X?Ks%>Zg-m>tr4hkc1cs)as%{>GEp^ z*Ov|U&JMXtx0>WejlWYTKj@^}y+U%hPOi{NB@&RVt=Yw~>&bZO&2RLoFJsNP3lVm9 zAud*LYWxE_X>*^@Is?fCNzGR}KloX_wpeX}Uhnmw{U~YY7NfS;L${Amx4FgT9ggSK zS9Ew~7(?jmRW(S(m<^Z20bb86jEb*^Nx(Dky*7ULeQiy*23XUfaA`s5-|NecEKduS zzimAgs_1f4Zz0^wzO>tgJ>z9N-anu5z4re%qkEKa7(O>qo>_P2`5~viH$%zg%;=q9 zyVaxJUZHAP;C{vc-4iMLxmo>oZ9(8SH-p<>IB*Yiy@@GSTXQRm4NH`hTtyN&!@soj zoHPy(*z|FvTc$o;TTtj(rhZymkk@S)m$-hc2a$VZhsbT4Wom#bC>$#JeHn7R5qDgf zFh>T;u;2$+cbWe6W?e~#%PMsTihEY6XB4=s;v&r*2_P>><+4ic1zHIC(P%aEA5G;V z8C7iPSK~=_bhzBZg{6<iq)g5)@RE!l;+of~ zHL6u#p*YS5WY&O7EjhoPKwFMZtx>HC)qo4~Yis_>Az)Q%jU=O9v;PIXJ*;X`-1D&7 zL@p0g$;*fw45wJe!|DjoV#pW0G5}0z9c0wj+)Vc4LchRe1LF!h47oJb zKID5gs2^)l7oK^ri!qtVVI=heSNFW$7pZ11`|fat#{g? zS{85;7fXg4Fc^HDbDWL_l+hN8HU?~JoELF9QLG0ECJdu!^!Z4BZ!_xyY0LVI;|rEK zjhJ6XAjcG`q6$4wkSDtOZ83I!!c9+KOE;8LmsAo>lp6Cf)=#%RkWUI%$2@39<{i$-A}#S$$q+SLudORS*_A>+-j1go{JWCQ7Z%X`KobdVLSD8z#gOy z-&B}g*T2yAoyI@AtE&gweLSDntsZQz>7`FQ?NLK7v-N4G%PzA6o;^J6bedXynY|i+ z+mr2JXG~$%?;F+5sxHR~Bz<1#%E@;3J{_#|jMfw8&6+c3=6r8@HvL8?KG2rdD`?9M zm{=>XS3Nx0?&0yOHUE<2S)Ke9iOQK`7j*lDk{zUErY@POOJ*u5nW?1Y<|%d|g6q$x z*m=Lo$sW4BDAb9MOsn$Q;aR&^^`rd{%^4&93LNBd9)kQ#ltT^P&3ly&N>SsSZ{HylpefAZwWBWW_wukd(#+>Jli zM^suG%=nC=PMtcPw5mPcf``+#tb6Yr?|S6^yTrWt_kqNJTJcRdV%{7)xaRfNe6zLK zy!m$fgXT?%bvwvcrxmPHM=!T~O!4;kTUv(okjL8#-Nb@KXOv`Jw0Rp3-Sp0xyY%Ve zTs|PhnMH#?^qquFVfkAo%Dt^TZ^i&@Cr0o`2j`F60o=L1?3{7W;;+d4 zw@w{t+2>`0y-&)To&uC1z!gzl=-WOR# zINdj3;+p%h(~=)NP3^tH9@37sxFO9t`=$;maHV~kr>9EXX!jkMDMY#r&SEi^#{HeQD= z^$R6)q)X-ME|sghRIct)xw=bTF$Z0$z3x&y{+BLQ@V|5^UrLwqrF1EuIsnSC9{+on z>XqE3u5!Cn(J5UDZ(4LIylK&;@TNtV>Q$Xqq`TCm-d?6l^|R74ye0GJE?D4gpE)+G z@0P5`zu4MQE5 zpLrq#MO*;+tsz+(*Vglh+-NoDcXpQo^D>;5m4IT#WbWI)B$0K)^xj-=8mk`uo!vEm zY~JdbSO(a!pdfK++c!_1J0asNc)y;=eotqAF!_y0{vReRj$FETazS{)re9ZZk87;* z%(sWe$ac=y`m8(qym*RECM26l)HRdRQ*?wkEp&u8Ep&u8Ep#-YI;~V~op1YN-U&uY zlg05q_i^8ntaVTQnU44J6vunD<9NAZNatIG-*Eg!<2MFBt~Oqt?1OV0XI#+ijPtw$ z0Qj|M&hrk=Ooqm&l?&|KI$vo#u4iIZRTcg11uC)7E|@SH?>mcAHSX|IynwHShn%B5 zq_5=cW*|S<9{J*+FM!X_o-=FuH4FXIuDY6baNTtaUBUwl;gW7BJlFW#xsK00MVd?1 z-i3Cz&Pl}cgA>3hTg7j%;Z1L_yQ%)y+xf%o^IAuz&0a9me>Pa1uVod#KF{zlQs)Po zdGzjmgf$+Zs;{>PW1*L1d;H$+sk;B(F7}kD>Kp8wESGhEp!QcI|6u2N&QaI?9x=x- zwfy(?h@Q;^&n@|u1PyzP7e;pj)Ghn%?&XizTzB+b;eVU5@!ET$>eunt~_0Avc!Ku^-uf4&ZsFQw z-Ckx})`jh(>-_4Ei_y3U zkOz*%8vhS>x&iXbi|wAdX>g$#JnbB1ILfWAR^AMCc(L8plc9co*%v_Kuaji#&4|4- z)NGyHrIY7%GIg7v9MYIsuLv|yCzstKB z<*MvgB{@H42l8_ts9(VT6zqb$9p>V4F}Mv&;EUaJI&K5Dm4e%6WqR(ZL-5d{0F zDX&X%i%!<-}&D`2KB*gw!JLa#!KHjc~-b=>dN;yxb(qnQs#?~ zy6a9eSj9f-fj5NDW}WQQNxP+Xz-F0Iq}95Ci-{pFCi0YpuFD8D7D%2EYPL@9(#i8W znffn@O zu2{Lj#|6qss*)uqse$i<+$8mJT$2Cj#Fr2#qLXpA3+9~LjoJN%+gUQ{nkhV@>e<^- ziKu#;h*5P=C+(IC)K4dK8bC6t*675)L!gbzMQm*8a$P5zV$T|ot9h1fyFhhV0jdjBf1Qk%WbKFebZNy3vBaivOR0j#x$dz@Xf0NIwm|WV)#MMs zbg{ZcClBjn;2og1Sp8E&3-7ScjIk$QKqBoa&~18=;&!e|loVt7--;Uw0BdW`;kwh~ zj1vJiHFl()-{c~NAfLw-VlU^Jk{jaEK`R4-6v306lOi`74K~2|Y6SFgIV7h6OBg?M z-2vIbpv5JvfdZ=GEA75m%Z#qHdrr^sa;uVCr`#r;h~G^7=Hs^rzuUOpax_jPY~kH^^n zRd+mWm)#J(%7?t#bb6=`(?pRhmb+(yK)t(>|(ui4|$>lUxF?>bE_SZ`md2ES*2 zrmoHO7pdR=$JfF3z~v@=%LOQ`=U002R5x#vea&f}w(719{`qRddv>u}z1}`o?f;|Q zhxB@=P7m9^<}ycCfhUEKOw!Up&3y6|d*ALBdmP_Y#UH||hJ06rPpQ0C_VH+LsMF?^ zZ9|!Djy8p}KKt9m2m(M4Tv?|QwEbfxXnV6=i?(fDf(H0OwwS_YcmL_H=0x>FFO;%3 zaqmqqmNb-(pEEX8*05$mM1P<_+?YZ6n)XuNp!XQKoQCG*PT;%xyYtJ#mp12#fxFpSK0v zV)8}97)R1k4U(a^G~|pW8APLx@O_&trHzSe>&ub|)zehJY$(rusC~HNcOxIrj4i8y zHoL!}^tbI^s4v^peKn65P|){Dr@BGJjz+&}$Or#wcl*#N3~Js2w6MGNTq>uVxNK}N zq$n1y&32}|*ZMj{2JwVpkiCUsM9S~`^T|-fYfsi{@eF;7E6OqX;G!laW4&3W4hDNV z3iFUqQ*mkA3xn~p1K$)Ty+_X}fxfT-jguSteKacd%qwwrTiy3}i+)R-z1Inmm}x;# zyu|`I`z3_5!sPvSx&}EKQ;gaHVxyQ=JcT)qixKM-=Cw6V`h7EV(82C*ZOu>2NMTL} z@}9LWUpe~O%@uB~n;Nrd@$1ckysWlrGnDt1Xpi5|7_C|s-m@7>{R{67l}R(OI??Dq zi`o9BweSrf#fT@geApu3D66|!UzpBv`po|}U`OIQ?$#fr&*yv55KL2c58U@gJFtD! z%xcEBtSY+V|2C9n)@8=aVE-WG1tFuhqx9f?A)B-mAT0u?`#2ER00FlXV<7O?Q(OZD zgXn^m<=1&ljhl%H$f>|!P=vMfo$g!M+hGL;^Arw@%dvLuZ>*vNkuNMXic@qd`-AL| z;Jw#77$rX;$*E*I7y|80Ve0h`b7=c%F~dOT1;HqGGz>a1ogw`@EG^1y8)3i#@_uSD z7`Vg$Ikk!aV+lz*Mrdlq_oBZxCEB4Sy?>whZP;VvTx(3~$O3=Ygme!uBDn9R2e|A2 zIn8nrET9)lKF>N{1UjPT=V^q(KgCL;s?@m{EVVQ(WY(PF9g7EA^~2Ht!ZU z^%o7fqPQCJdM|-M*kcg!2*I;+PXWRjC`M3CG(^%=gm! zn-wheFGu|sX*wzTEoc2D11j}4vjgO`@#P>X{=xBzrY-qiI_&esNp0-)UJh2>$x7!CVw0YNc_wNu;F~)l_%0#k-wo^3DAqfU%#)#Qy=So9z$Sn`nJ7dIb)OcBguqwa# z;cx35FG~Cu_&ydlCzj2o6&d`%46ySGyR8B-l4RbNV&-wtjh>N*8JZeDJsAOcuHkb1zWmB3chy(?_8)Jv zfrxK$zxee;>D-yQBg?jSOMZ_`I^bsS8oQa|CRH-UZwNK^P^*Fc#<)hqh1-9xC(84- zgu>0-AytEx_N?hI*C%rq#W-f;)F7iW~63@t|api$4&S2Sm!fu0mnx`Ckob=-!1GNoPTm1G5v&t;UmM$d5W z<_zZ=jN-@VZUF-U{fI>YrszvDEM{EI0ohTQSC^2C&=y#&#(NTYF~EkPMfgGzY;GQn z2u&aV4Wm^At44E@aSfs}WSlC(JZ4;&EP~-78Lfqf)-dBQhgS5!Nj9_Na2&C)uaAtB z9@H#YQ`_LpD~=I_HzyE85{?INwR@OL(dSL%GPTEirGl6 zAOm!1yudPITQ+sBLE2Iaa6oe|D-94NV%os#gl|cHQ-`S~pdsLT1d1)eu$w!T$N*h2 z-f&3_B$9waA_c6?U(b=&L9UGvc4;I?qYWrGj^jy62gG!r-&Hkt3(3evLj+^)6bOFX zt4o}&GaLc{9RjX@7Xp4Tih;5Mv@C7CKVqeZea4hJ`Ij4oo z+82KmE??T=vXK=JTri(qNT>{?U_wP)(QK;7$w2==OT;v6m9W1sDv@k}ET?sj!zPAc z)3{cKXXm-Y!e!)Ceso!RsDj*`3V6LcS%ImBq5;D$1IY!b8N}GCCWw$6h|EJQrPnQc za%9=@YYS!S%LxzGKw4?iKxx)xiwqoSj+CF3JG8#yPk;J^VhhnB+5{Z!?{3bBkzGB{ z%{E(Cvm7VgFVQ3_kPNgJR;O4(!XKI1O2$#1-2RytJV4oIF6?A9HCj>;*8n90YQ|R> zm9z@S=^Aw*hgEds2S}xqWBMI-LMWlI4?Wp!U=u<)8M=YB0?-j#fK83D23SK(u&1)i z0d_m$zf2QG5B!l>0BdVbL;aG#Ai;W*EA1_yOX8?YVlR;d46{rM7z-Z1l77j-7O=DT zsig5Zc>E6~S+$?MPG56EyQ}XpazqbBVE;ETFa*dipHPQN1Ipj*){4eh8XzJ)9$|yV1VkuN-A z+k!y9au!)Vu30@H)o=~a0mW5%y#VMo^UW^^N z*gmp)S+lBRtAiU_S*n_GaUtbC>##hG1QmT@Xn0D}`!C`*HyEB5ztl3>y3ZtT;3 zvXUCvqviUHDpnO^U@*9berK5hajsXuh?`4CgC+IO-nwLGz|Di&{3l5I3r+eT zX?d9c?Vu=K=}iF#gIn4AWi}76X4E zASnGpliC6h{i3t?6<03UU-a=zIKan8Q?Mgiu%i^@3YPvYD+$oDZl+wT4A?Xd3n=_z zTjv5KGJIBN@2f6t=liyCZ;RUHoaOtxNYrJNYRD;F&XErtdo5TQPi-5*` zjGQ$n*wk3P41DU=w|u#=N7E}ko}BOBTUnC3rEFOVa^vYm3l}bw1IfH^F_F&u7I_LQ z4Zp?st>HfB2|j-2V;SF9^P%{7h>yqlc$SZs`H1tejgR;F*u%#cd>lEQ&l7z7#K$sj zvaaIeUOpb+<54~=75I-YZ%lsB!}B^g(!%qo+*kzI$$;EqbWYsLj;g^;!301&70>sd zex6)DiBl^X>pUISduHf;QJzsTr&HyKi=0SJx|Z_MbT#Z#yD+muTPyqsb~>j{`?RPcvh$Mt$MF6`DiqnF6n4=y4v=sJ)o#<$_cnEeFDxLcBk^&V%IoL z=$+~_04{}T+R8y&Q(8sfeqxPU)VQw zYOTqX+>WEpLP-VwVVC3RdjGHNrE0}L>?!KxKe5sL(EQ{O zSEX5ZdDf+QLQsvDswq^5_SW%u9a4WtqQgeZAg1k4E!&4yYS_f_B$*bB!b5 zYz`(c(W8H`P8X>B`X?_6S3HIb(9HXTj3TVlOFNcqtuJeSA45sFAKa4iR%C0a;`ys@ z(FO2o6A77#Wi)EuI}FUV8}RfRKN$QcN1VnHdV=iY^L;saHp}8lTI`Z1|M3lyk}BD9J$lWc*(Xa+Po$D7#kL?4jlRZuUlA$g z_rhiTO1}KxBfkkb-^6nnJg2#Ma&mz62Db&&=dMTgaQio5F<8oajMm7G4MOG#k+0wUN*!dQeMAx$s z)v$ z0rk`EeLD$l(5;V8RayKQM<=(i%yTVu!g(3qzu1x%E;%GE3Hr!!8uj~1%rPungNVMM zA>O74)HfXHBGyu77;K7>ge06MbS}xr1dRGPlX)`dB-E36TOBHS%zMXyvYFS2gCDFX zt|cb>CY{Nygc|%!L+o)7Mq+;w#pPY>p;At67{MzIv5$l34h_*0pqzo^0u{Or!*3if zOxYQ+Vq{N`1co2!O!_U5`Pe0z1YrVYAl=S@XgSXJp>l-;l`B`9tcp0F@K>{Aj0y2R zFl`|`+Jut#OW(nwA4}+^U0%8)Hi4rX)XB6+Y2AdTP}#4#hr{JR|MkuK3jSrxtdT_8 zM@nlJwHcu?WI2-FSuik=8VvY+ZW>7sl>-6td1+=|4C_c#MOFkKm_N2zcTxXUL&FvS zGvOgEYczU*_x|*aln(cvk1gFmZR%I;Y`#Y7;Y_oKOZLvEwnihOH^IPH!6Wrm2-5H| zDwMgV9}J@5tund*A>GgM$v(^nIM-L~Jm+brBru@6cqvz+%lKZOE^~ba z{UItE<;v_Bef4g6-ubZ(@rvM(DVhjxvH^R1rft^e@#QaWSF5j>`)H-33s^s|Q7m1V z)jeFcCwn=rxp=)_eTBJ-fWBfP*>sUhBEs^?efb+b`fjfH>7Fkg8gg^P&N$D}#_G#b zGw>~?Y;w34dC)x3)1_|WBX@oENT{5v{mr!(476~Fy8v;iy=nhSmee=(iuq}M@**A4 zb7>519oM&&vOQ$rmgaCF*-vv~l^L*YTt{Vk2XD8<*Rn2T;o2ZH6Z#SF^W}Hl0@3z) zd7F&8yaRawKj7aPDTOV>Tw|C4Gs3M$0H?9|D|9y`Jv)KAY}BM{Yko%( zxT?^QmT`|*i~0Up@$uT0MHH@lqx91)@$u;~dFWetQ}AQUN$7DIk>bvXN42dcA&g+= zatyh!fQ+k2XuV-zMmFOAk!r>WDV;0zJ%_z=jHpTUn;IV@{tE5?k|e?)NCwMW)&S!= z1zpmz#uyHXU)d5L-=wnw3zP6$=nz9BD5m2pXw_+;&D)n@V{Dk|67qx`C&h+*g|w#V z7UHxYqFD<^7A8vqxV;kT_V+dk9G&g88ipw`R zOrvy6B2^6P=#^n-P-oE^qHGhHd4V~`beaEfK5JYei0}fo(vq4U@v_LV|B*Y?dHavs zv#W^FFT%Sh;?C_RY!|$bM*B;s5gXYom$(89jggdVtXQi>)JISXB;g~b)&|%DpX<8X zFc~WF*s4~zaZi{_(2Ju|c#qSP>@8QYMTfYTH@XEbF$^xg;heAzC|^sy z4agPYGT{_o&3F^4p&iI|^yN=)^*?hVwi}yw(s~2QS^#P>CBB!);j@( z+W?X@L@Ry1!@-o*(ghB1u*+)yge5WOPZOTL>P;5r#Or?pQk@*jKJs zs!ySZ0gB;H3!X_RX#WIphW{TpGXBX`SS{MFSpnQzgPo2~lDuU@VEuqnPBLGW&`Sbk zOw7Hg9~G0)nO>?{U|nNGQIvAFsWHMRHY)C06B}xl1921;bxR8-sXTP_VR(rBwIt(2 zF26t~n|(x@6Qx{&aQwftpN_D2;soOlMjcsfK#miW z8LG`07;dTH^{H1|NeM)KSoTQ13rmbd;zU-&(ICP}MqXNc8EP1C#n=eR`jI%5Ay=~} zbgb@LD*Z)6PzIA=u+Fu~$*k-v29$sq$7x*Jy{^o+)W1Na?H!y-A zV!vlV1Q;?kaj~me_yZUDMw!MK5CZ~dE<4<^y=4MqKsX29h`Q6w#of{ZV$lK$kg-i* zF)jhIuI1i;CXuKps*z*e3idN+;w#e$jCvdofC5EP4*csC88S@dA_tp-9J7Vn5Vi)o zS@=k-zP>DH1Mbt3=muWO*f+0hgM`0MlwNY}K|KhR&lvu4$Qk-Ym^Y|^Hi^=CrK7?! z_B(w8YGg+FXHUg8IiY|fzTEfrb9zo#Vu4fa4`Un${nHbrh&kd;Fd!8}2DDu7RAL}) zXdH){=2Z}>U6>h-o2euHuY6Lb*v%-2NUw}JlWdX+Il-H-g92o2nhMqtLA#0t_$Eq6 z1VBNEFNSG?M1}Az5Z%gVj4TaR&v}PKvTM3I=Lp8q(<@rTnv*u#OdC z$!jknFs7rx+1$MN;@H(KTCIBS#V|`}1cSHhhR_BlCL~5}f^nz81f*q`)1oTmzpCJC zE%0=shNN-NS*56vGd>|$#K-JA02xUofzE;-9UF34J?UA_>1LUnAj4TTOe6)%pcmtw zxn5l~^f}`Jed)+j4mTg0UJnq?g0ZBy2!PItrs3`^cP6-s=tkHMQW5(-Pb$ z0J}!Ro%;ijU)&kW$qmm~$S}FGs%2cE2s4Cb-!!?1b6Hm0sK|CPbLnNZ-X<`2vk{d` z`KVV6=lxHSH5!2lymE@H7#diKmt1x?kb(>dU?)r3Sj2W4qKZ_WmSdG}#{wP(O=fJ+ zk^dgDd)Os-FUw&Fl%8tFM!|cO6?6WTlw?Sav474I)ka=iy-B<~ z3_V=S4)w%vyey^b3&H1zxI{t(-WNH;tofR$9Z)bp5(R+7kwtrund9OhiZD15XoxVclgy0&lam~NoRWm1o1Fik4+@>&T0lJ&I>yyU0`m_T zjjNC?w3i_gRk_n;smWWcZ2u(sjF^&9WH(DZyUcdr1V(5PWYfzWpOV`Al@guiwrQ-9 zJTX+XAc&Bf)&8%9)W57?bVZ7FAPGhL0NM3JmzBug-8~fUACM>(h22(*=^|W?gle8V zr3hCoA@Dsie{gpkMJXRr^2$?6U>FyrCzYThPL%_Dr|8R&Bj%b<3mjR##Soq(YfBvo z3OZmt{ieIo2-ze9y@^AmRC^`at*TF1MG?GJF;@GN`sQGd_9y@CgoB0@zMm-Dq&oaJ zUwS2kU&G4o22c=65M`(vatviSfkD}WdDbnY!VH3d;!eBu zJiFP6U_uk;qV>5#re4Pw&tD$EH+VY65HfMbk$n@TA3pQ*rZV%tUy#Ag1<5GCGd3z* zk+VVW6-P!>V@?7YV-lrxFRuxeJvyo`bZWcjC14Px;EU7xdI`^|qBCA{MIG`_l}>MF z>_!U?ibUf0is~0oWYY@5m|%T2YbcE5|GzW`E*yX94j>I2W%K;f(Kq+LKt_%_^JutZ zr|^@>Q$Nv1ds3-PrgB!@lzL||MT9|UEORzmr(R8g|IA-w6 zdOok{z;0|d4iI9s#q0fnf~;eQsfajW20O<@10qi1%Fsmyl=UcF$?78K5P75g>n_mZ zXXdb)Sv)um5R+?yV+@EYhfrnQN+P)oDFL40lExYo@AG!#=)kghUiaQkfh(Bu#EdK+Q_U~{)fQWze;TE1k#@oY5QZlO5 zAO{2FwlN^aHgf7^Kpf(r9Ftw-Nd#9DjG<1_p=itw<0!k}T?WLe2kmE;n>#v=!e=If zXiFEwN;Wr194W`siD3mTcT)2 ziY*{CAQwLvP^!Fuszuy`jCt1+Ae%IvaPX!b*pI@jgY zi|Xp@$}u?tDXTQd+d5Vgp5kK5po0HJC6!=5L}3{hq)yimd^oIg#f8A98j$@E%5y;W zLrNKONa0^+H8qYmpqMe{U;PX$T?9VW&|*JCn`axb*bf2z5JxjsW)$6!s4@rHt#0g$ zID?ttJ)WL}&zOpH`2gCj8AXks9XN@EvT{XRV>w)2da zOLG5sM+J{vFUioyt~+~|W~7`z<+`-I_Il@>!9iL)efkh|H|$gNjX~U z9G>Q>X}J?B!@boPHgrEO3B=*)cH?F(SU3|mTKfm>^L(FP_v2UgJ08_|$i7|8{Mz2t zj%?-r%rrIru-!eI*9hyYko(Dni>m&Z?Nj$0#`VGHAHf}x+Yj5nRnH!=ea$7?scVkd zLsi8QJ4ZDh!7=2aId+HsX}q>jpR|>8z*-_)H~5G7bLU+BCJsf{);wK|L(z{HA5PCw zQ;yotrQ_(YYJ1Ec*`ssHq3kY2a%Cp%1&roUP)_)5nGUn=%_pu5LXuV?!6Jx|nq znCb7=UY-4%k2m_~=KFi*>cjgtLGF8bpc##lMx{PlAiCgQUfA{Zd zd)gJD@br!^4!3%Q=In}w!hHvy7_R(_e8bf0L;icye#}#Mei+D86TbEjQa!)+cTrVe z`)^fO9rowu?#mx7mG+e!#5ryp->ym@9GGy6<_T0 zsb>!R&r^@x;yXi)J>tJeeR0@7T-|-de{tG}+3I&k{HLj@NBvo9&k_F|_03}6x$3c_ z{?RIa%s*CLf6RZey6Bic*Yml$;+Vgy`s%3v3ia+HUza-nH~u~zwdJ@!qShSupRF!D z4*ZO7@z=p6zATmToqvcr_gjBRUAhGKV%PDn>%a9Es~eX2iq*5<`SaB!-{IW{%X~RK zjmW6ZPpA%h%3XP|(E)&O1&kVpBkH{>Utas>>VK~66aGT=hZFvg=Oa~j!e6G&yA6Eb zS?cSO)lBag)l>C7atD0xFIT9B*r4)v z1};_|J__{oe5w-1{C(AZ9|elkfR6&hRqn@uerek>)x4wrbJS73{_5kvm1^lC(4YHp zV3E4=lfc5X7di{c&PVf&9+soEwH~&A5}2YQp9XrWWuFGh)QnF9fwVQI9gln(nCz)m zfhE2IRkbUStB&3ZxkAVNt<}0+fspF5JCLm=ECnm??m#Csb9Z2->b)Bo)Aj^LtG0Vk z;)y)~eR~2W>K$er*b|uT*{LbM`dJ{~bECR(nXjk1^fO3)!Cq8z;9iva=VyT)>iy5~ zSNh(-S)S!;(B43fs@@wY^88B+v3GBvwK}mkFfb!OxUG#EdYjL$&fgapt6t-yYG2@7 zmGOCCw)E3c;!}7>dGh6Ya!;x_LHgq4yrAQRB$tiq$>^%4PP23CwtpTN(_WqNb)ZK& zZhuvY`+R4s{7Y=z@aw?Io@!I4!a}v6Q{h;(w^QM>btg_Md@!wUW#__K9(7Nb z!oL@$p$R6#6c?ifM(^oa0`ufGul#m`ugZH|tDfpw_}iY|B)qpT$Ri#-uT!)`yPd_V zQ(j??8j@FdNL6S0y|D}kZe(szQ+@ZJscmx}Ybr0(Xsf9jI)|@3I@^-(Y?{jr1{^|J zPe!X>O$l9LMusoW13nKF8rL_x~bbEg?7)EN!q1jkS0oCV3==IgNh4% zYHOr$QrgC}y5i!(Oize5BpSmfEVv?HK2mB4i>~!$jxxfn^JMT_CXOTOu9Ctbo=@uj zr=)OVj{e6KAF3e}3-v#ym^86)fak-cQQ*%L3m57^$PAbxIdprc&z?2?+I^l6>xNA# zT+=~yi55=g|H2rneitoV!J8pl_cU@^XuQ@7rp=xcTypwGi*B jZZ{brhTT-y!}G2dV%|-Kx2W6g!t5?dY~OXS!nFP$I^(nP delta 19226 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 t + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sonstiges/menu/kombinierbar.svg b/sonstiges/menu/kombinierbar.svg new file mode 100644 index 0000000..a3cdd4c --- /dev/null +++ b/sonstiges/menu/kombinierbar.svg @@ -0,0 +1,64 @@ + + + + + + + + + + From f990188249430d33c8fd69dd9f65369a31752f82 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:17:22 +0200 Subject: [PATCH 14/25] only encode password --- .../mobilelearning/helper/moodle/MoodleInterface.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java index 498d492..9abfdba 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java @@ -36,14 +36,12 @@ public Boolean login() { // get the token from // https://moodle.htwg-konstanz.de/moodle/login/token.php?username=USERNAME&password=PASSWORD&service=SERVICESHORTNAME CloseableHttpClient client = HttpClients.createDefault(); - String unencodedUrl = "https://moodle.htwg-konstanz.de/moodle/login/token.php?username=" + this.username + "&password=" + this.password + "&service=moodle_mobile_app"; - String encodedUrl = URLEncoder.encode(unencodedUrl, "UTF-8"); - HttpGet request = new HttpGet(encodedUrl); + HttpGet request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/login/token.php?username=" + this.username + "&password=" + URLEncoder.encode(this.password, "UTF-8") + "&service=moodle_mobile_app"); MoodleTokenResponse tokenResponse = mapper.readValue(client.execute(request).getEntity().getContent(), MoodleTokenResponse.class); this.token = tokenResponse.token; - // System.out.println("Successfully logged in as " + this.username + " with - // token " + this.token.substring(0, 5) + "..."); + System.out.println("Successfully logged in as " + this.username + " with token " + this.token.substring(0, 5) + "..."); + System.out.println(tokenResponse); // get user id String wsFunction = "core_webservice_get_site_info"; @@ -67,6 +65,7 @@ public Boolean login() { } catch (Exception e) { System.out.println("Error while logging into moodle: " + e.getMessage()); + System.out.println(e); return false; } From f2c3f2387d2efbe8f5a8e39d56e8fafa02dd350c Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:29:12 +0200 Subject: [PATCH 15/25] mock all courses from 1 to 1000 --- .../mobilelearning/helper/moodle/MoodleInterface.java | 5 ++++- frontend/pubspec.lock | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java index 9abfdba..c661324 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java @@ -83,7 +83,10 @@ public List getCourses() { // TEMP: mock the special users (Prof, Student, Admin) if (this.username.startsWith("Prof") || this.username.startsWith("Student") || this.username.startsWith("Admin")) { - return List.of(new MoodleCourse("1"), new MoodleCourse("2"), new MoodleCourse("3"), new MoodleCourse("940")); + List courses = new ArrayList(); + for (Integer i = 1; i <= 1000; i++) { + courses.add(new MoodleCourse(i.toString())); + } } // if courses are already set return them if not fetch them diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index 811b3cc..2ee1e4c 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -574,5 +574,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" From eb817f650c931fe716856c3174eefd05fcee8d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:29:59 +0200 Subject: [PATCH 16/25] alias @ quiz & scorboard border --- .../general/quiz/QuizScoreboard.dart | 40 ++++++++++++++----- frontend/lib/pages/quiz/attend_quiz_page.dart | 22 +++++++++- .../lib/pages/quiz/quiz_control_page.dart | 6 ++- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/frontend/lib/components/general/quiz/QuizScoreboard.dart b/frontend/lib/components/general/quiz/QuizScoreboard.dart index c49bdfb..2c8866a 100644 --- a/frontend/lib/components/general/quiz/QuizScoreboard.dart +++ b/frontend/lib/components/general/quiz/QuizScoreboard.dart @@ -2,10 +2,12 @@ import 'package:flutter/material.dart'; class QuizScoreboard extends StatefulWidget { final List scoreboard; + final String alias; const QuizScoreboard({ super.key, required this.scoreboard, + required this.alias, }); @override @@ -40,17 +42,33 @@ class _QuizScoreboardState extends State { physics: const NeverScrollableScrollPhysics(), itemCount: _scoreboard.length, itemBuilder: (BuildContext context, int index) { - return ListTile( - leading: Text( - _scoreboard[index]["rank"].toString(), - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - ), - title: Text(_scoreboard[index]["userAlias"]), - trailing: Text( - _scoreboard[index]["score"].toString(), - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - ), - ); + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(0.0), + border: (_scoreboard[index]["userAlias"] == widget.alias) + ? Border.all( + color: colors + .primary, // Change this color to whatever you want + width: 2.0, // Change this width to whatever you want + ) + : Border.all( + color: Colors + .transparent, // No border when condition is not met + ), + ), + child: ListTile( + leading: Text( + _scoreboard[index]["rank"].toString(), + style: + const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + title: Text(_scoreboard[index]["userAlias"]), + trailing: Text( + _scoreboard[index]["score"].toString(), + style: + const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + )); }, ); } diff --git a/frontend/lib/pages/quiz/attend_quiz_page.dart b/frontend/lib/pages/quiz/attend_quiz_page.dart index 4bd21c8..b3c2bab 100644 --- a/frontend/lib/pages/quiz/attend_quiz_page.dart +++ b/frontend/lib/pages/quiz/attend_quiz_page.dart @@ -405,6 +405,7 @@ class _AttendQuizPageState extends AuthState { } if (_fetchResult == 'success') { + final colors = Theme.of(context).colorScheme; final appBar = AppBar( title: const Text( 'Einem Quiz beitreten', //_form.name, TODO: find better solution @@ -515,7 +516,7 @@ class _AttendQuizPageState extends AuthState { child: Card( child: Padding( padding: const EdgeInsets.all(8), - child: QuizScoreboard(scoreboard: _scoreboard), + child: QuizScoreboard(scoreboard: _scoreboard, alias: _alias), ), ), ), @@ -570,6 +571,25 @@ class _AttendQuizPageState extends AuthState { body: SingleChildScrollView( child: Column( children: [ + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + color: colors.surfaceVariant, + child: Row( + children: [ + Expanded( + child: Text( + "Dein Alias: ${_alias}", + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + ), Padding( padding: const EdgeInsets.only(left: 16.0, top: 16.0, right: 16.0), diff --git a/frontend/lib/pages/quiz/quiz_control_page.dart b/frontend/lib/pages/quiz/quiz_control_page.dart index 619e7cf..b2f6e4c 100644 --- a/frontend/lib/pages/quiz/quiz_control_page.dart +++ b/frontend/lib/pages/quiz/quiz_control_page.dart @@ -541,7 +541,7 @@ class _QuizControlPageState extends AuthState { child: Card( child: Padding( padding: const EdgeInsets.all(8), - child: QuizScoreboard(scoreboard: _scoreboard), + child: QuizScoreboard(scoreboard: _scoreboard, alias: ""), ), ), ), @@ -613,7 +613,9 @@ class _QuizControlPageState extends AuthState { child: Padding( padding: const EdgeInsets.all(8), child: QuizScoreboard( - scoreboard: _scoreboard), + scoreboard: _scoreboard, + alias: "", + ), ), ), )) From 4561b376456a11ba68945d742006a67721ec2aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:49:46 +0200 Subject: [PATCH 17/25] border radius --- frontend/lib/components/general/quiz/QuizScoreboard.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/lib/components/general/quiz/QuizScoreboard.dart b/frontend/lib/components/general/quiz/QuizScoreboard.dart index 2c8866a..86d3bf9 100644 --- a/frontend/lib/components/general/quiz/QuizScoreboard.dart +++ b/frontend/lib/components/general/quiz/QuizScoreboard.dart @@ -44,7 +44,7 @@ class _QuizScoreboardState extends State { itemBuilder: (BuildContext context, int index) { return Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(0.0), + borderRadius: BorderRadius.circular(20.0), border: (_scoreboard[index]["userAlias"] == widget.alias) ? Border.all( color: colors From 8abb7f3645fe7c1bdb87e38d3d1ac860af526a4b Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:49:52 +0200 Subject: [PATCH 18/25] return courses --- .../mobilelearning/helper/moodle/MoodleInterface.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java index c661324..2fbf36e 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java @@ -87,6 +87,7 @@ public List getCourses() { for (Integer i = 1; i <= 1000; i++) { courses.add(new MoodleCourse(i.toString())); } + return courses; } // if courses are already set return them if not fetch them From 5154e9caf8dd558e8c154ed1ecbaf23afe5d5d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:00:13 +0200 Subject: [PATCH 19/25] revert scoreboardborder --- .../general/quiz/QuizScoreboard.dart | 40 +++++-------------- frontend/lib/pages/quiz/attend_quiz_page.dart | 2 +- .../lib/pages/quiz/quiz_control_page.dart | 5 +-- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/frontend/lib/components/general/quiz/QuizScoreboard.dart b/frontend/lib/components/general/quiz/QuizScoreboard.dart index 86d3bf9..c49bdfb 100644 --- a/frontend/lib/components/general/quiz/QuizScoreboard.dart +++ b/frontend/lib/components/general/quiz/QuizScoreboard.dart @@ -2,12 +2,10 @@ import 'package:flutter/material.dart'; class QuizScoreboard extends StatefulWidget { final List scoreboard; - final String alias; const QuizScoreboard({ super.key, required this.scoreboard, - required this.alias, }); @override @@ -42,33 +40,17 @@ class _QuizScoreboardState extends State { physics: const NeverScrollableScrollPhysics(), itemCount: _scoreboard.length, itemBuilder: (BuildContext context, int index) { - return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), - border: (_scoreboard[index]["userAlias"] == widget.alias) - ? Border.all( - color: colors - .primary, // Change this color to whatever you want - width: 2.0, // Change this width to whatever you want - ) - : Border.all( - color: Colors - .transparent, // No border when condition is not met - ), - ), - child: ListTile( - leading: Text( - _scoreboard[index]["rank"].toString(), - style: - const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - ), - title: Text(_scoreboard[index]["userAlias"]), - trailing: Text( - _scoreboard[index]["score"].toString(), - style: - const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - ), - )); + return ListTile( + leading: Text( + _scoreboard[index]["rank"].toString(), + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + title: Text(_scoreboard[index]["userAlias"]), + trailing: Text( + _scoreboard[index]["score"].toString(), + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + ); }, ); } diff --git a/frontend/lib/pages/quiz/attend_quiz_page.dart b/frontend/lib/pages/quiz/attend_quiz_page.dart index b3c2bab..6fd54f6 100644 --- a/frontend/lib/pages/quiz/attend_quiz_page.dart +++ b/frontend/lib/pages/quiz/attend_quiz_page.dart @@ -516,7 +516,7 @@ class _AttendQuizPageState extends AuthState { child: Card( child: Padding( padding: const EdgeInsets.all(8), - child: QuizScoreboard(scoreboard: _scoreboard, alias: _alias), + child: QuizScoreboard(scoreboard: _scoreboard), ), ), ), diff --git a/frontend/lib/pages/quiz/quiz_control_page.dart b/frontend/lib/pages/quiz/quiz_control_page.dart index b2f6e4c..1da9cf1 100644 --- a/frontend/lib/pages/quiz/quiz_control_page.dart +++ b/frontend/lib/pages/quiz/quiz_control_page.dart @@ -541,7 +541,7 @@ class _QuizControlPageState extends AuthState { child: Card( child: Padding( padding: const EdgeInsets.all(8), - child: QuizScoreboard(scoreboard: _scoreboard, alias: ""), + child: QuizScoreboard(scoreboard: _scoreboard), ), ), ), @@ -613,8 +613,7 @@ class _QuizControlPageState extends AuthState { child: Padding( padding: const EdgeInsets.all(8), child: QuizScoreboard( - scoreboard: _scoreboard, - alias: "", + scoreboard: _scoreboard ), ), ), From baa73bf804908750dcb93ca0a3124415692dcb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:12:23 +0200 Subject: [PATCH 20/25] alias top row fix? --- frontend/lib/pages/quiz/attend_quiz_page.dart | 314 +++++++++--------- 1 file changed, 158 insertions(+), 156 deletions(-) diff --git a/frontend/lib/pages/quiz/attend_quiz_page.dart b/frontend/lib/pages/quiz/attend_quiz_page.dart index 6fd54f6..7e29cf2 100644 --- a/frontend/lib/pages/quiz/attend_quiz_page.dart +++ b/frontend/lib/pages/quiz/attend_quiz_page.dart @@ -568,173 +568,175 @@ class _AttendQuizPageState extends AuthState { return Scaffold( appBar: appBarWithProgress, - body: SingleChildScrollView( - child: Column( - children: [ - Positioned( - top: 0, - left: 0, - right: 0, - child: Container( - color: colors.surfaceVariant, - child: Row( - children: [ - Expanded( - child: Text( - "Dein Alias: ${_alias}", - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - ), - ], - ), - ), - ), - Padding( - padding: - const EdgeInsets.only(left: 16.0, top: 16.0, right: 16.0), - child: Column( + body: Stack(children: [ + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + color: colors.surfaceVariant, + child: Row( children: [ - const SizedBox(height: 16), - Text(element.name, - style: const TextStyle( - fontSize: 25, fontWeight: FontWeight.w700)), - Text(element.description, - style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.w500), - textAlign: TextAlign.center), - const SizedBox(height: 16), - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: element.type == QuestionType.single_choice - ? SingleChoiceQuiz( - correctAnswers: _correctAnswers, - currentQuestionFinished: - _form!.currentQuestionFinished, - voted: _voted, - value: _value, - options: element.options, - onSelectionChanged: (newValue) { - setState(() { - _value = newValue; - }); - }, - ) - : element.type == QuestionType.yes_no - ? YesNoQuiz( - correctAnswers: _correctAnswers, - currentQuestionFinished: - _form!.currentQuestionFinished, - voted: _voted, - value: _value, - onSelectionChanged: (newValue) { - setState(() { - _value = newValue; - }); - }, - ) - : Text(element.type.toString()), + Expanded( + child: Text( + "Dein Alias: ${_alias}", + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, ), ), ], ), ), - if (!_form!.currentQuestionFinished && _voted) - Container( - margin: const EdgeInsets.only( - top: 0.0, - bottom: 10.0), // specify the top and bottom margin - - width: 130, - height: 130, - child: RiveAnimation.direct( - widget.riveFile!, - fit: BoxFit.cover, - artboard: 'true & false', - stateMachines: ['tf State Machine'], - onInit: _onRiveInit, - )), - if (_form!.currentQuestionFinished && _voted) - Container( - margin: const EdgeInsets.only( - top: 0.0, - bottom: 10.0), // specify the top and bottom margin - - width: 130, - height: 130, - child: RiveAnimation.direct( - widget.riveFile!, - fit: BoxFit.cover, - artboard: 'true & false', - stateMachines: ['tf State Machine'], - onInit: _onRiveInit, - )), - if (_form!.currentQuestionFinished && !_voted) - Container( - margin: const EdgeInsets.only( - top: 0.0, - bottom: 10.0), // specify the top and bottom margin - - width: 130, - height: 130, - child: RiveAnimation.direct( - widget.riveFile!, - fit: BoxFit.cover, - artboard: 'true & false', - animations: ['nicht abgestimmt'], - )), - // if the user gained point, show them - if (_form!.currentQuestionFinished && - _voted && - _userHasAnsweredCorrectly) - Text( - "Du hast $_gainedPoints Punkte erhalten.", - style: - const TextStyle(fontSize: 20, fontWeight: FontWeight.w700), + ), + SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: + const EdgeInsets.only(left: 16.0, top: 16.0, right: 16.0), + child: Column( + children: [ + const SizedBox(height: 16), + Text(element.name, + style: const TextStyle( + fontSize: 25, fontWeight: FontWeight.w700)), + Text(element.description, + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.w500), + textAlign: TextAlign.center), + const SizedBox(height: 16), + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: element.type == QuestionType.single_choice + ? SingleChoiceQuiz( + correctAnswers: _correctAnswers, + currentQuestionFinished: + _form!.currentQuestionFinished, + voted: _voted, + value: _value, + options: element.options, + onSelectionChanged: (newValue) { + setState(() { + _value = newValue; + }); + }, + ) + : element.type == QuestionType.yes_no + ? YesNoQuiz( + correctAnswers: _correctAnswers, + currentQuestionFinished: + _form!.currentQuestionFinished, + voted: _voted, + value: _value, + onSelectionChanged: (newValue) { + setState(() { + _value = newValue; + }); + }, + ) + : Text(element.type.toString()), + ), + ), + ], + ), ), - const SizedBox(height: 10), - (!_form!.currentQuestionFinished && !_voted) - ? SizedBox( - height: 55, - width: buttonWidth, - child: ElevatedButton( - style: ButtonStyle( - elevation: MaterialStateProperty.all(6.0), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(14.0), + if (!_form!.currentQuestionFinished && _voted) + Container( + margin: const EdgeInsets.only( + top: 0.0, + bottom: 10.0), // specify the top and bottom margin + + width: 130, + height: 130, + child: RiveAnimation.direct( + widget.riveFile!, + fit: BoxFit.cover, + artboard: 'true & false', + stateMachines: ['tf State Machine'], + onInit: _onRiveInit, + )), + if (_form!.currentQuestionFinished && _voted) + Container( + margin: const EdgeInsets.only( + top: 0.0, + bottom: 10.0), // specify the top and bottom margin + + width: 130, + height: 130, + child: RiveAnimation.direct( + widget.riveFile!, + fit: BoxFit.cover, + artboard: 'true & false', + stateMachines: ['tf State Machine'], + onInit: _onRiveInit, + )), + if (_form!.currentQuestionFinished && !_voted) + Container( + margin: const EdgeInsets.only( + top: 0.0, + bottom: 10.0), // specify the top and bottom margin + + width: 130, + height: 130, + child: RiveAnimation.direct( + widget.riveFile!, + fit: BoxFit.cover, + artboard: 'true & false', + animations: ['nicht abgestimmt'], + )), + // if the user gained point, show them + if (_form!.currentQuestionFinished && + _voted && + _userHasAnsweredCorrectly) + Text( + "Du hast $_gainedPoints Punkte erhalten.", + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.w700), + ), + const SizedBox(height: 10), + (!_form!.currentQuestionFinished && !_voted) + ? SizedBox( + height: 55, + width: buttonWidth, + child: ElevatedButton( + style: ButtonStyle( + elevation: MaterialStateProperty.all(6.0), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14.0), + ), ), + backgroundColor: MaterialStateProperty.all( + Theme.of(context).colorScheme.surface), + foregroundColor: MaterialStateProperty.all( + Theme.of(context).colorScheme.primary), ), - backgroundColor: MaterialStateProperty.all( - Theme.of(context).colorScheme.surface), - foregroundColor: MaterialStateProperty.all( - Theme.of(context).colorScheme.primary), + child: const Text('Senden', + style: TextStyle(fontSize: 20)), + onPressed: () { + if (_value == null) { + return; + } + var message = { + "action": "ADD_RESULT", + "resultElementId": element.id, + "resultValues": [_value], + "role": "STUDENT" + }; + _socketChannel?.sink.add(jsonEncode(message)); + setState(() { + _voted = true; + }); + }, ), - child: - const Text('Senden', style: TextStyle(fontSize: 20)), - onPressed: () { - if (_value == null) { - return; - } - var message = { - "action": "ADD_RESULT", - "resultElementId": element.id, - "resultValues": [_value], - "role": "STUDENT" - }; - _socketChannel?.sink.add(jsonEncode(message)); - setState(() { - _voted = true; - }); - }, - ), - ) - : Container(), + ) + : Container(), - const SizedBox(height: 20), - ], - )), + const SizedBox(height: 20), + ], + )) + ]), ); } else { _showErrorDialog(_fetchResult); From e865e638df453da7da55a95fc6c9d25a817ccfbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:20:16 +0200 Subject: [PATCH 21/25] undo scoreboardborder revert --- .../general/quiz/QuizScoreboard.dart | 40 ++++++++++++++----- frontend/lib/pages/quiz/attend_quiz_page.dart | 34 ++++++++-------- .../lib/pages/quiz/quiz_control_page.dart | 5 ++- 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/frontend/lib/components/general/quiz/QuizScoreboard.dart b/frontend/lib/components/general/quiz/QuizScoreboard.dart index c49bdfb..86d3bf9 100644 --- a/frontend/lib/components/general/quiz/QuizScoreboard.dart +++ b/frontend/lib/components/general/quiz/QuizScoreboard.dart @@ -2,10 +2,12 @@ import 'package:flutter/material.dart'; class QuizScoreboard extends StatefulWidget { final List scoreboard; + final String alias; const QuizScoreboard({ super.key, required this.scoreboard, + required this.alias, }); @override @@ -40,17 +42,33 @@ class _QuizScoreboardState extends State { physics: const NeverScrollableScrollPhysics(), itemCount: _scoreboard.length, itemBuilder: (BuildContext context, int index) { - return ListTile( - leading: Text( - _scoreboard[index]["rank"].toString(), - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - ), - title: Text(_scoreboard[index]["userAlias"]), - trailing: Text( - _scoreboard[index]["score"].toString(), - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - ), - ); + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), + border: (_scoreboard[index]["userAlias"] == widget.alias) + ? Border.all( + color: colors + .primary, // Change this color to whatever you want + width: 2.0, // Change this width to whatever you want + ) + : Border.all( + color: Colors + .transparent, // No border when condition is not met + ), + ), + child: ListTile( + leading: Text( + _scoreboard[index]["rank"].toString(), + style: + const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + title: Text(_scoreboard[index]["userAlias"]), + trailing: Text( + _scoreboard[index]["score"].toString(), + style: + const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + )); }, ); } diff --git a/frontend/lib/pages/quiz/attend_quiz_page.dart b/frontend/lib/pages/quiz/attend_quiz_page.dart index 7e29cf2..a346e86 100644 --- a/frontend/lib/pages/quiz/attend_quiz_page.dart +++ b/frontend/lib/pages/quiz/attend_quiz_page.dart @@ -516,7 +516,7 @@ class _AttendQuizPageState extends AuthState { child: Card( child: Padding( padding: const EdgeInsets.all(8), - child: QuizScoreboard(scoreboard: _scoreboard), + child: QuizScoreboard(scoreboard: _scoreboard, alias: _alias), ), ), ), @@ -570,24 +570,24 @@ class _AttendQuizPageState extends AuthState { appBar: appBarWithProgress, body: Stack(children: [ Positioned( - top: 0, - left: 0, - right: 0, - child: Container( - color: colors.surfaceVariant, - child: Row( - children: [ - Expanded( - child: Text( - "Dein Alias: ${_alias}", - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), + top: 0, + left: 0, + right: 0, + child: Container( + color: colors.surfaceVariant, + child: Row( + children: [ + Expanded( + child: Text( + "Dein Alias: ${_alias}", + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + ), + ), + ], ), - ], + ), ), - ), - ), SingleChildScrollView( child: Column( children: [ diff --git a/frontend/lib/pages/quiz/quiz_control_page.dart b/frontend/lib/pages/quiz/quiz_control_page.dart index 1da9cf1..b2f6e4c 100644 --- a/frontend/lib/pages/quiz/quiz_control_page.dart +++ b/frontend/lib/pages/quiz/quiz_control_page.dart @@ -541,7 +541,7 @@ class _QuizControlPageState extends AuthState { child: Card( child: Padding( padding: const EdgeInsets.all(8), - child: QuizScoreboard(scoreboard: _scoreboard), + child: QuizScoreboard(scoreboard: _scoreboard, alias: ""), ), ), ), @@ -613,7 +613,8 @@ class _QuizControlPageState extends AuthState { child: Padding( padding: const EdgeInsets.all(8), child: QuizScoreboard( - scoreboard: _scoreboard + scoreboard: _scoreboard, + alias: "", ), ), ), From 61c1e009ae626dd258a286e7eba92ae265bd46f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:22:54 +0200 Subject: [PATCH 22/25] alias bar change --- frontend/lib/pages/quiz/attend_quiz_page.dart | 324 +++++++++--------- 1 file changed, 163 insertions(+), 161 deletions(-) diff --git a/frontend/lib/pages/quiz/attend_quiz_page.dart b/frontend/lib/pages/quiz/attend_quiz_page.dart index a346e86..86fdcf1 100644 --- a/frontend/lib/pages/quiz/attend_quiz_page.dart +++ b/frontend/lib/pages/quiz/attend_quiz_page.dart @@ -569,173 +569,175 @@ class _AttendQuizPageState extends AuthState { return Scaffold( appBar: appBarWithProgress, body: Stack(children: [ - Positioned( - top: 0, - left: 0, - right: 0, - child: Container( - color: colors.surfaceVariant, - child: Row( - children: [ - Expanded( - child: Text( - "Dein Alias: ${_alias}", - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - ), - ], - ), - ), - ), SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: - const EdgeInsets.only(left: 16.0, top: 16.0, right: 16.0), - child: Column( - children: [ - const SizedBox(height: 16), - Text(element.name, - style: const TextStyle( - fontSize: 25, fontWeight: FontWeight.w700)), - Text(element.description, - style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.w500), - textAlign: TextAlign.center), - const SizedBox(height: 16), - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: element.type == QuestionType.single_choice - ? SingleChoiceQuiz( - correctAnswers: _correctAnswers, - currentQuestionFinished: - _form!.currentQuestionFinished, - voted: _voted, - value: _value, - options: element.options, - onSelectionChanged: (newValue) { - setState(() { - _value = newValue; - }); - }, - ) - : element.type == QuestionType.yes_no - ? YesNoQuiz( - correctAnswers: _correctAnswers, - currentQuestionFinished: - _form!.currentQuestionFinished, - voted: _voted, - value: _value, - onSelectionChanged: (newValue) { - setState(() { - _value = newValue; - }); - }, - ) - : Text(element.type.toString()), + child: SizedBox( + width: double.infinity, + child: Column( + children: [ + Container( + color: colors.surfaceVariant, + child: Row( + children: [ + Expanded( + child: Text( + "Dein Alias: ${_alias}", + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + ), + ), + ], + ), ), - ), - ], - ), - ), - if (!_form!.currentQuestionFinished && _voted) - Container( - margin: const EdgeInsets.only( - top: 0.0, - bottom: 10.0), // specify the top and bottom margin - - width: 130, - height: 130, - child: RiveAnimation.direct( - widget.riveFile!, - fit: BoxFit.cover, - artboard: 'true & false', - stateMachines: ['tf State Machine'], - onInit: _onRiveInit, - )), - if (_form!.currentQuestionFinished && _voted) - Container( - margin: const EdgeInsets.only( - top: 0.0, - bottom: 10.0), // specify the top and bottom margin - - width: 130, - height: 130, - child: RiveAnimation.direct( - widget.riveFile!, - fit: BoxFit.cover, - artboard: 'true & false', - stateMachines: ['tf State Machine'], - onInit: _onRiveInit, - )), - if (_form!.currentQuestionFinished && !_voted) - Container( - margin: const EdgeInsets.only( - top: 0.0, - bottom: 10.0), // specify the top and bottom margin - - width: 130, - height: 130, - child: RiveAnimation.direct( - widget.riveFile!, - fit: BoxFit.cover, - artboard: 'true & false', - animations: ['nicht abgestimmt'], - )), - // if the user gained point, show them - if (_form!.currentQuestionFinished && - _voted && - _userHasAnsweredCorrectly) - Text( - "Du hast $_gainedPoints Punkte erhalten.", - style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.w700), - ), - const SizedBox(height: 10), - (!_form!.currentQuestionFinished && !_voted) - ? SizedBox( - height: 55, - width: buttonWidth, - child: ElevatedButton( - style: ButtonStyle( - elevation: MaterialStateProperty.all(6.0), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(14.0), + Padding( + padding: + const EdgeInsets.only(left: 16.0, top: 4.0, right: 16.0), + child: Column( + children: [ + const SizedBox(height: 16), + Text(element.name, + style: const TextStyle( + fontSize: 25, fontWeight: FontWeight.w700)), + Text(element.description, + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.w500), + textAlign: TextAlign.center), + const SizedBox(height: 16), + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: element.type == QuestionType.single_choice + ? SingleChoiceQuiz( + correctAnswers: _correctAnswers, + currentQuestionFinished: + _form!.currentQuestionFinished, + voted: _voted, + value: _value, + options: element.options, + onSelectionChanged: (newValue) { + setState(() { + _value = newValue; + }); + }, + ) + : element.type == QuestionType.yes_no + ? YesNoQuiz( + correctAnswers: _correctAnswers, + currentQuestionFinished: + _form!.currentQuestionFinished, + voted: _voted, + value: _value, + onSelectionChanged: (newValue) { + setState(() { + _value = newValue; + }); + }, + ) + : Text(element.type.toString()), + ), ), - ), - backgroundColor: MaterialStateProperty.all( - Theme.of(context).colorScheme.surface), - foregroundColor: MaterialStateProperty.all( - Theme.of(context).colorScheme.primary), + ], ), - child: const Text('Senden', - style: TextStyle(fontSize: 20)), - onPressed: () { - if (_value == null) { - return; - } - var message = { - "action": "ADD_RESULT", - "resultElementId": element.id, - "resultValues": [_value], - "role": "STUDENT" - }; - _socketChannel?.sink.add(jsonEncode(message)); - setState(() { - _voted = true; - }); - }, ), - ) - : Container(), + if (!_form!.currentQuestionFinished && _voted) + Container( + margin: const EdgeInsets.only( + top: 0.0, + bottom: + 10.0), // specify the top and bottom margin + + width: 130, + height: 130, + child: RiveAnimation.direct( + widget.riveFile!, + fit: BoxFit.cover, + artboard: 'true & false', + stateMachines: ['tf State Machine'], + onInit: _onRiveInit, + )), + if (_form!.currentQuestionFinished && _voted) + Container( + margin: const EdgeInsets.only( + top: 0.0, + bottom: 10.0), // specify the top and bottom margin + + width: 130, + height: 130, + child: RiveAnimation.direct( + widget.riveFile!, + fit: BoxFit.cover, + artboard: 'true & false', + stateMachines: ['tf State Machine'], + onInit: _onRiveInit, + )), + if (_form!.currentQuestionFinished && !_voted) + Container( + margin: const EdgeInsets.only( + top: 0.0, + bottom: 10.0), // specify the top and bottom margin + + width: 130, + height: 130, + child: RiveAnimation.direct( + widget.riveFile!, + fit: BoxFit.cover, + artboard: 'true & false', + animations: ['nicht abgestimmt'], + )), + // if the user gained point, show them + if (_form!.currentQuestionFinished && + _voted && + _userHasAnsweredCorrectly) + Text( + "Du hast $_gainedPoints Punkte erhalten.", + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.w700), + ), + const SizedBox(height: 10), + (!_form!.currentQuestionFinished && !_voted) + ? SizedBox( + height: 55, + width: buttonWidth, + child: ElevatedButton( + style: ButtonStyle( + elevation: + MaterialStateProperty.all(6.0), + shape: + MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14.0), + ), + ), + backgroundColor: MaterialStateProperty.all< + Color>( + Theme.of(context).colorScheme.surface), + foregroundColor: MaterialStateProperty.all< + Color>( + Theme.of(context).colorScheme.primary), + ), + child: const Text('Senden', + style: TextStyle(fontSize: 20)), + onPressed: () { + if (_value == null) { + return; + } + var message = { + "action": "ADD_RESULT", + "resultElementId": element.id, + "resultValues": [_value], + "role": "STUDENT" + }; + _socketChannel?.sink.add(jsonEncode(message)); + setState(() { + _voted = true; + }); + }, + ), + ) + : Container(), - const SizedBox(height: 20), - ], - )) + const SizedBox(height: 20), + ], + ))), ]), ); } else { From d54e026a403b51ddcbc9db603375ede82b5a989b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20T=C3=B6gel?= <71888952+TobiTgl@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:36:56 +0200 Subject: [PATCH 23/25] alias top bar --- frontend/lib/pages/quiz/attend_quiz_page.dart | 112 ++++++++++-------- 1 file changed, 60 insertions(+), 52 deletions(-) diff --git a/frontend/lib/pages/quiz/attend_quiz_page.dart b/frontend/lib/pages/quiz/attend_quiz_page.dart index 86fdcf1..9c15079 100644 --- a/frontend/lib/pages/quiz/attend_quiz_page.dart +++ b/frontend/lib/pages/quiz/attend_quiz_page.dart @@ -573,71 +573,61 @@ class _AttendQuizPageState extends AuthState { child: SizedBox( width: double.infinity, child: Column( - children: [ - Container( - color: colors.surfaceVariant, - child: Row( - children: [ - Expanded( - child: Text( - "Dein Alias: ${_alias}", - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - ), - ], - ), - ), + children: [ + const SizedBox(height: 32), Padding( - padding: - const EdgeInsets.only(left: 16.0, top: 4.0, right: 16.0), - child: Column( - children: [ - const SizedBox(height: 16), - Text(element.name, - style: const TextStyle( - fontSize: 25, fontWeight: FontWeight.w700)), - Text(element.description, - style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.w500), - textAlign: TextAlign.center), - const SizedBox(height: 16), - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: element.type == QuestionType.single_choice - ? SingleChoiceQuiz( - correctAnswers: _correctAnswers, - currentQuestionFinished: - _form!.currentQuestionFinished, - voted: _voted, - value: _value, - options: element.options, - onSelectionChanged: (newValue) { - setState(() { - _value = newValue; - }); - }, - ) - : element.type == QuestionType.yes_no - ? YesNoQuiz( + padding: const EdgeInsets.all(16), + child: Container( + constraints: const BoxConstraints(maxWidth: 800), + child: Column( + children: [ + Text(element.name, + style: const TextStyle( + fontSize: 25, + fontWeight: FontWeight.w700)), + Text(element.description, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500), + textAlign: TextAlign.center), + const SizedBox(height: 16), + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: element.type == + QuestionType.single_choice + ? SingleChoiceQuiz( correctAnswers: _correctAnswers, currentQuestionFinished: _form!.currentQuestionFinished, voted: _voted, value: _value, + options: element.options, onSelectionChanged: (newValue) { setState(() { _value = newValue; }); }, ) - : Text(element.type.toString()), - ), + : element.type == QuestionType.yes_no + ? YesNoQuiz( + correctAnswers: _correctAnswers, + currentQuestionFinished: _form! + .currentQuestionFinished, + voted: _voted, + value: _value, + onSelectionChanged: (newValue) { + setState(() { + _value = newValue; + }); + }, + ) + : Text(element.type.toString()), + ), + ), + ], ), - ], - ), - ), + )), if (!_form!.currentQuestionFinished && _voted) Container( margin: const EdgeInsets.only( @@ -738,6 +728,24 @@ class _AttendQuizPageState extends AuthState { const SizedBox(height: 20), ], ))), + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + color: colors.surfaceVariant, + child: Row( + children: [ + Expanded( + child: Text( + "Dein Alias: ${_alias}", + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + ), + ), + ], + ), + )), ]), ); } else { From b06a5467c587d8fb9e81ba48ff21a686ad1aa531 Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 10 Jun 2024 09:42:09 +0200 Subject: [PATCH 24/25] Live Tab fix auto refresh --- frontend/lib/tabs/live_tab.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/lib/tabs/live_tab.dart b/frontend/lib/tabs/live_tab.dart index f5ae425..da7132c 100644 --- a/frontend/lib/tabs/live_tab.dart +++ b/frontend/lib/tabs/live_tab.dart @@ -67,10 +67,10 @@ class _LiveTabState extends State { _fetchResult = ''; }); // fetch forms every 5 seconds - Timer.periodic(const Duration(seconds: 5), (timer) { + Timer.periodic(const Duration(seconds: 1), (timer) { if (!mounted) { timer.cancel(); - } else { + } else if (ModalRoute.of(context)!.isCurrent) { fetchForms(); } }); From e9eee2f2012ef39591e283ad918151645158cef5 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:56:54 +0200 Subject: [PATCH 25/25] disconnect log --- .../mobilelearning/services/quiz/socket/LiveQuizSocket.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java index 2489c1b..00b8253 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java @@ -201,6 +201,7 @@ private void sendMessageToUser(User user, LiveQuizSocketMessage message) { @OnClose public void onClose(Session session, @PathParam("courseId") String courseId, @PathParam("formId") String formId, @PathParam("userId") String userId) { + log(String.format("User %s disconnected", userId)); connections.remove(session.getId()); }