From d17646a6e916f671a799bbdf554f38c0eb6796fa Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Thu, 16 Feb 2017 20:21:57 +0300 Subject: [PATCH 01/48] https://github.com/status-im/status-react/issues/585 --- .re-natal | 1 + .../main/res/drawable-hdpi/icon_add_blue.png | Bin 0 -> 353 bytes .../main/res/drawable-hdpi/icon_back_dark.png | Bin 0 -> 450 bytes .../main/res/drawable-hdpi/icon_check_on.png | Bin 0 -> 316 bytes .../res/drawable-hdpi/icon_hamburger_dark.png | Bin 0 -> 335 bytes .../res/drawable-hdpi/icon_options_dark.png | Bin 0 -> 292 bytes .../res/drawable-hdpi/icon_options_gray.png | Bin 0 -> 295 bytes .../res/drawable-hdpi/icon_search_dark.png | Bin 0 -> 888 bytes .../main/res/drawable-mdpi/icon_add_blue.png | Bin 0 -> 179 bytes .../main/res/drawable-mdpi/icon_back_dark.png | Bin 0 -> 387 bytes .../main/res/drawable-mdpi/icon_check_on.png | Bin 0 -> 223 bytes .../res/drawable-mdpi/icon_hamburger_dark.png | Bin 0 -> 184 bytes .../res/drawable-mdpi/icon_options_dark.png | Bin 0 -> 171 bytes .../res/drawable-mdpi/icon_options_gray.png | Bin 0 -> 179 bytes .../res/drawable-mdpi/icon_search_dark.png | Bin 0 -> 555 bytes .../main/res/drawable-xhdpi/icon_add_blue.png | Bin 0 -> 354 bytes .../res/drawable-xhdpi/icon_back_dark.png | Bin 0 -> 573 bytes .../main/res/drawable-xhdpi/icon_check_on.png | Bin 0 -> 385 bytes .../drawable-xhdpi/icon_hamburger_dark.png | Bin 0 -> 345 bytes .../res/drawable-xhdpi/icon_options_dark.png | Bin 0 -> 400 bytes .../res/drawable-xhdpi/icon_options_gray.png | Bin 0 -> 374 bytes .../res/drawable-xhdpi/icon_search_dark.png | Bin 0 -> 1185 bytes .../res/drawable-xxhdpi/icon_add_blue.png | Bin 0 -> 530 bytes .../res/drawable-xxhdpi/icon_back_dark.png | Bin 0 -> 772 bytes .../res/drawable-xxhdpi/icon_check_on.png | Bin 0 -> 552 bytes .../drawable-xxhdpi/icon_hamburger_dark.png | Bin 0 -> 575 bytes .../res/drawable-xxhdpi/icon_options_dark.png | Bin 0 -> 594 bytes .../res/drawable-xxhdpi/icon_options_gray.png | Bin 0 -> 568 bytes .../res/drawable-xxhdpi/icon_search_dark.png | Bin 0 -> 1749 bytes .../res/drawable-xxxhdpi/icon_add_blue.png | Bin 0 -> 762 bytes .../res/drawable-xxxhdpi/icon_back_dark.png | Bin 0 -> 991 bytes .../res/drawable-xxxhdpi/icon_check_on.png | Bin 0 -> 787 bytes .../drawable-xxxhdpi/icon_hamburger_dark.png | Bin 0 -> 814 bytes .../drawable-xxxhdpi/icon_options_dark.png | Bin 0 -> 856 bytes .../drawable-xxxhdpi/icon_options_gray.png | Bin 0 -> 780 bytes .../res/drawable-xxxhdpi/icon_search_dark.png | Bin 0 -> 2379 bytes images/icon_dots_horizontal_dark.png | Bin 0 -> 170 bytes .../icon_add_blue.imageset/Contents.json | 21 ++ .../icon_add_blue.imageset/icon_add_blue.png | Bin 0 -> 354 bytes .../icon_back_dark.imageset/Contents.json | 21 ++ .../icon_back_dark.png | Bin 0 -> 573 bytes .../icon_check_on.imageset/Contents.json | 21 ++ .../icon_check_on.imageset/icon_check_on.png | Bin 0 -> 385 bytes .../Contents.json | 21 ++ .../icon_hamburger_dark.png | Bin 0 -> 345 bytes .../icon_options_dark.imageset/Contents.json | 21 ++ .../icon_dots_horizontal_dark.png | Bin 0 -> 251 bytes .../icon_options_gray.imageset/Contents.json | 21 ++ .../icon_dots_horizontal_gray.png | Bin 0 -> 250 bytes .../icon_search_dark.imageset/Contents.json | 21 ++ .../icon_search_dark.png | Bin 0 -> 1185 bytes package.json | 1 + src/status_im/android/core.cljs | 38 ++-- src/status_im/android/platform.cljs | 22 +- .../chat/handlers/webview_bridge.cljs | 3 +- src/status_im/commands/handlers/loading.cljs | 29 ++- src/status_im/components/confirm_button.cljs | 10 + src/status_im/components/context_menu.cljs | 49 +++++ src/status_im/components/react.cljs | 2 +- src/status_im/components/styles.cljs | 44 +++- src/status_im/components/toolbar/actions.cljs | 23 ++- src/status_im/components/toolbar/styles.cljs | 45 ++--- src/status_im/components/toolbar/view.cljs | 20 +- src/status_im/contacts/handlers.cljs | 69 +++++-- src/status_im/contacts/screen.cljs | 191 ++++++++++-------- src/status_im/contacts/styles.cljs | 44 ++-- src/status_im/contacts/subs.cljs | 70 ++++--- src/status_im/contacts/views/contact.cljs | 37 ++-- .../contacts/views/contact_inner.cljs | 6 +- .../contacts/views/contact_list.cljs | 108 +++++----- src/status_im/data_store/chats.cljs | 6 +- src/status_im/data_store/contact_groups.cljs | 23 +++ .../data_store/realm/contact_groups.cljs | 26 +++ .../realm/schemas/account/core.cljs | 8 +- .../realm/schemas/account/v2/core.cljs | 2 +- .../schemas/account/v5/contact_group.cljs | 15 ++ .../realm/schemas/account/v5/core.cljs | 36 ++++ .../schemas/account/v5/group_contact.cljs | 8 + src/status_im/db.cljs | 1 + src/status_im/handlers.cljs | 1 + src/status_im/ios/core.cljs | 5 +- src/status_im/ios/platform.cljs | 29 ++- src/status_im/new_group/handlers.cljs | 96 ++++++++- src/status_im/new_group/screen_private.cljs | 74 ++++++- src/status_im/new_group/styles.cljs | 82 ++++++-- src/status_im/new_group/subs.cljs | 14 +- src/status_im/new_group/views/contact.cljs | 33 +-- .../new_group/views/contact_list.cljs | 38 ++++ src/status_im/participants/views/contact.cljs | 2 +- src/status_im/translations/en.cljs | 15 +- src/status_im/translations/ru.cljs | 6 + 91 files changed, 1114 insertions(+), 365 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_add_blue.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_back_dark.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_check_on.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_hamburger_dark.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_options_dark.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_options_gray.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_search_dark.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_add_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_back_dark.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_check_on.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_hamburger_dark.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_options_dark.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_options_gray.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_search_dark.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_add_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_back_dark.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_check_on.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_hamburger_dark.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_options_dark.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_options_gray.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_search_dark.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_add_blue.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_back_dark.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_check_on.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_hamburger_dark.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_options_dark.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_options_gray.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_search_dark.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_add_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_back_dark.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_check_on.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_hamburger_dark.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_options_dark.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_options_gray.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_search_dark.png create mode 100644 images/icon_dots_horizontal_dark.png create mode 100644 ios/StatusIm/Images.xcassets/icon_add_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_add_blue.imageset/icon_add_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_back_dark.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_back_dark.imageset/icon_back_dark.png create mode 100644 ios/StatusIm/Images.xcassets/icon_check_on.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_check_on.imageset/icon_check_on.png create mode 100644 ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/icon_hamburger_dark.png create mode 100644 ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_dots_horizontal_dark.png create mode 100644 ios/StatusIm/Images.xcassets/icon_options_gray.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_dots_horizontal_gray.png create mode 100644 ios/StatusIm/Images.xcassets/icon_search_dark.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_search_dark.imageset/icon_search_dark.png create mode 100644 src/status_im/components/confirm_button.cljs create mode 100644 src/status_im/components/context_menu.cljs create mode 100644 src/status_im/data_store/contact_groups.cljs create mode 100644 src/status_im/data_store/realm/contact_groups.cljs create mode 100644 src/status_im/data_store/realm/schemas/account/v5/contact_group.cljs create mode 100644 src/status_im/data_store/realm/schemas/account/v5/core.cljs create mode 100644 src/status_im/data_store/realm/schemas/account/v5/group_contact.cljs create mode 100644 src/status_im/new_group/views/contact_list.cljs diff --git a/.re-natal b/.re-natal index ad994fe623..8f9b7f3b7c 100644 --- a/.re-natal +++ b/.re-natal @@ -25,6 +25,7 @@ "identicon.js", "react-native-fs", "react-native-dialogs", + "react-native-popup-menu", "react-native-image-resizer", "react-native-image-crop-picker", "react-native-webview-bridge", diff --git a/android/app/src/main/res/drawable-hdpi/icon_add_blue.png b/android/app/src/main/res/drawable-hdpi/icon_add_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..bc625c7666aaae42b28406f40b17b0b6756b1bfe GIT binary patch literal 353 zcmV-n0iOPeP)Px$8%ab#R9Fe^RY4BIAP@xVCp7V<@6dOsC-tg{FR;GAM6c>eeTV+Tn~A;x5E>xV z1gKz46Ss#l-LT7a76ydi0R=#TKT`mw{x9boPqxp2th1jr&lqE#QnQhgEOQGolpYn9 z!%4nk9}=6W^9ZF~jS=S^gCjvQA$wiISn?M5Dj}O(ECxa$kg$f5&)oturFceQFB(DRr zh>cC~GvGDGDy58hipimSs!BbW0}6lwf2Y6;3Vl+54lE^I00000NkvXXu0mjf2z`=e literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_back_dark.png b/android/app/src/main/res/drawable-hdpi/icon_back_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..82558dfb9d0fe6d738e972f39d0d640ffef4c565 GIT binary patch literal 450 zcmV;z0X_bSP)Px$d`Uz>R9Fe^mAy*DKoG}w_E7LRNo8RpC|4pKJ=Kn`Lf$l*t0 zOzZg`HdeldU=GZf5!M)TA^SCjkZopnGy9+4{$VFV^rLs6cRPz=k z7(NX)w^y!<`BysL+1q`8d(BK#!6dmWmta2d`2htU|KtLEj>J}wW%0c0tokn1#5Fcx zO2P8B6B8I>@Z!)S7zuDS%kIxjFX{~B6UNyg-!M)<95B{ETrgHZoG`{f+%N>B-G|~h zmbIowhb^Br6>b~azmCz`#$h4wLJ4uekhZo%1;CPmp;(|8BBFC2`>RQFZJ=3t`&c&i zX(fQset2@@8_MX0RGc7$z^DR)=}UHZ1^`&?+0TrCs0=rhF%UPD6%Z$sH4qn+6A%ZK zGmvj6?LI_>+Xg*(disq%b#!{!cBXCLi$hAh*%BZhuLnVrB)Q7zie4O2MSh)fH_HO&U91pyrT_o{07*qoM6N<$g4{gBH2?qr literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_check_on.png b/android/app/src/main/res/drawable-hdpi/icon_check_on.png new file mode 100644 index 0000000000000000000000000000000000000000..d8318e7fcb15d7fe9b2cdfea6b7c439efa370283 GIT binary patch literal 316 zcmV-C0mJ@@P)Px#_DMuRR5%gslB)^=Q4oe#@xp?Lh(+AuOBjt-t3`v!VzL;_MzdfxSWJS^Xc3#q z>Jtcp;AQ=e?7(Q&D#{T#$k{K?`5bOc5S$U#F`?fB#t@a!U66u zhPW2ccY_`287saSt$EfAJ-C9zj3Q~4O$lLu)ptPl@MaM%1&6 zx}DM_KAPh`B%)r5yV1;QHGfFP>!PgUCjg7cTbb4?Jea1 O0000Px$2}wjjR9Fe^mcb5!Fbsy*Y4kzVck!Uniy_eiKAI$GLcD17;Jb(qf(fmwTwn=B z1#jJftn29hexszu=uiSmKnW;;3IV8Cp0NzVQHFRkWX7KBHxo=cw03$*qDNf-Tj${Q zEXQSMVmP2n>>ZQmHA56M?AeoXS=GGz{W25cm^zfe9|?$MPed?ZZP#dN(xkx!O0P+@ z2LNi?EBX79lf~o)V}sJJ!pACRLC8j2to-&A%bqNW1pOlc+tJ~8;(>f+F6)iUzVT0O z5$>1c?$Gwi{3O*@0^br4Kk81}j}KaovS_jFJ83^$%ke~7ln<5WqM%ON4@YQV;Vg+z hpAt|4NPx#-bqA3R9Fe^R5=d9Fc7p+M8zxkQ`&qZR4C#pY4fMNf{Mmq8Os)#_*&6KlWH@& zo*j+Xs}w&vKnMQofR@nr{d9hs^`Vp*9FLwa`g&iM>D9{HwH~zRzGB9}Va5+;e{TV+ zi%xarzt!HE7)Mx~Psc(*Y4Vn=P>`OtO%b-O+CxM$WCz&IjK3x~)O*c{AJPFX#@w|E zpS^!waT|oi`E)E4lqPS<3I(Ahh_G^LT#V&ju@XDL#fW_gsPNgNC5W)lFc%30<>>44 qLP2N=BCK2(7h}0stfT`6ao`ODqgh8Dg5&W30000|k1|%Oc%$NbB7>k44ofy`glX(de^K@|xiQs%2 zV$FBRfG1a=sWI5#yPfP#x0w(pomEW$ z1J|GM#z~s?=ht8Uz1hZF(|lEM_FTQ^uahNylthRU*WmPaQV!Ks~-dMO=| z`?D)Wn0IpBX+ObDUG9H0oo)$TG2l1UaqExjxGHiW=}O4Nh*vkWy#o%XIAc@O%CtM+ a0lQOkiN%w=>7Rj~W$<+Mb6Mw<&;$T{)Oy_j literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_search_dark.png b/android/app/src/main/res/drawable-hdpi/icon_search_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..68be50ff4071a80c6d400e49b815bf5115f8a79b GIT binary patch literal 888 zcmV-;1Bd*HP)Px&GD$>1R9Fe^R?kaRaS)&RKGy<6?4|`_QBn$~Mn(Mrm9CnXb&2Ao9a5xj5uGZ8 zE*-i=5%j|)6Os)tsi&+%r-(?Q3^lAMLa0MOq(kn$Y3AAYwXJ^Ndu#1&-(hEVetf1qv0&Zv`+cJP~0_ytCOMCq_VfkZ>I#EFjQ(035TF8n{20cp4VZ6c>t6 z>mj>#Aw@TUV5bR4>w7j+4spW&d(P}s4;FgfOuq~TT7t1cymSBY722USLTkFMpOxD7;fw6DD!MN zD8>p&&os5$PxNczicBk2)IL0TYhpS4XzXaK15Q83mx`Z(uZ-U7Ke1e_pUpBkpS^n5 z!lX{Qey)tAiuRevNX*RS#8g#H!yEv${m!YcuHA8S>c#W#?*EWK##biO^alek`jOFb zqsc^qEBV0vPZUX~Qj6qtKnQ6hL;!nregv$3tp`a&@cPM7!Z#Ow%ej z@LDGXNrh@k$H=bIdRS>BBuh^~WVFl69~XrMbPyssmaF_z>tUsl(BcMOgn2Xfb$eJq za;RR%GR6n3hm}S`JiZS#h(mBv>wYp8J73I%j(ahv#ymZwVkBf)me-tocO8*E6NLGL zX3z0Uu8}ximS5IJN=Jfnvi-(AH2re?V^wusEhlV~BtnYHo|%~(AI}Dn%51FO(93;y zhJEg`le5o&4*+t-)ZEgrXU@BI}7y|0VxbD}U}xG!|UkA!NE(On}GMEl0~iv-Ju` zYD&T#tL*{D*zelRI?lMOwc@Ae-~Rv2263(#lT5xJT)~>5*mqKOr4Ey-tBeM*5AGkCiCxvXPx$JxN4CR7eeDU>F4iLV%foJWlEV|Nk=r0n32{2mawy1e9RJCy7fgC?-wv`;Q+x zfSNhYbd)q28X9m~Lb3&5!+(C?&+wl?oq>_@`1aL{tZ+F5B+i0Q5?v12aA5FUVCQ7; zMOTB)C)x*C40l<-Xwh4A1JU_JSwODgAj=3^K#Ac5EuhqJkOfR20vGuH^ZQ0nYJo;5 zQDKg57G4X0A@~iX;s1XIR+jI~1k|D%4dLU}#KFN82DIcV&Wmq7|_j1yiK790)m^j+}4eS(gF4$~tygV+E6$2(Yw zxEl5_PcdM7WFF9}@XA`?_kkxHFFCN@a`+?CVb8qLIL!4$lS8YF!Pgg&ebxsLQ008$-5&!@I literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_hamburger_dark.png b/android/app/src/main/res/drawable-mdpi/icon_hamburger_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c36b03f6707e3b6f101a5c4d0d301ccdd05a4702 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|iacE$Lp*qs z6C_v{D>`Iy7$g}V&^F0C{r~^}y&F$H6iQA>xw9+xtCD<4rCLd2pxs?(hHRDUwqv=e zKmOn6UY#u=xji?2Z^sK3hawf`*e~*{k1lR{(#CMjLrqov@u`Cb?1{Z82|7tzC6;AQ fk>h3j)yBZEv09RA8G}O^&~^q-S3j3^P6Px$xsf~?T3DyByD+NI- z(Lx~-3qROcX=ml9vPdH-1VKc^PqH`eTs%1LcB5!v<2E-t@6EiuHv{m0{@MZ5Js_9M z8Ryra0f)A&+xhutySG)e=s=a&Urw~+`QRtO>b>2 zJ%-iNd+w7An2$E+{6T)R1ZXUBOem^czGzNdpgK^f zt2fRxHDDt87!vaEYo3^ZWDBnF-mIjy((?k$=W2Nphzam2a)A)RO zpW7nXbG8L7yI3i|o=B@YzY?h_5D2NhnTeT}?}+?ZfJMI}65ArxYjrvHo@c-|v0bA4 tQiyVYCBV%B5oyIKAwER~{_lV9zz4Xmxwe^!{J{VK002ovPDHLkV1lJ@`0fAz literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_add_blue.png b/android/app/src/main/res/drawable-xhdpi/icon_add_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..2fcfcb6e06db9f0463a43cacf0e8246c8409abf9 GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^TMZ}qR+nwP`>yPp7%Qx9m)iN2$@1iH z`NTW_XDb=yD7aP@@|p;wr|f3pyYZ=a_2EVf<=dhK2d3r6#M*NIytz!0|HQksx2B!W zb1m96^`~*1-NavFS?tEIAJv|m^uOJ~mHic)NYrMXK=TQmGMzVWhW|YMQF{N@$}8s^ z!Zt*gub5M^@qgWvot}DInG+4YyDlEMlXrm8!eAmp-oj1>_560`!yJbb@?P)Px$_en%SRA>e5n7>QIKorN{C7_~RROluyfZOJIYQ^RpRuLobRGz?#y(#bVXZqiwj6wE5-l**?R=nbnM_sx;HRo}mT z6YZ(&7f2FM2)qNV^+d&Eo)Ulw;zNtTvF~4mGYv3FJXmC}*|=+^5s$g?vzWF}QvPq^ zTlHEqDTg~qDDrU1yh+kM)A1M?#Z3)jpLx4+GT&sA569xcE=f~W!=@6F2VwrEn0c>*49+^R; zkW#P-(EBa7ydT9>Ty4=NPn~vmqfqQJh+S4AGQz?=#-D?BN3=Fio-hD5L6N#4QUS~Y zL}~!t5K;hiLP!J91tAqc2ZVG0)exBgsD#K2Kovx$0Mj5g3&r3uXa{&sbj8!8Xo0`x z;f#c{63$Ff4gvC!&sq6uwfY&wc(2h6!<)x_{=u)+DUhQd10c{`zi%&c7aK`X27o;g z!UA%D&a*A!v98kmGd;qg_SW;fh3&($Wwl*RH{*bDz&KzWNO0gAb_^A9@G;6L00000 LNkvXXu0mjfDJ}Wy literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_check_on.png b/android/app/src/main/res/drawable-xhdpi/icon_check_on.png new file mode 100644 index 0000000000000000000000000000000000000000..ef90004718a55bd97f08af51b3daef9f066d793e GIT binary patch literal 385 zcmV-{0e=38P)Px$J4r-AR7ef&lRryBVHAf&1i`_%#l;4xC2Ej#5T|Inv;}QJn}g8US7?o($*nb4 zTm1s9Elo8PBq)Rub$brf<#c%8dllbFJn-Q8^E9`C&g62I(-7uI7|o3N zC-t${oT1!u&nx&Hpg93C(=nxpyt@pqmAXe>aEa-kft*2yoaw-&PkIQ(dV~B9iiv=P zx@$C2%3e$BoH?Sts7(y0OR~V{g_%kD4t1xYZ6Yj#{KaiZ@6tA@Ut!1kq}D8y;2yH# z8NpVnnQzEq5nSi`d-RE<>f4{Ik3j)$!Nwzv%3LN{B8>8Iqh5F*-^kiqc#dfkBKY@{ fUD#;7kamF|u2&&PlaXVv00000NkvXXu0mjff;p~e literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_hamburger_dark.png b/android/app/src/main/res/drawable-xhdpi/icon_hamburger_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..7ac556cc2d2818be2c381976a7f40cb05462fb3e GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^T=_`%UVp-4xl4iee9Z3=XjvFJf1^uA$hrHt4js*93v{(bE6xR({D6l;WJg z07ZZF8C~7ii=U2qw@LWDdWO%W`LBGrZkjE3ZayO3aryG{ufN}%jaFn%+3IkZok6(n zHn04GE4??qKHC=Hyfx;z-r+wg4ooT^B$*1m{s_&`+O$Qxc~jiEf{Ir8i{r^)Au)Snz)vvv=ao gOpp^`Xd;W;z2~-KUqx3R0frTWr>mdKI;Vst0FWk%g#Z8m literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_options_dark.png b/android/app/src/main/res/drawable-xhdpi/icon_options_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..af7dfd34ee1286fcbb9474eba63510c9d31c8bdf GIT binary patch literal 400 zcmV;B0dM|^P)Px$N=ZaPRA>e5m_G`_FciiUh1Ra(B6tSH!QC_H=;|3fglBNo(a8gN0zn+SfU|=L zYN6JoP|${^r2U-w38KxHm-oJ3`sYz0_#pujAORAnGXePz^OM=U_k4xRSj1z!z7%rb z^1a1&y}F?D!42r*A7OYDaoqkXR?2JOc>}bG#!nK!fhKPhuh&(E5)F{!dkMIK^tAa- zlK!`8=^WQzxB=G!s?LWS&=+i8Q8q0vrf3{)K;LbIx?qjOYAn$Vq1r&RTDTc~J{@lT z;b;>@@2*li>U&q@cY*Is(RUy-J4Z;MegxpHght3-$l*kSKL^+gIndWr;XB}%zw&gr z0b9Rg)5X%{Z=8t;Z-_o znT)pgGq#}Zia!sfX{N5dYLs}hX=me=)S&H&&o;+=e`i%)vLN+Zp%hD9bHh)Ki5n8c zW_^5UkiU3FYuW|>=(F<=ocYtey&7m#DAXte?x~5+jEn+592hoVkl^|!E+zc4DF2_c z+D|Rj<;ygWpPJO(SY*b2^sqy~t1Bi?BO;B=8zNWmNOOU`$-t4qa&O(sGS?pqzcK;? OlEKr}&t;ucLK6UhOPC1& literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_search_dark.png b/android/app/src/main/res/drawable-xhdpi/icon_search_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..0fbc32de6cefff533454c1b2a7e625509586b140 GIT binary patch literal 1185 zcmV;S1YY}zP)Px(TS-JgRA>e5SY2pTR}h}LcatbqDSZ(O5`P*6jiSB?BKY7-P17LQShW~ah2+H- zUju6J!55*A+Jeo``jDCxDr*uc{nMBBDKsi>#k9~s6r`va3I6Qnjx)R7yXVB+J?GwC zQ1D&|cV^Daob%1jnVB1a_=zJBM<9+s9D(;a0$2_B)&reQUe?IiIG(5`$yI6Q^__GfVTD{pXBJ}X#!}k%K!f-&~C@u?8TK_kfPi-wF|bLB~0O=q?*eCF_@ew6FnPT+5D+0ph=!KEWa{ zN0(Z@>{z48t6;2BD4+B2^0pdzM0kwg92`vzj+WcMtE;PS`qA?q0y@b$%3gSLYxAnj zy}i9&Ia^z~YooY&UGuk`0vml@IlP;2w~bsJ{L`0}dXJBfdy|5+MeiK_ zpDU$JQB$WH7QhKkq8VSxY1Q=k{zL11KI+>DK$?{19G!lRw`6`yCLbbUT2;?wJ>9pu zXi1v^5UkLA5&o|6AsBQ(vvm+xgfK6uY6gI?OtH+34);G$_>d&sQw=zcRNv~7HEjmK zvyI}-?e6YQD111QoCe)M^Q|vgaz+3$m?^$+`pNT^3LlOnZJ8_pMdicLgrM0vj_x~*FJIRPKt^I;S>7JvQR%R%%!cMsWCJ(jU=HFD#B<&HvR&N9 zr|1{~$UM*Wdp2-Lv|7f4fVUt7FoAcLI2uKDx|SX~UqwMEcruO>nap3$)~?&MfV=UI z;^weJ#siyC;PpJz$Ni*Lu?H9NtGk&S)2b{A%_(kv+72IHoSVtsVi1k0wu}eTVWml_ za-Wv8k;ntlc3+l%BmQ(Xm8`mni7zVvqS&^-W24OTJnb(MK6rRMkPcgDQe5YyRC2W` zTv*(xr_F0C#4Mn*_v-M#<-kuw!Ww}1myZ#d=eYrW7;(R%S&cv_m#XNy95wR8;IH7q zR{r6_e-?7u@CQyd@J&?5ztr%qy`Acq9W2`tp#X@}v5U#O@-f0+U|%EPWTlOyRPyxt z8(-LM`JCspsWpgDDOBpPG7`&FDT7&Iw&8!PaEFy9C3Sv&smw>5BhMGR*h{KNr>X&z z0%elb5`?i2m<|(V{h!+tcbb|v-(uT6{O6xR-g`tY>$ZMD3CvTLU1Gs0E0( zatG%BjOFfxi?n-W_`=wHeU%SgMpffl(fN*CqQrWH=S+LN69D9pB|#J~cv&3p3;-X5 zqz&iw6!X&#QdilN#|v=;;t0eMh$9e3fFtk<_ZXB)_(O_|00000NkvXXu0mjf53@gK literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_add_blue.png b/android/app/src/main/res/drawable-xxhdpi/icon_add_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..e339e0df067b44c2934e03bd2678552d51e55a17 GIT binary patch literal 530 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D%z&v?2xhEy=V zz3J$8$U)@T$C<|}I@Bt3rt9r#)PCi5ajJEGf|7T?swe-$rb0H2l_`_@zbt*r@;^u8 zbH@GI^8J%+<~(j>VB%0{Kp|qLH0URquU=oUH}iJ5__p$u^B$}|KYLeQ+}&UEcfQ^| zYj?wx|GRVJmCk*N@V;SIsJpkuX5HD6fU{G+`$xV1HurM;nYCXZ2g`~xiZreEH=h%2 zU3*?+eK*6bq{Ys~3@T3;m^?T-3}jg*2nZxvaVRJ%94ZlTaB^sQsnF2Uz;W4;fs;|t z%va>HiUIHLOK+A<`RKAe{(Y=;%+_swYQDlp56>u(+_j3U>Rx@qZMADNW-XA6n)Oz$ zWQHQYuieSYV^X;eliysJal|^f`F2CiRPx%zDYzuRCodH+r4WPK@YKmWNaDLGaEx;WhF=e{s}e zhQXNmquTq0Ox$6BG|)gCi(qfF{`ADt?({n~e1%ip?(+l@x!bkQ}G;wV6q>e4f<^oOF2aza7@ilXMPg^N@7M*#`7 zCJna{+)i*}icS+C0%jP7#m}vx!5-qMK(K!9Na#S^k-PwLM)C&470D|QMj~( z;)GNg5ErCMfjA&l4n!S^1Q2B;GC)+3NC8nqA_qhb38fwcn;fP=>7z_NX|H=24l_@g zu_RAWy6`fklJPToZoAbwNXNMDNuHo|lVwg)9IM&%dW@bl5Nvo5lC4I5xq0>SR}7dm zC+a_C(n*HxJDtw)?WJ2=KYqp+>Px$;z>k7R9Fe^mdz_fQ5eSOPNMNqBucYjAsg9XBePLb7D^UuETpVREG%r4wcRX~ zKS0@8SlCczLsq0@LlT9g2>CXCN3*!ykN2Kix1+dkJVt8O-j5 zFwbzkrowb%_9TRPfa}r@Lvs(902%F}LL)PM;05^A9YlwgE{#dB=1^K;U7{mE-w=3n z%-feYELwH6etKx`w@=%yH@Gg7gy2Vj`o;K_dVn@d8ZM53X+Jggw?Unt9#44W}mf0+d)KEtZ(@vmn|MpsBk<^(F(_`s2V_r?K q`a`8&H!aJ`>CVP|@d^Cv6Zi&LvU6z$h$v(L0000eu%^MXEGgq&g27%5mHCkq7e-VI&$@hThGG7@MeSuAGND4b@rk!w*=!?HPo!_I3a2pdV5)iSC~;`XmgFCu20^Y zt>5+Bb6um3ys0{=`udqRi+}?IBZRmm8t``MCLQbhHFan2Onb9&>t)$@BJB~8zoyU7 zyrsNq?XhQ%tKY?~-Zfcx)%E+k+*9h`q=n4by8q_Z?d~D7uTFW}7qKVB+y~aSW+o zd^^k5kJ(V5^=$xy`+_CU#5%aFxH1-*{Fx%d;V9h7q_UuitB`?p9pi+y&oaz`zGvh7*WVD|gB_j~#L#ZwMt^*Q!DEK980SZ`=mbN1`@!u8kPCdBaE zwDc`_V$Sp~+W2Plf^0q!^E7gw%k(A9QKpO$E~FMuURb% zWoKT(pW?kpZf&YfKO5VL$tpqI%qs3XOCQOtE%jN=$L8@$CVLWuT~>3-aQ{Zr9Y5Ey zUE=i6Eh#mNaTe{_AgdxgO(}puqvvKAx2uTEN%n2cB5v2?O-=l_L4En*KgWj|`fDUb z1Z0o4U0t~N27~*q7aC#=l`&5J+XSxN<*knVx}!yI?QDmK>;?|4d#o<=GCwKgw7qpJ zC9%OqZ=rj%w7?p^MT;XMysWxd9d7x$2YPN$WfW2XqQ+Y+39XC#mb^Z012o?CuG-9L zeMxMmzUW$YT{bbAZwu5toAc}PXp7yCpZh||Ze h2@I&np_*kMLt?s&SJs^=F~CH^;OXk;vd$@?2>{Ts;CcW6 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_options_gray.png b/android/app/src/main/res/drawable-xxhdpi/icon_options_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..41b7456e34ee949aca436c55f62b12b2cfe1c8ab GIT binary patch literal 568 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D%zKY6-1hEy=V zy?m^VqvT`NH(NG*V)%B@X>SuJ%av=wnjD@{2io)l-2XAy8sXVnGwbzF59+#p`S<1tmoj@Y{eP`q zc3t4{)fZ1*7=`toeqQqPu4sl$-Hl&7@sqoj#P5G$ahqrF!Gek(f%os%y>|QUe5GH( z-_N*j&h%eF%3HsNXYSv6{hz>B<(&8L=7%$gf8EQy*804D{`>9bmzTF*>)W@(*74Kq z;5}~MxgT9mbKPzD#9wsMM0cy|_03myFh;7qjC{>zQa@FE-JPK5ij$9w%oT1v7dd|^ zD7xn2Ca3M!pVu^7?5zG%%|At4Abs({kB!&cF23cQ#ClrIpvB^}$o_tNX;*!jnfBSuY5XhC(}d?vpcdvN7-avDg}l#c!-E9czb263~e(l-~D&C z`S~j^S z_^?tvFz3KTJ)p7 ti!0z=-1q%bmGfi-k)wo>WtZ>|Hg6|h$GxJGH-Slk!PC{xWt~$(698(!?>7Jd literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_search_dark.png b/android/app/src/main/res/drawable-xxhdpi/icon_search_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..85ba66b31b690ec9caac5c01f5810dc28a8f1ccc GIT binary patch literal 1749 zcmV;`1}gc9P)Px*k4Z#9RCodHn_X-aRTO~lo!$P>V)%(6Qlbwni3+H}AD&1|nP$zT zduDg;?450v+1O+XXS1T+CnKoigeGyzRO6VL?mO@RCD za8Ki#56_$CZf2U#GtMg*6BUB-_24(bnV1%WPjiD!2+jsJu3I(K+S+>0@0eul`vNEu zi3CS}pL~mPc0dU6jN5=X;-oO4qM z)*j^Scz-N9<<*XgdCCBV!|#>foV^|uOw_3e3~j)QN*J8IF%XNMS7lSyjuJq%p{7TY zO!UF8{*-J0F7zQi@s9>$Z6{!52^acGRdNQj2!~yST=S6I$T(-Spj!+;1Fq*Vw|PEm^%P9&0ZvXSF3ON>@|_1IA7m{}kf5 znkg2+%!4n5n%>T&vznpz=T(o# zVv#v&T(!*8BZm7N>s3xiBLK?2!C1Seq}tp0#b3d-rQ0D-4N>MHOIP0Ee;%a9{E&G9 zWNiW+_Bpt6;<0E)F2VMnKAqr2E9>DsKSA0N=CR%T_dh_6DHeJHB)DiH%}0%?lt}}!s&Xm<&cC9> zxyt%FqrU?DD`|EFE5DX-UkInocPWqu#MlPPHaCjCq2x+r2LG0_1K`M5C|$2IX+ZD} zhn`OQXLYb_DqX5Z0$G~0%}tYxMUB@*E7E{qT3XG8wbhw3t+!MLX1B#nx(qQHPm9Gq zPsOztKncQeaVXT~y6`0CXBHW}j8ZVTpkkp^J}E&CEu-EDp&Pgn1Xzi zuwARlhm##?Ku$s3y*IbT$w{tqc!WvYu;A8A0=xfLAE(4mQ=R;@-4N=p;$^7{aylA0LctcQ}T zmPrG`0Px%j5~R5_80-XMv#YkHg?ue9)z9>OS3|fO4j4~RI@l}nqwb@8c>-h|>T&TU zWe_`o$(h;yn%54kp~tgJ5sqo{PB;jl;)6739La7)jRqBfE6V}FkKwr$r3@?S1#|xP zNOfcQS!&!#hB>Du6#l>zydQeqbVJNw9dHEni<1r2a;W#be|CkM>XSlrfdwZ!0{c1G zvcRg`$&+>HXuYji#3|>b=E9HCvu#V|UTFI+q-1{nb-FRvKC2s=BCyl_Fxv!hbcI1x z4gjXC+6u}C+#%y85M(>3SGki-nA5#&b5&zLAmt1Q@&vC5HJ`$BE2kUsL!K{4o^w#@ zrm@9pop^G77-V@__UIe(+$$rampk!6JwV~9(!`@kIWR?AyCh6FxyRH z{_21wj^)HAo7{f6Y5MP(&967q^$ZUWr)@jzie9gCUO{%pc;bnNdfYJHfk)tmeN5&W z<_;O$c<$@2_I;RZ@NsgQ@Apc|IR`lfj^|c*G=rxP*kFf}q1;Iq3TCdE!5HoHvDt{TFa#;QD9;fatgj!vG1(mcD*dr~tC`%5=`o3=f;f-g51Z9u( z6LVhy$_k0IHrW*}%G4xd`ds*aD14JVf)Chb!b&;&FA rO+XXS1T+CnKoigeGyzS(J%RrKoA{2Y+CnDn00000NkvXXu0mjfGWJH- literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_add_blue.png b/android/app/src/main/res/drawable-xxxhdpi/icon_add_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..f80af67d19915416bb5d360418f52021d34e33d8 GIT binary patch literal 762 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>VA|s8;uuoF z`1a1htYAlxV;^UF%uZXqE~l3DH^;ZgBdvKX;%}X=v_5bXzqE9pTMbJs>*~BKxwFKo z<_hboh%!H|xnAu5gPm(<%(F9R-X~w;wp=0-$Dz=`z=WTetrcLL_vYj3%X?3sez&9S z>49tauNvKz^XI#7v-h{^?Yc{>AD(>uez$w`&E@N++}6Ia_1_J-_ixg<6Sr*YWDytt zeDh=ck8SVP?N0tKl#`g+`I0GPwSC0RgO^;dPi^;}u6b`6_X5TH(aO7bKf9-pzmz*+ zLRX)wU<0$i;S>guu0AQ22M29Fv{3P%P$o1+0t0UB0W0%R%O zyJe|Pl>3_Mhu^0^dAVv??+N>+bI&)6&u+_qaIHJ#ZiQFPYE}LRt6~H8UQoR9IywInLmR`@+fu7! zS>AffHJF~tnr<;C%lChCmFXu2x5ZT{|2JIW=3T!%(>+$W~ z_WcE~O#ff6+Qxp{JAUr(XV16dA5VV%4XK_qzhNKqjV-@e1m5AP^Yp667R~HSxDV`_;{E#K&Ua~hJ-Vx}=kxrr zieV4mse;uuoF z_;!wMhKQp`LwcE6y2`;HmnC#Wa*o8YupV?X)Li4|GC^RAfVFhCHfyw_^iBy?!-onF z5}7=+mnuZ8SkRgzyfILySnQ+OW1o~AN0V>fojiBu_h-4rhu^%}xAXn&oww)K$|P?Q zWK?os>0l64U~*~T5WvP+F^6HjO_Ms~tFO}5xBvV$)O`Aaq5J-pS-t#rJh~i=$>M5$ znjbFvoN{Kfdj996fb_n5Irr`x%;uR9WH;Cws#$6D`7fyAY3?Msp<8IttWP?i>#7=81%t1el2I=*7lC4Y>Ad}sSi&b zdM;@Fx2En_aVoP`MUqIl?7RelNqD4|~M~m}>G_TbS;9Gb$eZ?&py4VXu&YQcXTf z3)g*aM#aPBdI}{!{8$BQdhcJ9Hf;JYzE7C(`RmE<=8>PGR8R4hwNDHTUa4$VeQ>(? z3(3WQ)~CJhjO6+!+jPG)Ew{`2RLMvo183%-7NXs-6CSj)Ix z_xmGWho;SEEdG8~nw%1OSFra<*Mpq7-9OG;x^v|;P_LDR@B+(;Ebjh?UUr+5aQdY; z2nudu(PwG-Q~IR0Awac4Rl$Yx9w&!y({v`MNe|XG1gKQ#DzI?g<36Cr*uro|=m5t7 zt%JXcwy@oNzbxE&r$BnQeyaNEs+o)LSD5uNn=(swusML6@nUWdqX& z4+dR^W|j|33%nf^88)$)F#Vbsko@S#=4V%`YuBviy;AHTx1{JiXHm-JQn{ydH^2J3 zBCVk@^qH9HDqfkmIk`1P$8YHco@HQOf5qplvgx?_b3){ZT6N=QjH{zI$F?r|rLq73 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_check_on.png b/android/app/src/main/res/drawable-xxxhdpi/icon_check_on.png new file mode 100644 index 0000000000000000000000000000000000000000..780956a86bdbd9a523069fae3187faf30e3fc920 GIT binary patch literal 787 zcmV+u1MK{XP)Px%%}GQ-RA>e5m_bMtQ51%qGz=4?gb*T;kQPacsD)A+!Hv-(G$Ck_D?JmlH<^HHU zca}<+*$ZZhOqRMGut>U_#^pXBKa-l+f^@~5J4+?ZG=e7@=Wu?2%N9v@)0k-j&w(bs zL+W$q&Qb|8&0tyM9L_gz&LZh<8Z)in4ba3FNL}vSSt?=X7jhPeR zBhbV;q*LzPSt?(XJ_$|nLP73W*9~Ob*Tf2>mWYTp!Qy)*syt+FzgA0l@O!{! z3C-}-3vLdTqaWcS@G7im7(XR=eq&u8n6&*1@ z0Dda8gz^X+h^i#WAoM^K74aHQtEmL}tBUo1DRT@OOgf2jh#diPaMr|oNNwRl++Wu$ z+~!Pit^C0p(bGV7KuyR;?)PTH^`>UQHfMrsZTR6UI!62?(0m`nk38(S43r^UIX0#n z6lnwUF{xyXAXc5O^N>2l%6V(FJ?IdGf?YpUD!m~^<-Pr-&7Ecbc6tsK%9xXr)1t*> z-1H4aiS#MBle6pNIF~W`Yw0^HqXH%yfaztg*#8!Z!7`-XQ888rWD|-DdH?Bm=O{rX z4Az1%!xP9Zej$P6KP^f8(}r33r{Fwj0*hdXgNPhReE1Id4)_lE4*WkI_yy>0Nah1P RNhbgR002ovPDHLkV1kT=V~hX* literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_hamburger_dark.png b/android/app/src/main/res/drawable-xxxhdpi/icon_hamburger_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..8f50831927aae5a41f3bd73f6e0c406f2fd045a1 GIT binary patch literal 814 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>V0z){;uuoF z`1bbstYAlx;~!@(@qBxzwO(vnEn{GYK;hk8;^JZlr*hw4SlRK5t4V1~N7I70%uDnY zL|Y$4<(mI%%-hnt^RZ;<)n3K#=Emkvs};MQ-dP&YpZq1R=v`qSGb4+D0|QZn-|Pne zjSHj8-|L5+TO0l6slcJ6E}5H2Rr~Wjnx_^2eJk#7zxwkjZh?>P2ltlh#RTYY%dmOB z|7_{*z0;-p?KH0^wqBJBE#UW;tyAH8_~-oM$3NCill#QPA|AFxJ11a+NcCj#1&(pQ zmR87LaeT`9;T->!?i??h$M*x*yT&ybZ@#;4GxxNrg-;*JtuC(k znU#OItKekZN52EKoy8{)pXLr&rT%8`?|Yf&zbsqJ@u|*X<-7upcXtZE zdf(eTwf>1e%M@{iitRN@?)&UlH|kIB(M)2G{CCrP+ZCmaoxwI5@8$_dkF1O}xW_j55dGU>5RpaSW+o ze0ytQzKEm9@sBg(npZk281lBM@iu*6SMU&!n8d|1V^-9^rhlv+1~ZZrLWG=}6#j4v ztWa2K+3j$3O5Ad5Z+(;LdsE8lcW=(uyKj8`_PN*Rtzhbs4r zJ4IwWeY-b*w?JI(kF(F)+kY?j&0UkLt;A@$&-$N8)9(39FZTZ4^w3Ox+Ju&4%9^Q@ zEN>rCwimU37oHP6U)QpH)8mL|=Nl@{&Y#=*{1VR~?vqRR=l-=m_(xJ;f5GiX z$Cn(L@#}O|WLr;;`TT~{yXWS`{C_uP*U_}DP4gT6Z=V(G@of9b*rd%zrc7wi5lH3@ za$;J>)F-6PGg~gpp7E-1-mem|D6Ng$vAka|)-XN#p(owZ=zxq|}A}Cw|?Ub^2o1 z+?y!jF5%a}zVTts5Is^UuSU8^Sk%zxEn)U40v9(!St$Gh_&_sq_m_pDxcoy?S5a;j$D zTwWdyVjUaVG(nDWC&4k{xt6=aWvrZWrAS~>oy;WeI5RvU;N5mcU{+!9boFyt=akR{ E0KKVd(EtDd literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_options_gray.png b/android/app/src/main/res/drawable-xxxhdpi/icon_options_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..f1535c3f3e61a1ef4bc2a0de17d6ad9c9760181b GIT binary patch literal 780 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>U^?dM;uuoF z_;!w=-(d#<*S(5NobMVgDHn2Zv50#(x;i?ac6=eg%PPt$&Jg%Sz~iOzI|d<+q%t8L z!3h(~-EYk`)$e_KB>r(_z3lDT>qA8KIUE?61R5Av6c`w>Fn{?Sn0oEO*Ry~9OzZ7e zYHxqPsw%qg{(AeLU)!?`_E_0j&6sv2*pThcJ-_Sm_tKu1#?G%g&@6VM`1zfu&wjng zvAI{7ee?L0+pZD{ALhrWm)EU%U%L3YTD0`y!$Lk8(w=vJ`D~fq^XJ`%rwd-~U8;7G zQR~zUd*&zB`~Owcf3a=jo3=Ar`d!q1wHC9bAFP62>F*Hyu=Iw5-nEILlTV(JRw%dL zXkv2f#;k=_pV>^d&sx}f@}E?$&t8e%O6H_lTAs=G7%ES6v97v!>>AJ2ndS)}TcmGY zy$)28ax!6NC38yE!E#gncRnWGxh*DhkL+PAlGne?z0kuY`LCoyl~I0!%#t&2e^k%v zTvJ}X^JLKF-1l>;MH3s&ygYHIPyVX7+_m_4cO%L2z*9C8B=YOD9zB2Y=61=K^Z#zN zp@ily{|5GrXXM0_8Fnt{QErV1aQhK73rI4bU`=h=ui>kwv7UKWPQTmiRoS2IPh@Pe zmC|KfqBLP=-%n$Q$!{-a1piFB$KbooeeuzTHlPu0F7s4(F0i>1zG@P8)WL~$%`pL0 z&(?~bWZk;xAu~!0E)ZZkdL&3{UTw92_A!Pc$Fl-wHmHbCVf^)d(vzlrmp%6Q>1h~# zh<|#5^{>;UFT5Zte6OZ(+Mm+@H_M2PW9I^itp7gA|9CE>RGZuid3<0GBgmQEjJ%9R zj=Y^V-bId;JJyG&if?IB{>!#=!Iv}9+TU`mc5Mx`!$+#a PgTe~DWM4ffcr%o literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_search_dark.png b/android/app/src/main/res/drawable-xxxhdpi/icon_search_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..8a24c2fb54f9cca6b37b761500ee72148857237b GIT binary patch literal 2379 zcma)8>pK&S1Krk&iJEIzv53uGY9d4oL#~QkFn2bikB6Cl!<+2nqGPhqL zx6lls$V;w`Tq3Xhynn#&d43+NI_@>T?~m#Ff|a!pv#Dw!+oje zV+#}PptL|piHaDChL$zqg?RX9yb~7^GHWZ;ZIWviD**+TQav!6JZHNr&2#bU-NkT+ z5|z@o5xPFlyxvaf{0idM61S~?4Pjm5PH>`1=$ zZfgI%a2Hk}7`o$1kPiE-5x~nYIcOmR)4BB>URF^npPXM;T{iDkD}h__&#hSY=|15? zv^y%@&M@j8Me<#<*x1uBJrS+Nx^4a3ZSKc#9skK+;)x5s5(fLxd_)nKAcd7SS_Np@ z#~Wb^8?IyuK|@hE$$=SYIP1)&jlZb0vNp4J6XSC>F~2Y}tiERl))|I0#@;bE>Rh^f zz1I%p4SsmV-Sx(c;LG;q1mx}A~_da3%&TQCELa zj*qb5zp6vD)cm*LO2i<&c~2X1RQ##1(`-UrnDbPO&sI2xb!$}mM%4@G`2F}C%5Y9< z?|_9{u$y15juS3)slnEHoGDlHVwFGOAdQnme;$r1KhdB@{B9;(W8Y`{Yzyle6Yn*g zaBJ>$G2!b4YXP@M3`K3wXX$~By7&R}spR4FRlO{EGUs|&X&H3|q3?FC!Ns9bDGX{osQ+-YVyOExZBilI4}^Ry$5%E8 zx%9*+6MLjf&!-%7Y5=reC5n1uFf5Ya9KLXR94=#2}W!P>VA|>c_seC4?_? z>V2vC$QH#VF#RJxZ4z?W*&|X%GSef)IyfoWj~b}vAPT*SojvZM%fP4C&qJtkmVQoM zk#Mz_%+>_v z(A>?(Fe#`0P5dCH;*ybas#qBPd%uM|NVLUOdX+(_bN+l)?UiPZR(V_fOJU8TtJMU_ z&L_buU)QmtPk|Z8N)$%XRLxKEeTZ>*0PTe2kuH6^?fdDrNZ0KvhTrPBk$@it zt(!*cnoV0%7lB^PlLn-9;}^1)S*+=IaG#HAC66L#Ott7SrPxRd-YhNo4V^rQ4?3=l zE!cAtI&xmA*jX%b?OxN6Ho4w=?{x)>P|lugzMuEJhXR8U>TI_`M+d7V4RQkv z#2H@i4!u!_%oVkQ=t}ijRYZ2*BMl30fJF2`m!PR}T%myTBa_OI^t;CPYFG)@ZbBQ6 z%|7rirp8E1Kc^uXph1Z~9UHS2Aiq->EH!tRo7~)i6>mjN=~wSQ(!K4|jN7yTHRx!k;^(fD9#byvuurrB8a|6tXrCAc?-(zQ+o_IC?-yk9O^e z>rj^|P*yE;7wK*^ckIdfsU`mPwyx{URLXQzyN#QaY`YkUmzsC<;e($Xho9yq;-JnC z=29~4oAS@&VJdPG%IXsIOzFBMro+H402{a;?fvJQ@@N3_>#IO;+Mf{8r~VI~4_c{a zcCbk)-v@v64DSb8*nA`V^eHKNUE3GwdgJio^$(S5S4GpIo?e+0%T$b@=s64Y?i}L2>Qb zais8PG)=k6_C*MiOTSX%!hJAy6LD2*j8vGnW7U|Gp(@_%^q&%io{7ZL6#Tz4Qb?G{ zRxhHPt%(4Mk5{llO#(nPKt= z`8#b#w0*~AIu$I{E-GaBKe$mHJ=K`LHT-^IWQttW558wamY_Kp+zV&Tt_qOI6OS%r9No_KGU~;5DQX!r# zPtaphNa2dc8Db8qD_j$!7ne+_F&0_pGB|qL4k&OiGKl`yTIpzQW literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_add_blue.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_add_blue.imageset/Contents.json new file mode 100644 index 0000000000..db6aecbb67 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_add_blue.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_add_blue.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_add_blue.imageset/icon_add_blue.png b/ios/StatusIm/Images.xcassets/icon_add_blue.imageset/icon_add_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..2fcfcb6e06db9f0463a43cacf0e8246c8409abf9 GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^TMZ}qR+nwP`>yPp7%Qx9m)iN2$@1iH z`NTW_XDb=yD7aP@@|p;wr|f3pyYZ=a_2EVf<=dhK2d3r6#M*NIytz!0|HQksx2B!W zb1m96^`~*1-NavFS?tEIAJv|m^uOJ~mHic)NYrMXK=TQmGMzVWhW|YMQF{N@$}8s^ z!Zt*gub5M^@qgWvot}DInG+4YyDlEMlXrm8!eAmp-oj1>_560`!yJbb@?P)Px$_en%SRA>e5n7>QIKorN{C7_~RROluyfZOJIYQ^RpRuLobRGz?#y(#bVXZqiwj6wE5-l**?R=nbnM_sx;HRo}mT z6YZ(&7f2FM2)qNV^+d&Eo)Ulw;zNtTvF~4mGYv3FJXmC}*|=+^5s$g?vzWF}QvPq^ zTlHEqDTg~qDDrU1yh+kM)A1M?#Z3)jpLx4+GT&sA569xcE=f~W!=@6F2VwrEn0c>*49+^R; zkW#P-(EBa7ydT9>Ty4=NPn~vmqfqQJh+S4AGQz?=#-D?BN3=Fio-hD5L6N#4QUS~Y zL}~!t5K;hiLP!J91tAqc2ZVG0)exBgsD#K2Kovx$0Mj5g3&r3uXa{&sbj8!8Xo0`x z;f#c{63$Ff4gvC!&sq6uwfY&wc(2h6!<)x_{=u)+DUhQd10c{`zi%&c7aK`X27o;g z!UA%D&a*A!v98kmGd;qg_SW;fh3&($Wwl*RH{*bDz&KzWNO0gAb_^A9@G;6L00000 LNkvXXu0mjfDJ}Wy literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_check_on.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_check_on.imageset/Contents.json new file mode 100644 index 0000000000..a5f8b13cf1 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_check_on.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_check_on.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_check_on.imageset/icon_check_on.png b/ios/StatusIm/Images.xcassets/icon_check_on.imageset/icon_check_on.png new file mode 100644 index 0000000000000000000000000000000000000000..ef90004718a55bd97f08af51b3daef9f066d793e GIT binary patch literal 385 zcmV-{0e=38P)Px$J4r-AR7ef&lRryBVHAf&1i`_%#l;4xC2Ej#5T|Inv;}QJn}g8US7?o($*nb4 zTm1s9Elo8PBq)Rub$brf<#c%8dllbFJn-Q8^E9`C&g62I(-7uI7|o3N zC-t${oT1!u&nx&Hpg93C(=nxpyt@pqmAXe>aEa-kft*2yoaw-&PkIQ(dV~B9iiv=P zx@$C2%3e$BoH?Sts7(y0OR~V{g_%kD4t1xYZ6Yj#{KaiZ@6tA@Ut!1kq}D8y;2yH# z8NpVnnQzEq5nSi`d-RE<>f4{Ik3j)$!Nwzv%3LN{B8>8Iqh5F*-^kiqc#dfkBKY@{ fUD#;7kamF|u2&&PlaXVv00000NkvXXu0mjff;p~e literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/Contents.json new file mode 100644 index 0000000000..14c6ed1c54 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_hamburger_dark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/icon_hamburger_dark.png b/ios/StatusIm/Images.xcassets/icon_hamburger_dark.imageset/icon_hamburger_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..7ac556cc2d2818be2c381976a7f40cb05462fb3e GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^T=_`%UVp-4xl4iee9Z3=XjvFJf1^uA$hrHt4js*93v{(bE6xR({D6l;WJg z07ZZF8C~7ii=U2qw@LWDdWO%W`LBGrZkjE3ZayO3aryG{ufN}%jaFn%+3IkZok6(n zHn04GE4??qKHC=Hyfx;z-r+wg4ooT^B$*1m{s_&`+O$Qxc~jiEf{Ir8i{r^)Au)Snz)vvv=ao gOpp^`Xd;W;z2~-KUqx3R0frTWr>mdKI;Vst0FWk%g#Z8m literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json new file mode 100644 index 0000000000..b74610d665 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_dots_horizontal_dark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_dots_horizontal_dark.png b/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_dots_horizontal_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..846998d7558a3c4549955df6ced0e746b64e7a32 GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`Z1r?;42j@; zJIR)>*?^~2w#BND>)nx4rY}Mi`wq>rF6{D)y%e=FHMwq?#^uvO`mDbI-q$oz8m>RHn03#%0xd mg=i&LFJgmP$k2F-W#2jHNX|k1|%Oc%$NbB7>k44ofy`glX(f`Z1Hq)42j@; zJIRo**?`BDb5+6vk-63KZtEC@o%=6M{9W=+QzC)$XY*41)rnn3e|0wQugiIT)OWEm zlac}yg>tsUY|s5&_WNUXyMS6nQqTN__3Ix0uzKsO*?;x$-v=$pJd;0J@+N(nV{)XM zbE!=jfB9+7<8IIVw4XkdyV-an#P}Rv%iNF66=$D+s6PArzs()>-OdpSZ+dFExtt## mUuqK*ypf}$0g6J@3K)5fN~F^6Ft`ET&*16m=d#Wzp$Py9FkvVF literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_search_dark.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_search_dark.imageset/Contents.json new file mode 100644 index 0000000000..255462e697 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_search_dark.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_search_dark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_search_dark.imageset/icon_search_dark.png b/ios/StatusIm/Images.xcassets/icon_search_dark.imageset/icon_search_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..0fbc32de6cefff533454c1b2a7e625509586b140 GIT binary patch literal 1185 zcmV;S1YY}zP)Px(TS-JgRA>e5SY2pTR}h}LcatbqDSZ(O5`P*6jiSB?BKY7-P17LQShW~ah2+H- zUju6J!55*A+Jeo``jDCxDr*uc{nMBBDKsi>#k9~s6r`va3I6Qnjx)R7yXVB+J?GwC zQ1D&|cV^Daob%1jnVB1a_=zJBM<9+s9D(;a0$2_B)&reQUe?IiIG(5`$yI6Q^__GfVTD{pXBJ}X#!}k%K!f-&~C@u?8TK_kfPi-wF|bLB~0O=q?*eCF_@ew6FnPT+5D+0ph=!KEWa{ zN0(Z@>{z48t6;2BD4+B2^0pdzM0kwg92`vzj+WcMtE;PS`qA?q0y@b$%3gSLYxAnj zy}i9&Ia^z~YooY&UGuk`0vml@IlP;2w~bsJ{L`0}dXJBfdy|5+MeiK_ zpDU$JQB$WH7QhKkq8VSxY1Q=k{zL11KI+>DK$?{19G!lRw`6`yCLbbUT2;?wJ>9pu zXi1v^5UkLA5&o|6AsBQ(vvm+xgfK6uY6gI?OtH+34);G$_>d&sQw=zcRNv~7HEjmK zvyI}-?e6YQD111QoCe)M^Q|vgaz+3$m?^$+`pNT^3LlOnZJ8_pMdicLgrM0vj_x~*FJIRPKt^I;S>7JvQR%R%%!cMsWCJ(jU=HFD#B<&HvR&N9 zr|1{~$UM*Wdp2-Lv|7f4fVUt7FoAcLI2uKDx|SX~UqwMEcruO>nap3$)~?&MfV=UI z;^weJ#siyC;PpJz$Ni*Lu?H9NtGk&S)2b{A%_(kv+72IHoSVtsVi1k0wu}eTVWml_ za-Wv8k;ntlc3+l%BmQ(Xm8`mni7zVvqS&^-W24OTJnb(MK6rRMkPcgDQe5YyRC2W` zTv*(xr_F0C#4Mn*_v-M#<-kuw!Ww}1myZ#d=eYrW7;(R%S&cv_m#XNy95wR8;IH7q zR{r6_e-?7u@CQyd@J&?5ztr%qy`Acq9W2`tp#X@}v5U#O@-f0+U|%EPWTlOyRPyxt z8(-LM`JCspsWpgDDOBpPG7`&FDT7&Iw&8!PaEFy9C3Sv&smw>5BhMGR*h{KNr>X&z z0%elb5`?i2m<|(V{h!+tcbb|v-(uT6{O6xR-g`tY>$ZMD3CvTLU1Gs0E0( zatG%BjOFfxi?n-W_`=wHeU%SgMpffl(fN*CqQrWH=S+LN69D9pB|#J~cv&3p3;-X5 zqz&iw6!X&#QdilN#|v=;;t0eMh$9e3fFtk<_ZXB)_(O_|00000NkvXXu0mjf53@gK literal 0 HcmV?d00001 diff --git a/package.json b/package.json index de30bad5f3..b56cea2ea1 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "react-native-linear-gradient": "1.5.7", "react-native-network-info": "github:alwx/react-native-network-info", "react-native-orientation": "github:youennPennarun/react-native-orientation", + "react-native-popup-menu": "^0.7.1", "react-native-qrcode": "^0.2.2", "react-native-randombytes": "^2.1.0", "react-native-share": "1.0.17", diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 9fc2105c4f..5bfd5d6fc0 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -12,6 +12,7 @@ splash-screen http-bridge]] [status-im.components.main-tabs :refer [main-tabs]] + [status-im.components.context-menu :refer [menu-context]] [status-im.contacts.search-results :refer [contacts-search-results]] [status-im.contacts.views.contact-list :refer [contact-list]] [status-im.contacts.views.new-contact :refer [new-contact]] @@ -23,8 +24,9 @@ [status-im.accounts.screen :refer [accounts]] [status-im.transactions.screen :refer [confirm]] [status-im.chats-list.screen :refer [chats-list]] - [status-im.new-group.screen-private :refer [new-group]] [status-im.new-group.screen-public :refer [new-public-group]] + [status-im.new-group.screen-private :refer [new-group contact-group]];; TODO: confusion with names + [status-im.new-group.views.contact-list :refer [contact-group-list]] [status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.remove :refer [remove-participants]] [status-im.group-settings.screen :refer [group-settings]] @@ -33,7 +35,8 @@ status-im.data-store.core [taoensso.timbre :as log] [status-im.components.status :as status] - [status-im.chat.styles.screen :as st] + [status-im.components.styles :as st] + [status-im.chat.styles.screen :as chat-st] [status-im.accounts.views.qr-code :refer [qr-code-view]])) (defn init-back-button-handler! [] @@ -105,6 +108,8 @@ :chat-list main-tabs :new-group new-group :new-public-group new-public-group + :contact-group contact-group + :contact-group-list contact-group-list :group-settings group-settings :contact-list main-tabs :contact-list-search-results contacts-search-results @@ -118,21 +123,20 @@ :login login :recover recover :my-profile my-profile)] - [view - {:flex 1} - [component] - (when @modal-view - [view - st/chat-modal - [modal {:animation-type :slide - :transparent false - :on-request-close #(dispatch [:navigate-back])} - (let [component (case @modal-view - :qr-scanner qr-scanner - :qr-code-view qr-code-view - :confirm confirm - :contact-list-modal contact-list)] - [component])]])]))))}))) + [menu-context st/flex + [view st/flex + [component] + (when @modal-view + [view chat-st/chat-modal + [modal {:animation-type :slide + :transparent false + :on-request-close #(dispatch [:navigate-back])} + (let [component (case @modal-view + :qr-scanner qr-scanner + :qr-code-view qr-code-view + :confirm confirm + :contact-list-modal contact-list)] + [component])]])]]))))}))) (defn init [] (status/call-module status/init-jail) diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 7d565ad2d1..2875810d98 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -1,6 +1,5 @@ (ns status-im.android.platform - (:require [status-im.components.styles :as styles] - [status-im.components.toolbar.styles :refer [toolbar-background2]])) + (:require [status-im.components.styles :as styles])) (def component-styles {:status-bar {:default {:height 0 @@ -8,7 +7,7 @@ :color styles/color-white} :main {:height 0 :bar-style "dark-content" - :color toolbar-background2} + :color styles/color-white} :transparent {:height 20 :bar-style "light-content" :translucent? true @@ -34,8 +33,17 @@ :item {:status-text {:color styles/color-black :line-height 22 :font-size 14}}} - :contacts {:subtitle {:color styles/color-gray2 - :font-size 14}} + :contacts {:subtitle {:color styles/color-gray4 + :font-size 14} + :separator {:height 0} + :icon-check {:border-radius 2 + :width 17 + :height 17} + :group-header {:flexDirection :row + :alignItems :center + :height 56 + :padding-top 10 + :backgroundColor styles/color-light-gray}} :bottom-gradient {:height 3} :input-label {:left 4} :input-error-text {:margin-left 4} @@ -47,7 +55,8 @@ :toolbar-last-activity {:color styles/text2-color :background-color :transparent :top 0 - :font-size 12}}) + :font-size 12} + :toolbar-title-container {:padding-left 16}}) (def fonts {:light {:font-family "sans-serif-light"} @@ -56,7 +65,6 @@ :toolbar-title {:font-family "sans-serif"}}) - ;; Dialogs (def react-native-dialogs (js/require "react-native-dialogs")) diff --git a/src/status_im/chat/handlers/webview_bridge.cljs b/src/status_im/chat/handlers/webview_bridge.cljs index b9fcbb27f8..a26726a1b2 100644 --- a/src/status_im/chat/handlers/webview_bridge.cljs +++ b/src/status_im/chat/handlers/webview_bridge.cljs @@ -108,8 +108,7 @@ [db [_ _ {:keys [handler action params]}]] (assoc db :contacts-click-handler handler :contacts-click-action action - :contacts-click-params params - :contacts-filter #(not (nil? (:address %))))) + :contacts-click-params params)) (def qr-context {:toolbar-title (label :t/address)}) diff --git a/src/status_im/commands/handlers/loading.cljs b/src/status_im/commands/handlers/loading.cljs index f5c0da206c..be3341493d 100644 --- a/src/status_im/commands/handlers/loading.cljs +++ b/src/status_im/commands/handlers/loading.cljs @@ -9,8 +9,10 @@ [status-im.commands.utils :refer [reg-handler]] [status-im.constants :refer [console-chat-id wallet-chat-id]] [taoensso.timbre :as log] + [status-im.i18n :refer [label]] [status-im.utils.homoglyph :as h] - [status-im.utils.js-resources :as js-res])) + [status-im.utils.js-resources :as js-res] + [status-im.utils.random :as random])) (def commands-js "commands.js") @@ -164,3 +166,28 @@ (reg-handler ::clear-commands-callbacks (fn [db [chat-id]] (assoc-in db [::commands-callbacks chat-id] nil))) + +(reg-handler :load-default-contacts! + (u/side-effect! + (fn [{:keys [chats groups]}] + (let [default-contacts js-res/default-contacts + default-dapps-group-contacts (mapv #(hash-map :identity (clojure.core/name (first %))) + (filter #(true? (:dapp? (second %))) default-contacts))] + (doseq [[id {:keys [name photo-path public-key add-chat? + dapp? dapp-url dapp-hash]}] default-contacts] + (let [id' (clojure.core/name id)] + (when-not (chats id') + (when add-chat? + (dispatch [:add-chat id' {:name (:en name)}])) + (dispatch [:add-contacts [{:whisper-identity id' + :name (:en name) + :photo-path photo-path + :public-key public-key + :dapp? dapp? + :dapp-url (:en dapp-url) + :dapp-hash dapp-hash}]])))) + (dispatch [:add-groups [{:group-id "dapps" + :name (label :t/contacts-group-dapps) + :order 0 + :timestamp (random/timestamp) + :contacts default-dapps-group-contacts}]]))))) diff --git a/src/status_im/components/confirm_button.cljs b/src/status_im/components/confirm_button.cljs new file mode 100644 index 0000000000..799d82b36d --- /dev/null +++ b/src/status_im/components/confirm_button.cljs @@ -0,0 +1,10 @@ +(ns status-im.components.confirm-button + (:require [status-im.components.styles :as st] + [status-im.components.react :refer [view + text + touchable-highlight]])) + +(defn confirm-button [label on-press] + [touchable-highlight {:on-press on-press} + [view st/confirm-button + [text {:style st/confirm-button-label} label]]]) \ No newline at end of file diff --git a/src/status_im/components/context_menu.cljs b/src/status_im/components/context_menu.cljs new file mode 100644 index 0000000000..293eedad60 --- /dev/null +++ b/src/status_im/components/context_menu.cljs @@ -0,0 +1,49 @@ +(ns status-im.components.context-menu + (:require [reagent.core :as r] + [status-im.components.styles :as st] + [status-im.i18n :refer [label]] + [status-im.utils.platform :refer [platform-specific ios?]] + [re-frame.core :refer [dispatch]] + [status-im.components.react :refer [view touchable-highlight]])) + +(def react-native-popup-menu (js/require "react-native-popup-menu")) + +(defn get-property [name] + (aget react-native-popup-menu name)) + +(defn adapt-class [class] + (when class + (r/adapt-react-class class))) + +(defn get-class [name] + (adapt-class (get-property name))) + +(def menu (get-class "Menu")) +(def menu-context (get-class "MenuContext")) +(def menu-trigger (get-class "MenuTrigger")) +(def menu-options (get-class "MenuOptions")) +(def menu-option (get-class "MenuOption")) + +(def list-selection-fn (:list-selection-fn platform-specific)) + +(defn open-ios-menu [options] + (list-selection-fn {:options (mapv :text options) + :callback (fn [index] + (when (< index (count options)) + (when-let [handler (:value (nth options index))] + (handler)))) + :cancel-text (label :t/cancel)}) + nil) + +(defn context-menu [trigger options] + (if ios? + [touchable-highlight + {:on-press #(open-ios-menu options)} + [view + trigger]] + [menu {:onSelect #(when % (do (%) nil))} + [menu-trigger trigger] + [menu-options st/context-menu + (for [option options] + ^{:key option} + [menu-option option])]])) \ No newline at end of file diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index 2feb470712..c7ec58bc17 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -85,7 +85,7 @@ (assoc :style (merge style font))))])) (defn icon - ([n] (icon n {})) + ([n] (icon n st/icon-default)) ([n style] [image {:source {:uri (keyword (str "icon_" (name n)))} :style style}])) diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index b6df42eaf0..f0df443e8e 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -8,11 +8,16 @@ (def color-gray "#838c93de") (def color-gray2 "#8f838c93") (def color-gray3 "#00000040") +(def color-gray4 "#939ba1") +(def color-gray5 "#d9dae1") (def color-steel "#838b91") (def color-white "white") -(def color-light-blue-transparent "#bbc4cb32") +(def color-light-blue "#628fe3") +(def color-light-blue2 "#eff3fc") (def color-light-gray "#EEF2F5") (def color-red "red") +(def color-light-red "#e86363") + (def color-separator "#D6D6D6") (def text1-color color-black) @@ -23,15 +28,16 @@ (def new-messages-count-color color-blue-transparent) (def chat-background color-light-gray) (def selected-message-color "#E4E9ED") -(def separator-color "#0000001f") +(def selected-contact-color color-light-blue2) +(def separator-color color-gray4) (def default-chat-color color-purple) (def flex {:flex 1}) (def icon-search - {:width 17 - :height 17}) + {:width 24 + :height 24}) (def create-icon {:fontSize 20 @@ -39,8 +45,12 @@ :color :white}) (def icon-back - {:width 8 - :height 14}) + {:width 24 + :height 24}) + +(def icon-default + {:width 24 + :height 24}) (def icon-add {:width 14 @@ -78,3 +88,25 @@ (def button-input {:flex 1 :flexDirection :column}) + +(def confirm-button + {:flex-direction :row + :height 52 + :justify-content :center + :align-items :center + :background-color color-light-blue}) + +(def confirm-button-label + {:color color-white + :font-size 17 + :line-height 20 + :letter-spacing -0.2}) + +(def context-menu + {:customStyles {:optionsContainer {:padding-top 8 + :padding-bottom 8} + :optionWrapper {:padding-left 16 + :justify-content :center + :height 48} + :text {:font-size 15 + :line-height 20}}}) diff --git a/src/status_im/components/toolbar/actions.cljs b/src/status_im/components/toolbar/actions.cljs index d38c3bcf39..ecf66d40e1 100644 --- a/src/status_im/components/toolbar/actions.cljs +++ b/src/status_im/components/toolbar/actions.cljs @@ -3,29 +3,34 @@ (def nothing {:image {:source nil - :style st/action-search}}) + :style st/action-default}}) (defn hamburger [handler] - {:image {:source {:uri :icon_hamburger} - :style st/action-hamburger} + {:image {:source {:uri :icon_hamburger_dark} + :style st/action-default} :handler handler}) (defn add [handler] {:image {:source {:uri :icon_add} - :style st/action-add} + :style st/action-default} + :handler handler}) + +(defn opts [handler] + {:image {:source {:uri :icon_options_dark} + :style st/action-default} :handler handler}) (defn search [handler] - {:image {:source {:uri :icon_search} - :style st/action-search} + {:image {:source {:uri :icon_search_dark} + :style st/action-default} :handler handler}) (defn back [handler] - {:image {:source {:uri :icon_back} - :style st/action-back} + {:image {:source {:uri :icon_back_dark} + :style st/action-default} :handler handler}) (defn back-white [handler] {:image {:source {:uri :icon_back_white} - :style st/action-back} + :style st/action-default} :handler handler}) diff --git a/src/status_im/components/toolbar/styles.cljs b/src/status_im/components/toolbar/styles.cljs index de800ccc25..eabc5fce60 100644 --- a/src/status_im/components/toolbar/styles.cljs +++ b/src/status_im/components/toolbar/styles.cljs @@ -2,15 +2,17 @@ (:require [status-im.components.styles :refer [text1-color color-white color-light-gray + color-gray5 color-blue - color-black]])) + color-black]] + [status-im.utils.platform :as p])) (def toolbar-background1 color-white) (def toolbar-background2 color-light-gray) (def toolbar-height 56) -(def toolbar-icon-width 32) -(def toolbar-icon-spacing 8) +(def toolbar-icon-width 24) +(def toolbar-icon-spacing 24) (def toolbar-gradient {:height 4}) @@ -23,6 +25,11 @@ {:flex-direction :row :height toolbar-height}) +(def toolbar-line + {:height 1 + :background-color color-gray5 + :opacity 0.4}) + (defn toolbar-nav-actions-container [actions] {:width (when (and actions (> (count actions) 0)) (-> (+ toolbar-icon-width toolbar-icon-spacing) @@ -38,9 +45,9 @@ :padding-right 12}) (def toolbar-title-container - {:flex 1 - :alignItems :center - :justifyContent :center}) + (merge (get-in p/platform-specific [:component-styles :toolbar-title-container]) + {:flex 1 + :justifyContent :center})) (def toolbar-title-text {:margin-top 0 @@ -61,12 +68,11 @@ :justify-content :center}) (def toolbar-with-search - {:background-color toolbar-background2 + {:background-color toolbar-background1 :elevation 0}) (def toolbar-with-search-content {:flex 1 - :align-items :center :justify-content :center}) (def toolbar-search-input @@ -79,25 +85,8 @@ (def toolbar-with-search-title {:color color-black - :align-self :center - :text-align :center :font-size 16}) - -;; Specific actions - -(def action-hamburger - {:width 16 - :height 12}) - -(def action-add - {:width 17 - :height 17}) - -(def action-search - {:width 17 - :height 17}) - -(def action-back - {:width 8 - :height 14}) +(def action-default + {:width 24 + :height 24}) diff --git a/src/status_im/components/toolbar/view.cljs b/src/status_im/components/toolbar/view.cljs index bb6778bec2..9210c9c735 100644 --- a/src/status_im/components/toolbar/view.cljs +++ b/src/status_im/components/toolbar/view.cljs @@ -7,7 +7,7 @@ image touchable-highlight]] [status-im.components.sync-state.gradient :refer [sync-state-gradient-view]] - [status-im.components.styles :refer [icon-back + [status-im.components.styles :refer [icon-default icon-search]] [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :as st] @@ -34,8 +34,8 @@ [touchable-highlight {:on-press #(dispatch [:navigate-back]) :accessibility-label id/toolbar-back-button} [view (get-in platform-specific [:component-styles :toolbar-nav-action]) - [image {:source {:uri :icon_back} - :style icon-back}]]]))] + [image {:source {:uri :icon_back_dark} + :style icon-default}]]]))] (or custom-content [view {:style st/toolbar-title-container} [text {:style st/toolbar-title-text @@ -50,7 +50,8 @@ [view st/toolbar-action [image action-image]]]) custom-action)]] - [sync-state-gradient-view]])) + [sync-state-gradient-view] + [view st/toolbar-line]])) (defn- toolbar-search-submit [on-search-submit] (let [text @(subscribe [:get-in [:toolbar-search :text]])] @@ -67,10 +68,7 @@ {:style st/toolbar-search-input :auto-focus true :placeholder search-placeholder - :return-key-type "search" - :on-blur #(dispatch [:set-in [:toolbar-search :show] nil]) - :on-change-text #(dispatch [:set-in [:toolbar-search :text] %]) - :on-submit-editing #(toolbar-search-submit on-search-submit)}] + :on-change-text #(dispatch [:set-in [:toolbar-search :text] %])}] [view [text {:style st/toolbar-with-search-title :font :toolbar-title} @@ -83,9 +81,11 @@ style on-search-submit] :as opts}] - (let [toggle-search-fn #(dispatch [:set-in [:toolbar-search :show] %]) + (let [toggle-search-fn #(do + (dispatch [:set-in [:toolbar-search :show] %]) + (dispatch [:set-in [:toolbar-search :text] ""])) actions (if-not show-search? - (into actions [(act/search #(toggle-search-fn search-key))]))] + (into [(act/search #(toggle-search-fn search-key))] actions))] [toolbar {:style (merge st/toolbar-with-search style) :nav-action (if show-search? (act/back #(toggle-search-fn nil)) diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index 5e26ad9ddf..5a6284e9e0 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -17,12 +17,24 @@ [status-im.utils.js-resources :as js-res])) (defmethod nav/preload-data! :group-contacts + [db [_ _ group show-search?]] + (-> db + (assoc :contacts-group group) + (update :toolbar-search assoc + :show (when show-search? :contact-list) + :text ""))) + +(defmethod nav/preload-data! :contact-group [db [_ _ group]] - (dissoc - (if group - (assoc db :contacts-group group) - db) - :contacts-filter)) + (if group + (-> db + (assoc :contact-group group + :selected-contacts (into #{} (map :identity (:contacts group))) + :new-chat-name (:name group)) + (update :toolbar-search assoc + :show :contact-list + :text "")) + db)) (defmethod nav/preload-data! :new-group [db _] @@ -34,8 +46,7 @@ [db [_ _ click-handler]] (-> db (assoc-in [:toolbar-search :show] nil) - (assoc :contacts-click-handler click-handler - :contacts-filter nil))) + (assoc :contacts-click-handler click-handler))) (register-handler :remove-contacts-click-handler (fn [db] @@ -167,16 +178,15 @@ (defn save-contacts! [{:keys [new-contacts]} _] (contacts/save-all new-contacts)) -(defn update-pending-status [old-contacts {:keys [whisper-identity pending] :as contact}] - (let [{old-pending :pending - :as old-contact} (get old-contacts whisper-identity)] - (if old-contact - (assoc contact :pending (and old-pending pending)) - (assoc contact :pending pending)))) +(defn update-pending-status [old-contacts {:keys [whisper-identity pending?] :as contact}] + (let [{old-pending :pending? + :as old-contact} (get old-contacts whisper-identity) + pending?' (if old-contact (and old-pending pending?) pending?)] + (assoc contact :pending? (boolean pending?')))) (defn add-new-contacts [{:keys [contacts] :as db} [_ new-contacts]] - (let [identities (set (map :whisper-identity contacts)) + (let [identities (set (keys contacts)) new-contacts' (->> new-contacts (map #(update-pending-status contacts %)) (remove #(identities (:whisper-identity %))) @@ -243,9 +253,9 @@ (register-handler :add-pending-contact (u/side-effect! (fn [{:keys [chats contacts]} [_ chat-id]] - (let [contact (if-let [contact-info (get-in chats [chat-id :contact-info])] - (read-string contact-info) - (assoc (get contacts chat-id) :pending false)) + (let [contact (if-let [contact-info (get-in chats [chat-id :contact-info])] + (read-string contact-info) + (assoc (get contacts chat-id) :pending? false)) contact' (assoc contact :address (public-key->address chat-id))] (dispatch [::prepare-contact contact']) (dispatch [:watch-contact contact']) @@ -283,6 +293,8 @@ (let [{{:keys [public private]} :keypair timestamp :timestamp} payload prev-last-updated (get-in db [:contacts from :keys-last-updated])] + + (when (<= prev-last-updated timestamp) (let [contact {:whisper-identity from :public-key public @@ -305,9 +317,19 @@ (after stop-watching-contact) (u/side-effect! (fn [_ [_ {:keys [whisper-identity] :as contact}]] - (dispatch [:update-contact! (assoc contact :pending true)]) + (dispatch [:update-contact! (assoc contact :pending? true)]) (dispatch [:account-update-keys])))) +(defn remove-contact-from-group [whisper-identity] + (fn [contacts] + (remove #(= whisper-identity (:identity %)) contacts))) + +(register-handler :remove-contact-from-group + (u/side-effect! + (fn [_ [_ {:keys [whisper-identity]} group]] + (let [group' (update group :contacts (remove-contact-from-group whisper-identity))] + (dispatch [:update-group group']))))) + (register-handler :remove-contact (fn [db [_ whisper-identity pred]] (if-let [contact (contacts/get-by-id whisper-identity)] @@ -329,3 +351,14 @@ 0 (dispatch [:hide-contact contact]) :default)) :cancel-text (label :t/cancel)})))) + +(register-handler + :open-contact-group-list + (after #(dispatch [:navigate-to :contact-group-list])) + (fn [db _] + (-> + (assoc db :contact-group nil + :selected-contacts #{} + :new-chat-name "") + (assoc-in [:toolbar-search :show] nil) + (assoc-in [:toolbar-search :text] "")))) diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index 7b83b460e7..f56dc110af 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -6,6 +6,7 @@ [status-im.components.react :refer [view text image + icon touchable-highlight linear-gradient scroll-view @@ -14,10 +15,12 @@ [status-im.components.action-button :refer [action-button action-button-item]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar-with-search]] + [status-im.components.toolbar.view :refer [toolbar-with-search toolbar]] [status-im.components.toolbar.actions :as act] + [status-im.components.toolbar.styles :as tst] [status-im.components.drawer.view :refer [open-drawer]] [status-im.components.icons.custom-icons :refer [ion-icon]] + [status-im.components.context-menu :refer [context-menu]] [status-im.contacts.views.contact :refer [contact-view]] [status-im.utils.platform :refer [platform-specific]] [status-im.i18n :refer [label]] @@ -25,30 +28,45 @@ [status-im.components.styles :refer [color-blue create-icon]])) -(def contacts-limit 50) +(def contacts-limit 5) -(defn toolbar-view [show-search?] - (let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?]) - actions (if new-contact? - [(act/add #(dispatch [:navigate-to :new-contact]))])] - (toolbar-with-search - {:show-search? show-search? - :search-key :contact-list - :title (label :t/contacts) - :search-placeholder (label :t/search-for) - :nav-action (act/hamburger open-drawer) - :actions actions - :on-search-submit (fn [text] - (when-not (str/blank? text) - (dispatch [:set :contacts-filter #(let [name (-> (or (:name %) "") - (str/lower-case)) - text (str/lower-case text)] - (not= (.indexOf name text) -1))]) - (dispatch [:set :contact-list-search-text text]) - (dispatch [:navigate-to :contact-list-search-results])))}))) +(def toolbar-options + [{:text (label :t/new-contact) :value #(dispatch [:navigate-to :new-contact])} + {:text (label :t/edit) :value #(dispatch [:set-in [:contacts-ui-props :edit?] true])} + {:text (label :t/new-group) :value #(dispatch [:open-contact-group-list])}]) -(defn subtitle-view [subtitle contacts-count] - [view st/contact-group-header-inner +(defn toolbar-actions [] + (let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?])] + [view st/toolbar-actions + [touchable-highlight + {:on-press #(dispatch [:navigate-to :group-contacts nil :show-search])} + [view st/search-btn + [icon :search_dark]]] + [view st/more-btn + [context-menu + [icon :options_dark] + (if new-contact? toolbar-options (rest toolbar-options))]]])) + +(defn toolbar-view [] + [toolbar {:style tst/toolbar-with-search + :title (label :t/contacts) + :nav-action (act/hamburger open-drawer) + :custom-action (toolbar-actions)}]) + +(defn toolbar-edit [] + [toolbar {:style tst/toolbar-with-search + :nav-action (act/back #(dispatch [:set-in [:contacts-ui-props :edit?] false])) + :title (label :t/edit-contacts)}]) + +(defn options-btn [group] + (let [options [{:value #(dispatch [:navigate-to :contact-group group]) :text (label :t/edit-group)}]] + [view st/more-btn + [context-menu + [icon :options_gray] + options]])) + +(defn subtitle-view [subtitle contacts-count group extended?] + [view (get-in platform-specific [:component-styles :contacts :group-header]) [text {:style (merge st/contact-group-subtitle (get-in platform-specific [:component-styles :contacts :subtitle])) :uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?]) @@ -58,7 +76,9 @@ (get-in platform-specific [:component-styles :contacts :subtitle])) :uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?]) :font :medium} - (str contacts-count)]]) + (str contacts-count)] + (when extended? + [options-btn group])]) (defn group-top-view [] [linear-gradient {:style st/contact-group-header-gradient-bottom @@ -68,37 +88,47 @@ [linear-gradient {:style st/contact-group-header-gradient-top :colors st/contact-group-header-gradient-top-colors}]) -(defn line-view [] - [view {:style {:background-color "#D7D7D7" - :height 1}}]) +(defn on-scroll-animation [e show-toolbar-shadow?] + (let [offset (.. e -nativeEvent -contentOffset -y)] + (reset! show-toolbar-shadow? (pos? offset)))) -(defn contact-group-view [contacts contacts-count subtitle group click-handler] - (let [shadows? (get-in platform-specific [:contacts :group-block-shadows?])] +(defn contact-group-form [{:keys [contacts contacts-count group edit? click-handler]}] + (let [shadows? (get-in platform-specific [:contacts :group-block-shadows?]) + subtitle (:name group)] [view st/contact-group - [view st/contact-group-header - [subtitle-view subtitle contacts-count]] - (if shadows? - [group-top-view] - [line-view]) + (when subtitle + [subtitle-view subtitle contacts-count group edit?]) + (when (and subtitle shadows?) + [group-top-view]) [view (doall (map (fn [contact] ^{:key contact} - [contact-view {:contact contact - :extended? true - :on-click click-handler - :more-on-click nil}]) + [contact-view + {:contact contact + :extended? edit? + :on-click (when-not edit? click-handler) + :extend-options (when group + [{:value #(dispatch [:hide-contact contact]) + :text (label :t/delete-contact)} + {:value #(dispatch [:remove-contact-from-group contact group]) + :text (label :t/remove-from-group)}])}]) contacts))] - (when (<= contacts-limit (count contacts)) + (when (< contacts-limit contacts-count) [view st/show-all - [touchable-highlight {:on-press #(dispatch [:navigate-to :group-contacts group])} + [touchable-highlight (when-not edit? {:on-press #(dispatch [:navigate-to :group-contacts group])}) [view [text {:style st/show-all-text :font :medium} - (label :t/show-all)]]]]) - (if shadows? - [group-bottom-view] - [line-view])])) + (str (- contacts-count contacts-limit) " " (label :t/more))]]]]) + (when shadows? + [group-bottom-view])])) + +(defview contact-group-view [{:keys [group] :as params}] + [contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit] + contacts-count [:all-added-group-contacts-count (:group-id group)]] + [contact-group-form (merge params {:contacts contacts + :contacts-count contacts-count})]) (defn contacts-action-button [] [action-button {:button-color color-blue @@ -113,44 +143,35 @@ [ion-icon {:name :md-create :style create-icon}]]]) -(defn contact-list [_] - (let [peoples (subscribe [:get-added-people-with-limit contacts-limit]) - dapps (subscribe [:get-added-dapps-with-limit contacts-limit]) - people-count (subscribe [:added-people-count]) - dapps-count (subscribe [:added-dapps-count]) - click-handler (subscribe [:get :contacts-click-handler]) - show-search (subscribe [:get-in [:toolbar-search :show]]) - show-toolbar-shadow? (r/atom false)] - (fn [current-view?] - [view st/contacts-list-container - [toolbar-view (and current-view? - (= @show-search :contact-list))] - [view {:style st/toolbar-shadow} - (when @show-toolbar-shadow? - [linear-gradient {:style st/contact-group-header-gradient-bottom - :colors st/contact-group-header-gradient-bottom-colors}])] - (if (pos? (+ @dapps-count @people-count)) - [scroll-view {:style st/contact-groups - :onScroll (fn [e] - (let [offset (.. e -nativeEvent -contentOffset -y)] - (reset! show-toolbar-shadow? - (<= st/contact-group-header-height offset))))} - (when (pos? @dapps-count) - [contact-group-view - @dapps - @dapps-count - (label :t/contacts-group-dapps) - :dapps - @click-handler]) - (when (pos? @people-count) - [contact-group-view - @peoples - @people-count - (label :t/contacts-group-people) - :people - @click-handler])] - [view st/empty-contact-groups - [react/icon :group_big st/empty-contacts-icon] - [text {:style st/empty-contacts-text} (label :t/no-contacts)]]) - (when (get-in platform-specific [:contacts :action-button?]) - [contacts-action-button])]))) +(defview contact-list [current-view?] + [contacts [:get-added-contacts-with-limit contacts-limit] + contacts-count [:added-contacts-count] + click-handler [:get :contacts-click-handler] + edit? [:get-in [:contacts-ui-props :edit?]] + groups [:all-added-groups] + show-toolbar-shadow? (r/atom false)] + [view st/contacts-list-container + (if edit? + [toolbar-edit] + [toolbar-view]) + (when @show-toolbar-shadow? + [linear-gradient {:style st/contact-group-header-gradient-bottom + :colors st/contact-group-header-gradient-bottom-colors}]) + (if (pos? (+ (count groups) contacts-count)) + [scroll-view {:style st/contact-groups + :onScroll #(on-scroll-animation % show-toolbar-shadow?)} + (when (pos? contacts-count) + [contact-group-form {:contacts contacts + :contacts-count contacts-count + :edit? edit? + :click-handler click-handler}]) + (for [group groups] + ^{:key group} + [contact-group-view {:group group + :edit? edit? + :click-handler click-handler}])] + [view st/empty-contact-groups + [react/icon :group_big st/empty-contacts-icon] + [text {:style st/empty-contacts-text} (label :t/no-contacts)]]) + (when (and (not edit?) (get-in platform-specific [:contacts :action-button?])) + [contacts-action-button])]) diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index c19c8440ed..b3841b33b2 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -6,7 +6,7 @@ color-separator color-gray2 color-gray]] - [status-im.components.toolbar.styles :refer [toolbar-background2]] + [status-im.components.toolbar.styles :refer [toolbar-background1 toolbar-background2]] [status-im.utils.platform :as p])) ;; Contacts list @@ -15,6 +15,9 @@ {:height 2 :background-color toolbar-background2}) +(def toolbar-actions + {:flex-direction :row}) + (def contact-groups {:flex 1 :background-color toolbar-background2}) @@ -43,22 +46,13 @@ (def contact-group {:flex-direction :column}) -(def contact-group-header - {:flex-direction :column - :background-color toolbar-background2}) - -(def contact-group-header-inner - {:flexDirection :row - :alignItems :center - :height 48 - :backgroundColor toolbar-background2}) - (def contact-group-subtitle - {:flex 1 - :margin-left 16}) + {:margin-left 16}) (def contact-group-count - {:margin-right 14}) + {:flex 1 + :margin-left 8 + :opacity 0.6}) (def contact-group-header-gradient-top {:flexDirection :row @@ -79,9 +73,6 @@ ["rgba(24, 52, 76, 0.01)" "rgba(24, 52, 76, 0.05)"]) -(def contact-group-header-height (+ (:height contact-group-header-inner) - (:height contact-group-header-gradient-bottom))) - (def show-all {:flexDirection :row :alignItems :center @@ -95,6 +86,9 @@ ;; ios only: :letterSpacing 0.5}) +(def contact-separator-container + {:background-color color-white}) + (def contact-container {:flex-direction :row :background-color color-white}) @@ -129,8 +123,8 @@ (def option-inner-image {:width 24 :height 18 - :top 16 - :left 13}) + :top 16 + :left 13}) (def group-icon (assoc option-inner-image @@ -167,14 +161,18 @@ :color text2-color}) (def more-btn - {:width 56 + {:width 24 :height 56 + :margin-right 14 :alignItems :center :justifyContent :center}) -(def more-btn-icon - {:width 4 - :height 16}) +(def search-btn + {:width 24 + :height 56 + :margin-right 24 + :alignItems :center + :justifyContent :center}) ; New contact diff --git a/src/status_im/contacts/subs.cljs b/src/status_im/contacts/subs.cljs index cc884b8f97..6d34d6fa9e 100644 --- a/src/status_im/contacts/subs.cljs +++ b/src/status_im/contacts/subs.cljs @@ -1,7 +1,8 @@ (ns status-im.contacts.subs (:require-macros [reagent.ratom :refer [reaction]]) (:require [re-frame.core :refer [register-sub subscribe]] - [status-im.utils.identicon :refer [identicon]])) + [status-im.utils.identicon :refer [identicon]] + [clojure.string :as str])) (register-sub :current-contact (fn [db [_ k]] @@ -29,47 +30,66 @@ (sort-contacts) (reaction))))) -(register-sub :all-added-people - (fn [] - (let [contacts (subscribe [:all-added-contacts])] - (reaction (remove :dapp? @contacts))))) +(register-sub :all-added-group-contacts + (fn [db [_ group-id]] + (let [contacts (subscribe [:all-added-contacts]) + group-contacts (reaction (into #{} (map #(:identity %) + (get-in @db [:contact-groups group-id :contacts]))))] + (reaction (filter #(@group-contacts (:whisper-identity %)) @contacts))))) -(register-sub :all-added-dapps - (fn [] - (let [contacts (subscribe [:all-added-contacts])] - (reaction (filter :dapp? @contacts))))) - -(register-sub :get-added-people-with-limit - (fn [_ [_ limit]] - (let [contacts (subscribe [:all-added-people])] +(register-sub :all-added-group-contacts-with-limit + (fn [db [_ group-id limit]] + (let [contacts (subscribe [:all-added-group-contacts group-id])] (reaction (take limit @contacts))))) -(register-sub :get-added-dapps-with-limit +(register-sub :all-added-group-contacts-count + (fn [_ [_ group-id]] + (let [contacts (subscribe [:all-added-group-contacts group-id])] + (reaction (count @contacts))))) + +(register-sub :get-added-contacts-with-limit (fn [_ [_ limit]] - (let [contacts (subscribe [:all-added-dapps])] + (let [contacts (subscribe [:all-added-contacts])] (reaction (take limit @contacts))))) -(register-sub :added-people-count +(register-sub :added-contacts-count (fn [_ _] - (let [contacts (subscribe [:all-added-people])] + (let [contacts (subscribe [:all-added-contacts])] (reaction (count @contacts))))) -(register-sub :added-dapps-count - (fn [_ _] - (let [contacts (subscribe [:all-added-dapps])] - (reaction (count @contacts))))) +(register-sub :all-added-groups + (fn [db _] + (let [groups (reaction (vals (:contact-groups @db)))] + (->> (remove :pending? @groups) + (sort-by :order >) + (reaction))))) (defn get-contact-letter [contact] (when-let [letter (first (:name contact))] (clojure.string/upper-case letter))) +(defn search-filter [text item] + (let [name (-> (or (:name item) "") + (str/lower-case)) + text (str/lower-case text)] + (not= (str/index-of name text) nil))) + +(register-sub :all-added-group-contacts-filtered + (fn [_ [_ group-id]] + (let [contacts (if group-id + (subscribe [:all-added-group-contacts group-id]) + (subscribe [:all-added-contacts])) + text (subscribe [:get-in [:toolbar-search :text]])] + (reaction + (if @text + (filter #(search-filter @text %) @contacts) + @contacts))))) + (register-sub :contacts-with-letters (fn [db _] - (let [contacts (reaction (:contacts @db)) - pred (subscribe [:get :contacts-filter])] + (let [contacts (reaction (:contacts @db))] (reaction - (let [ordered (sort-contacts @contacts) - ordered (if @pred (filter @pred ordered) ordered)] + (let [ordered (sort-contacts @contacts)] (reduce (fn [prev cur] (let [prev-letter (get-contact-letter (last prev)) cur-letter (get-contact-letter cur)] diff --git a/src/status_im/contacts/views/contact.cljs b/src/status_im/contacts/views/contact.cljs index 3096290342..67cc593ae9 100644 --- a/src/status_im/contacts/views/contact.cljs +++ b/src/status_im/contacts/views/contact.cljs @@ -4,31 +4,40 @@ [re-frame.core :refer [dispatch]] [status-im.contacts.styles :as st] [status-im.contacts.views.contact-inner :refer [contact-inner-view]] + [status-im.components.context-menu :refer [context-menu]] + [status-im.i18n :refer [label]] [status-im.utils.platform :refer [platform-specific]])) (defn- on-press [{:keys [whisper-identity] :as contact}] (dispatch [:send-contact-request! contact]) (dispatch [:start-chat whisper-identity {} :navigation-replace])) -(defn- more-on-press [contact] - (dispatch [:open-contact-menu (:list-selection-fn platform-specific) contact])) - (defn letter-view [letter] [view st/letter-container (when letter [text {:style st/letter-text} letter])]) +(defn options-btn [contact more-options] + (let [options [{:value #(dispatch [:hide-contact contact]) :text (label :t/delete-contact)}]] + [view st/more-btn + [context-menu + [icon :options_gray] + (or more-options options)]])) + +;;TODO: maybe it's better to have only one global component contact-view with the types: default, extended and toggle +;;TODO: at the moment toggle in the other component new-group-contact (defview contact-view [{{:keys [whisper-identity letter dapp?] :as contact} :contact - :keys [extended? letter? on-click more-on-click info]}] + :keys [extended? letter? on-click extend-options info]}] [chat [:get-chat whisper-identity]] [touchable-highlight - {:on-press #((or on-click on-press) contact)} - [view st/contact-container - (when letter? - [letter-view letter]) - [contact-inner-view contact info] - (when (and extended? (not dapp?)) - [touchable-highlight - {:on-press #((or more-on-click more-on-press) contact)} - [view st/more-btn - [icon :more_vertical st/more-btn-icon]]])]]) + (when-not extended? + {:on-press #((or on-click on-press) contact)}) + [view + [view st/contact-container + (when letter? + [letter-view letter]) + [contact-inner-view {:contact contact :info info}] + (when extended? + [options-btn contact extend-options])] + [view st/contact-separator-container + [view (get-in platform-specific [:component-styles :contacts :separator])]]]]) diff --git a/src/status_im/contacts/views/contact_inner.cljs b/src/status_im/contacts/views/contact_inner.cljs index 9e245d902b..df185d5310 100644 --- a/src/status_im/contacts/views/contact_inner.cljs +++ b/src/status_im/contacts/views/contact_inner.cljs @@ -10,10 +10,8 @@ [contact-icon-contacts-tab contact]]) (defn contact-inner-view - ([contact] - (contact-inner-view contact nil)) - ([{:keys [whisper-identity name] :as contact} info] - [view st/contact-inner-container + ([{:keys [info style] {:keys [whisper-identity name] :as contact} :contact}] + [view (merge st/contact-inner-container style) [contact-photo contact] [view st/info-container [text {:style st/name-text diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index 4260f25daa..0025f6c045 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -9,7 +9,7 @@ [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.text-field.view :refer [text-field]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.view :refer [toolbar-with-search toolbar]] [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :refer [toolbar-background1]] [status-im.components.drawer.view :refer [drawer-view open-drawer]] @@ -17,8 +17,7 @@ [status-im.contacts.styles :as st] [status-im.utils.listview :as lw] [status-im.i18n :refer [label]] - [status-im.utils.platform :refer [platform-specific]] - [status-im.contacts.views.contact-inner :refer [contact-inner-view]])) + [status-im.utils.platform :refer [platform-specific]])) (defn new-group-chat-view [] [view @@ -46,6 +45,7 @@ (defn render-row [chat-modal click-handler action params] (fn [row _ _] (list-item + ^{:key row} [contact-view {:contact row :letter? chat-modal :on-click (when click-handler @@ -64,58 +64,62 @@ label]]]]]) (defview contact-list-toolbar [] - [group [:get :contacts-group] - modal [:get :modal]] + [group [:get :contacts-group] + modal [:get :modal] + show-search [:get-in [:toolbar-search :show]]] [view [status-bar] - [toolbar {:title (label (if-not group - :t/contacts - (if (= group :dapps) - :t/contacts-group-dapps - :t/contacts-group-new-chat))) - :nav-action (when modal - (act/back #(dispatch [:navigate-back]))) - :background-color toolbar-background1 - :style (get-in platform-specific [:component-styles :toolbar]) - :actions [(act/search #())]}]]) + (toolbar-with-search + {:show-search? (= show-search :contact-list) + :search-key :contact-list + :title (if-not group + (label :t/contacts) + (or (:name group) (label :t/contacts-group-new-chat))) + :search-placeholder (label :t/search-for) + :actions (when modal + (act/back #(dispatch [:navigate-back])))})]) -(defview contact-list [] - [contacts [:contacts-with-letters] - group [:get :contacts-group] - modal [:get :modal] - click-handler [:get :contacts-click-handler] - action [:get :contacts-click-action] +(defview contacts-list-view [group modal click-handler action] + [contacts [:all-added-group-contacts-filtered (:group-id group)] params [:get :contacts-click-params]] (let [show-new-group-chat? (and (= group :people) (get-in platform-specific [:chats :new-chat-in-toolbar?]))] - [drawer-view - [view st/contacts-list-container - [contact-list-toolbar] - ;; todo add stub - (when modal - [view - [contact-list-entry {:click-handler #(do - (dispatch [:send-to-webview-bridge - {:event (name :webview-send-transaction)}]) - (dispatch [:navigate-back])) - :icon :icon_enter_address - :icon-style st/enter-address-icon - :label (label :t/enter-address)}] - [contact-list-entry {:click-handler #(click-handler :qr-scan action) - :icon :icon_scan_q_r - :icon-style st/scan-qr-icon - :label (label (if (= :request action) - :t/show-qr - :t/scan-qr))}]]) - (when contacts - [list-view {:dataSource (lw/to-datasource contacts) - :enableEmptySections true - :renderRow (render-row modal click-handler action params) - :bounces false - :renderHeader #(list-item - [view - (if show-new-group-chat? - [new-group-chat-view]) - [view st/spacing-top]]) - :renderFooter #(list-item [view st/spacing-bottom]) - :style st/contacts-list}])]])) + (when contacts + [list-view {:dataSource (lw/to-datasource contacts) + :enableEmptySections true + :renderRow (render-row modal click-handler action params) + :bounces false + :keyboardShouldPersistTaps true + :renderHeader #(list-item + [view + (if show-new-group-chat? + [new-group-chat-view]) + [view st/spacing-top]]) + :renderFooter #(list-item [view st/spacing-bottom]) + :style st/contacts-list}]))) + +(defview contact-list [] + [action [:get :contacts-click-action] + modal [:get :modal] + click-handler [:get :contacts-click-handler] + group [:get :contacts-group]] + [drawer-view + [view st/contacts-list-container + [contact-list-toolbar] + ;; todo add stub + (when modal + [view + [contact-list-entry {:click-handler #(do + (dispatch [:send-to-webview-bridge + {:event (name :webview-send-transaction)}]) + (dispatch [:navigate-back])) + :icon :icon_enter_address + :icon-style st/enter-address-icon + :label (label :t/enter-address)}] + [contact-list-entry {:click-handler #(click-handler :qr-scan action) + :icon :icon_scan_q_r + :icon-style st/scan-qr-icon + :label (label (if (= :request action) + :t/show-qr + :t/scan-qr))}]]) + [contacts-list-view group modal click-handler action]]]) diff --git a/src/status_im/data_store/chats.cljs b/src/status_im/data_store/chats.cljs index 4ed378a66b..a0c0996181 100644 --- a/src/status_im/data_store/chats.cljs +++ b/src/status_im/data_store/chats.cljs @@ -4,12 +4,12 @@ (:refer-clojure :exclude [exists?])) (defn- normalize-contacts - [chats] - (map #(update % :contacts vals) chats)) + [item] + (update item :contacts vals)) (defn get-all [] - (normalize-contacts (data-store/get-all-active))) + (map normalize-contacts (data-store/get-all-active))) (defn get-by-id [id] diff --git a/src/status_im/data_store/contact_groups.cljs b/src/status_im/data_store/contact_groups.cljs new file mode 100644 index 0000000000..4854c5112a --- /dev/null +++ b/src/status_im/data_store/contact_groups.cljs @@ -0,0 +1,23 @@ +(ns status-im.data-store.contact-groups + (:require [status-im.data-store.realm.contact-groups :as data-store]) + (:refer-clojure :exclude [exists?])) + +(defn- normalize-contacts + [item] + (update item :contacts vals)) + +(defn get-all + [] + (map normalize-contacts (data-store/get-all-as-list))) + +(defn save + [{:keys [group-id] :as group}] + (data-store/save group (data-store/exists? group-id))) + +(defn save-all + [groups] + (mapv save groups)) + +(defn delete + [group-id] + (data-store/delete group-id)) diff --git a/src/status_im/data_store/realm/contact_groups.cljs b/src/status_im/data_store/realm/contact_groups.cljs new file mode 100644 index 0000000000..122e0770c0 --- /dev/null +++ b/src/status_im/data_store/realm/contact_groups.cljs @@ -0,0 +1,26 @@ +(ns status-im.data-store.realm.contact-groups + (:require [status-im.data-store.realm.core :as realm] + [status-im.utils.random :refer [timestamp]]) + (:refer-clojure :exclude [exists?])) + +(defn get-all + [] + (-> @realm/account-realm + (realm/get-all :contact-group))) + +(defn get-all-as-list + [] + (realm/realm-collection->list (get-all))) + +(defn save + [group update?] + (realm/save @realm/account-realm :contact-group group update?)) + +(defn exists? + [group-id] + (realm/exists? @realm/account-realm :contact-group {:group-id group-id})) + +(defn delete + [group-id] + (when-let [group (realm/get-one-by-field @realm/account-realm :contact-group :group-id group-id)] + (realm/delete @realm/account-realm group))) \ No newline at end of file diff --git a/src/status_im/data_store/realm/schemas/account/core.cljs b/src/status_im/data_store/realm/schemas/account/core.cljs index 85a9629e22..121b62930b 100644 --- a/src/status_im/data_store/realm/schemas/account/core.cljs +++ b/src/status_im/data_store/realm/schemas/account/core.cljs @@ -3,7 +3,8 @@ [status-im.data-store.realm.schemas.account.v2.core :as v2] [status-im.data-store.realm.schemas.account.v3.core :as v3] [status-im.data-store.realm.schemas.account.v4.core :as v4] - )) + [status-im.data-store.realm.schemas.account.v5.core :as v5])) + ; put schemas ordered by version (def schemas [{:schema v1/schema @@ -17,4 +18,7 @@ :migration v3/migration} {:schema v4/schema :schemaVersion 4 - :migration v4/migration}]) + :migration v4/migration} + {:schema v5/schema + :schemaVersion 5 + :migration v5/migration}]) diff --git a/src/status_im/data_store/realm/schemas/account/v2/core.cljs b/src/status_im/data_store/realm/schemas/account/v2/core.cljs index 3cdb8d876b..aaa93940b8 100644 --- a/src/status_im/data_store/realm/schemas/account/v2/core.cljs +++ b/src/status_im/data_store/realm/schemas/account/v2/core.cljs @@ -29,4 +29,4 @@ (defn migration [old-realm new-realm] (log/debug "migrating v2 account database: " old-realm new-realm) (chat/migration old-realm new-realm) - (contact/migration old-realm new-realm)) + (contact/migration old-realm new-realm)) \ No newline at end of file diff --git a/src/status_im/data_store/realm/schemas/account/v5/contact_group.cljs b/src/status_im/data_store/realm/schemas/account/v5/contact_group.cljs new file mode 100644 index 0000000000..c1e4d6eee6 --- /dev/null +++ b/src/status_im/data_store/realm/schemas/account/v5/contact_group.cljs @@ -0,0 +1,15 @@ +(ns status-im.data-store.realm.schemas.account.v5.contact-group + (:require [taoensso.timbre :as log])) + +(def schema {:name :contact-group + :primaryKey :group-id + :properties {:group-id :string + :name :string + :timestamp :int + :order :int + :pending? {:type :bool :default false} + :contacts {:type :list + :objectType :group-contact}}}) + +(defn migration [old-realm new-realm] + (log/debug "migrating group schema v5")) diff --git a/src/status_im/data_store/realm/schemas/account/v5/core.cljs b/src/status_im/data_store/realm/schemas/account/v5/core.cljs new file mode 100644 index 0000000000..13d46af137 --- /dev/null +++ b/src/status_im/data_store/realm/schemas/account/v5/core.cljs @@ -0,0 +1,36 @@ +(ns status-im.data-store.realm.schemas.account.v5.core + (:require [status-im.data-store.realm.schemas.account.v4.chat :as chat] + [status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact] + [status-im.data-store.realm.schemas.account.v1.command :as command] + [status-im.data-store.realm.schemas.account.v3.contact :as contact] + [status-im.data-store.realm.schemas.account.v1.discover :as discover] + [status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store] + [status-im.data-store.realm.schemas.account.v4.message :as message] + [status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message] + [status-im.data-store.realm.schemas.account.v1.processed-message :as processed-message] + [status-im.data-store.realm.schemas.account.v1.request :as request] + [status-im.data-store.realm.schemas.account.v1.tag :as tag] + [status-im.data-store.realm.schemas.account.v1.user-status :as user-status] + [status-im.data-store.realm.schemas.account.v5.contact-group :as contact-group] + [status-im.data-store.realm.schemas.account.v5.group-contact :as group-contact] + [taoensso.timbre :as log])) + +(def schema [chat/schema + chat-contact/schema + command/schema + contact/schema + discover/schema + kv-store/schema + message/schema + pending-message/schema + processed-message/schema + request/schema + tag/schema + user-status/schema + contact-group/schema + group-contact/schema]) + +(defn migration [old-realm new-realm] + (log/debug "migrating v5 account database: " old-realm new-realm) + (chat/migration old-realm new-realm) + (contact/migration old-realm new-realm)) diff --git a/src/status_im/data_store/realm/schemas/account/v5/group_contact.cljs b/src/status_im/data_store/realm/schemas/account/v5/group_contact.cljs new file mode 100644 index 0000000000..c2df25137f --- /dev/null +++ b/src/status_im/data_store/realm/schemas/account/v5/group_contact.cljs @@ -0,0 +1,8 @@ +(ns status-im.data-store.realm.schemas.account.v5.group-contact + (:require [taoensso.timbre :as log])) + +(def schema {:name :group-contact + :properties {:identity "string"}}) + +(defn migration [_ _] + (log/debug "migrating group-contact schema v5")) \ No newline at end of file diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index b7adefea48..0d6a14f620 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -20,6 +20,7 @@ :new-contact-identity "" :contacts {} + :contact-groups {} :discoveries {} :discover-search-tags [] :tags {} diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index aae8015eac..0d4a01d122 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -74,6 +74,7 @@ (dispatch [:initialize-sync-listener]) (dispatch [:initialize-chats]) (dispatch [:load-contacts]) + (dispatch [:load-groups]) (dispatch [:init-chat]) (dispatch [:init-discoveries]) (dispatch [:init-debug-mode address]) diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 8734c9b925..6c3c20fb67 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -22,7 +22,8 @@ [status-im.accounts.screen :refer [accounts]] [status-im.transactions.screen :refer [confirm]] [status-im.chats-list.screen :refer [chats-list]] - [status-im.new-group.screen-private :refer [new-group]] + [status-im.new-group.screen-private :refer [new-group contact-group]] + [status-im.new-group.views.contact-list :refer [contact-group-list]] [status-im.new-group.screen-public :refer [new-public-group]] [status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.remove :refer [remove-participants]] @@ -92,6 +93,8 @@ :contact-list main-tabs :contact-list-search-results contacts-search-results :group-contacts contact-list + :contact-group contact-group + :contact-group-list contact-group-list :new-contact new-contact :qr-scanner qr-scanner :chat chat diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index f1d008c2b9..6a2d8d4627 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -1,6 +1,5 @@ (ns status-im.ios.platform - (:require [status-im.components.styles :as styles] - [status-im.components.toolbar.styles :refer [toolbar-background2]])) + (:require [status-im.components.styles :as styles])) (def component-styles {:status-bar {:default {:height 20 @@ -8,7 +7,7 @@ :color styles/color-white} :main {:height 20 :bar-style "default" - :color toolbar-background2} + :color styles/color-white} :transparent {:height 20 :bar-style "light-content" :color styles/color-transparent} @@ -23,7 +22,7 @@ :border-bottom-width 0.5} :chat {:new-message {:border-top-color styles/color-gray3 :border-top-width 0.5}} - :discover {:subtitle {:color styles/color-steel + :discover {:subtitle {:color styles/color-steel :font-size 13 :letter-spacing 1} :popular {:border-radius 3 @@ -41,9 +40,21 @@ :icon {:padding-top 0 :bottom -4 :justify-content :flex-end}}} - :contacts {:subtitle {:color styles/color-steel - :font-size 13 - :letter-spacing 1}} + :contacts {:subtitle {:color styles/color-black + :font-size 16 + :letter-spacing -0.2} + :separator {:margin-left 68 + :height 1 + :background-color styles/color-gray5 + :opacity 0.4} + :icon-check {:border-radius 50 + :width 24 + :height 24} + :group-header {:flexDirection :row + :alignItems :center + :margin-top 24 + :height 53 + :backgroundColor styles/color-white}} :bottom-gradient {:height 1} :input-label {:left 0} :input-error-text {:margin-left 0} @@ -55,7 +66,8 @@ :toolbar-last-activity {:color styles/text2-color :background-color :transparent :top 0 - :font-size 14}}) + :font-size 14} + :toolbar-title-container {:align-items :center}}) (def fonts {:light {:font-family "SFUIText-Light"} @@ -75,7 +87,6 @@ :cancelButtonIndex (count options)}) callback)) - ;; Structure to be exported (def platform-specific diff --git a/src/status_im/new_group/handlers.cljs b/src/status_im/new_group/handlers.cljs index 676707b319..836d6858bf 100644 --- a/src/status_im/new_group/handlers.cljs +++ b/src/status_im/new_group/handlers.cljs @@ -4,7 +4,9 @@ [status-im.utils.handlers :refer [register-handler]] [status-im.components.styles :refer [default-chat-color]] [status-im.data-store.chats :as chats] + [status-im.data-store.contact-groups :as groups] [clojure.string :as s] + [status-im.i18n :refer [label]] [status-im.utils.handlers :as u] [status-im.utils.random :as random] [taoensso.timbre :refer-macros [debug]] @@ -86,7 +88,7 @@ :private private-key} :callback #(dispatch [:incoming-message %1 %2])}))) -(register-handler :create-new-group +(register-handler :create-new-group-chat (-> prepare-chat ((enrich add-chat)) ((after create-chat!)) @@ -161,6 +163,98 @@ :keypair keypair :callback #(dispatch [:incoming-message %1 %2])}))))))) +(defn prepare-group + [{:keys [selected-contacts contact-groups] :as db} [_ group-name]] + (let [contacts (mapv #(hash-map :identity %) selected-contacts)] + (assoc db :new-group {:group-id (random/id) + :name group-name + :order (count contact-groups) + :timestamp (random/timestamp) + :contacts contacts}))) + +(defn add-group + [{:keys [new-group] :as db} _] + (update db :contact-groups merge {(:group-id new-group) new-group})) + +(defn update-group + [{:keys [new-group] :as db} _] + (update db :contact-groups merge {(:group-id new-group) new-group})) + +(defn create-group! + [{:keys [new-group]} _] + (groups/save new-group)) + +(defn update-group! + [{:keys [new-group] :as db} _] + (groups/save new-group)) + +(defn show-contact-list! + [_ _] + (dispatch [:navigate-to-clean :contact-list])) + +(register-handler + :create-new-group + (-> prepare-group + ((enrich add-group)) + ((after create-group!)) + ((after show-contact-list!)))) + +(defn prepare-group-after-edit + [{:keys [selected-contacts] :as db} [_ group group-name]] + (let [contacts (mapv #(hash-map :identity %) selected-contacts) + group' (assoc group :name group-name + :contacts contacts)] + (assoc db :new-group group'))) + +(register-handler + :update-group-after-edit + (-> prepare-group-after-edit + ((enrich update-group)) + ((after update-group!)) + ((after show-contact-list!)))) + +(register-handler + :update-group + (-> (fn [db [_ new-group]] + (assoc db :new-group new-group)) + ((enrich update-group)) + ((after update-group!)) + ((after show-contact-list!)))) + +(defn save-groups! [{:keys [new-groups]} _] + (groups/save-all new-groups)) + +(defn update-pending-status [old-groups {:keys [group-id pending?] :as group}] + (let [{old-pending :pending? + :as old-group} (get old-groups group-id) + pending?' (if old-pending (and old-pending pending?) pending?)] + (assoc group :pending? (boolean pending?')))) + +(defn add-new-groups + [{:keys [contact-groups] :as db} [_ new-groups]] + (let [identities (set (keys contact-groups)) + new-groups' (->> new-groups + (map #(update-pending-status contact-groups %)) + (remove #(identities (:group-id %))) + (map #(vector (:group-id %) %)) + (into {}))] + (-> db + (update :contact-groups merge new-groups') + (assoc :new-groups (vals new-groups'))))) + +(register-handler :add-groups + (after save-groups!) + add-new-groups) + +(defn load-groups! [db _] + (let [groups (->> (groups/get-all) + (map (fn [{:keys [group-id] :as group}] + [group-id group])) + (into {}))] + (assoc db :contact-groups groups))) + +(register-handler :load-groups load-groups!) + (defmethod nav/preload-data! :new-public-group [db] (dissoc db :public-group/topic)) diff --git a/src/status_im/new_group/screen_private.cljs b/src/status_im/new_group/screen_private.cljs index cc21d46a26..debb4d4a20 100644 --- a/src/status_im/new_group/screen_private.cljs +++ b/src/status_im/new_group/screen_private.cljs @@ -2,6 +2,7 @@ (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch]] [status-im.resources :as res] + [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.react :refer [view text image @@ -10,10 +11,12 @@ list-view list-item]] [status-im.components.text-field.view :refer [text-field]] + [status-im.components.confirm-button :refer [confirm-button]] [status-im.components.styles :refer [color-blue separator-color]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.view :refer [toolbar-with-search toolbar]] + [status-im.utils.platform :refer [platform-specific]] [status-im.utils.listview :refer [to-datasource]] [status-im.new-group.views.contact :refer [new-group-contact]] [status-im.new-group.styles :as st] @@ -21,7 +24,7 @@ [status-im.i18n :refer [label]] [cljs.spec :as s])) -(defview new-group-toolbar [] +(defview new-chat-group-toolbar [] [new-chat-name [:get :new-chat-name]] (let [create-btn-enabled? (s/valid? ::v/name new-chat-name)] [view @@ -31,15 +34,13 @@ :actions [{:image {:source res/v ;; {:uri "icon_search"} :style (st/toolbar-icon create-btn-enabled?)} :handler (when create-btn-enabled? - #(dispatch [:create-new-group new-chat-name]))}]}]])) + #(dispatch [:create-new-group-chat new-chat-name]))}]}]])) (defview group-name-input [] [new-chat-name [:get :new-chat-name]] [view [text-field - {:error (cond - (not (s/valid? ::v/not-empty-string new-chat-name)) - (label :t/empty-group-chat-name) + {:error (when (not (s/valid? ::v/not-illegal-name new-chat-name)) (label :t/illegal-group-chat-name)) :wrapper-style st/group-chat-name-wrapper @@ -54,7 +55,7 @@ (defview new-group [] [contacts [:all-added-contacts]] [view st/new-group-container - [new-group-toolbar] + [new-chat-group-toolbar] [view st/chat-name-container [text {:style st/members-text :font :medium} @@ -64,11 +65,64 @@ :font :medium} (label :t/members-title)] #_[touchable-highlight {:on-press (fn [])} - [view st/add-container - [icon :add_gray st/add-icon] - [text {:style st/add-text} (label :t/add-members)]]] + [view st/add-container + [icon :add_gray st/add-icon] + [text {:style st/add-text} (label :t/add-members)]]] [list-view {:dataSource (to-datasource contacts) :renderRow (fn [row _ _] (list-item [new-group-contact row])) :style st/contacts-list}]]]) + +(defview new-contacts-group-toolbar [edit?] + [view + [status-bar] + [toolbar + {:title (label (if edit? :t/edit-group :t/new-group))}]]) + +(defn chat-name-view [contacts-count] + [view st/chat-name-container + [text {:style st/group-name-text + :font :medium} + (label :t/group-name)] + [group-name-input] + [text {:style st/members-text + :font :medium} + (str (label :t/group-members) " " contacts-count)] + [touchable-highlight {:on-press #(dispatch [:navigate-forget :contact-group-list])} + [view st/add-container + [icon :add_blue st/add-icon] + [text {:style st/add-text} (label :t/add-members)]]]]) + +(defn delete-btn [on-press] + [touchable-highlight {:on-press on-press} + [view st/delete-group-container + [text {:style st/delete-group-text} (label :t/delete-group)] + [text {:style st/delete-group-prompt-text} (label :t/delete-group-prompt)]]]) + +;;TODO: should be refactored into one common function for group chats and contact groups +(defview contact-group [] + [contacts [:selected-group-contacts] + group-name [:get :new-chat-name] + group [:get :contact-group]] + (let [save-btn-enabled? (and (s/valid? ::v/name group-name) (pos? (count contacts)))] + [view st/new-group-container + [new-contacts-group-toolbar (boolean group)] + [chat-name-view (count contacts)] + [list-view + {:dataSource (to-datasource contacts) + :renderRow (fn [row _ _] + (list-item + ^{:key row} + [contact-view + {:contact row + :extend-options [{:value #(dispatch [:deselect-contact (:whisper-identity row)]) + :text (label :t/remove-from-group)}] + :extended? true}])) + :style st/contacts-list}] + (when group + [delete-btn #(dispatch [:update-group (assoc group :pending? true)])]) + (when save-btn-enabled? + [confirm-button (label :t/save) (if group + #(dispatch [:update-group-after-edit group group-name]) + #(dispatch [:create-new-group group-name]))])])) diff --git a/src/status_im/new_group/styles.cljs b/src/status_im/new_group/styles.cljs index cf4b583ab5..25615149f0 100644 --- a/src/status_im/new_group/styles.cljs +++ b/src/status_im/new_group/styles.cljs @@ -2,7 +2,11 @@ (:require [status-im.components.styles :refer [color-white color-blue text1-color - text2-color]] + text2-color + color-light-blue + color-light-red + selected-contact-color + color-gray4]] [status-im.utils.platform :refer [platform-specific]])) (defn toolbar-icon [enabled?] @@ -37,27 +41,49 @@ (def group-chat-name-wrapper {:padding-top 0}) +(def group-name-text + {:margin-top 11 + :margin-bottom 10 + :letter-spacing -0.1 + :color color-gray4 + :font-size 13 + :line-height 20}) + (def members-text - {:margin-top 24 - :margin-bottom 8 - :color text2-color - :font-size 14 - :line-height 20}) + {:margin-top 10 + :margin-bottom 8 + :letter-spacing -0.2 + :color color-gray4 + :font-size 16 + :line-height 19}) (def add-container {:flex-direction :row - :margin-bottom 16}) + :align-items :center + :margin-top 16 + :margin-bottom 16 + :margin-right 20}) (def add-icon - {:margin-vertical 18 - :margin-horizontal 3 - :width 17 - :height 17}) + {:align-items :center + :width 24 + :height 24}) (def add-text - {:margin-top 16 - :margin-left 32 - :color text2-color + {:margin-left 32 + :color color-light-blue + :letter-spacing -0.2 + :font-size 17 + :line-height 20}) + +(def delete-group-text + {:color color-light-red + :letter-spacing 0.5 + :font-size 14 + :line-height 20}) + +(def delete-group-prompt-text + {:color color-gray4 :font-size 14 :line-height 20}) @@ -70,9 +96,25 @@ :align-items :center :height 56}) -(def contact-item-checkbox - {:outer-size 20 - :filter-size 16 - :inner-size 12 - :outer-color color-blue - :inner-color color-blue}) +(def selected-contact + {:background-color selected-contact-color}) + +(def icon-check-container + (merge (get-in platform-specific [:component-styles :contacts :icon-check]) + {:alignItems :center + :justifyContent :center})) + +(def toggle-container + {:width 56 + :height 56 + :alignItems :center + :justifyContent :center}) + +(def check-icon + {:width 12 + :height 12}) + +(def delete-group-container + {:height 56 + :padding-left 72 + :margin-top 15}) \ No newline at end of file diff --git a/src/status_im/new_group/subs.cljs b/src/status_im/new_group/subs.cljs index 6753a5eacb..738b55ac04 100644 --- a/src/status_im/new_group/subs.cljs +++ b/src/status_im/new_group/subs.cljs @@ -1,7 +1,19 @@ (ns status-im.new-group.subs (:require-macros [reagent.ratom :refer [reaction]]) - (:require [re-frame.core :refer [register-sub]] + (:require [re-frame.core :refer [register-sub subscribe]] [status-im.utils.subs :as u])) (register-sub :is-contact-selected? (u/contains-sub :selected-contacts)) + +(register-sub :selected-contacts-count + (fn [_ _] + (let [contacts (subscribe [:get :selected-contacts])] + (reaction (count @contacts))))) + +(register-sub :selected-group-contacts + (fn [_ _] + (let [selected-contacts (subscribe [:get :selected-contacts]) + added-contacts (subscribe [:all-added-contacts])] + (reaction (do @selected-contacts ;;TODO: doesn't work without this line :( + (filter #(@selected-contacts (:whisper-identity %)) @added-contacts)))))) diff --git a/src/status_im/new_group/views/contact.cljs b/src/status_im/new_group/views/contact.cljs index be080bda05..20fca109ff 100644 --- a/src/status_im/new_group/views/contact.cljs +++ b/src/status_im/new_group/views/contact.cljs @@ -1,20 +1,29 @@ (ns status-im.new-group.views.contact (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.components.react :refer [view]] + [status-im.components.react :refer [view icon touchable-highlight]] [status-im.contacts.views.contact-inner :refer [contact-inner-view]] - [status-im.components.item-checkbox :refer [item-checkbox]] - [status-im.new-group.styles :as st])) + [status-im.new-group.styles :as st] + [status-im.contacts.styles :as cst] + [status-im.components.styles :refer [color-light-blue color-gray5]] + [status-im.utils.platform :refer [platform-specific]])) -(defn on-toggle [whisper-identity] - (fn [checked?] - (let [action (if checked? :select-contact :deselect-contact)] - (dispatch [action whisper-identity])))) +(defn on-toggle [checked? whisper-identity] + (let [action (if checked? :deselect-contact :select-contact)] + (dispatch [action whisper-identity]))) +;;TODO: maybe it's better to have only one global component contact-view (with the types: default, extended and toggle) (defview new-group-contact [{:keys [whisper-identity] :as contact}] [checked [:is-contact-selected? whisper-identity]] - [view st/contact-container - [item-checkbox (merge {:on-toggle (on-toggle whisper-identity) - :checked checked} - st/contact-item-checkbox)] - [contact-inner-view contact]]) + [touchable-highlight {:on-press #(on-toggle checked whisper-identity)} + [view + [view (merge st/contact-container (when checked {:style st/selected-contact})) + [contact-inner-view (merge {:contact contact} + (when checked {:style st/selected-contact}))] + [view st/toggle-container + [view (merge st/icon-check-container + {:background-color (if checked color-light-blue color-gray5)}) + (when checked + [icon :check_on st/check-icon])]]] + [view cst/contact-separator-container + [view (get-in platform-specific [:component-styles :contacts :separator])]]]]) diff --git a/src/status_im/new_group/views/contact_list.cljs b/src/status_im/new_group/views/contact_list.cljs new file mode 100644 index 0000000000..69d08511bb --- /dev/null +++ b/src/status_im/new_group/views/contact_list.cljs @@ -0,0 +1,38 @@ +(ns status-im.new-group.views.contact-list + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [dispatch]] + [status-im.components.react :refer [view + text + list-view + list-item]] + [status-im.components.confirm-button :refer [confirm-button]] + [status-im.components.status-bar :refer [status-bar]] + [status-im.components.toolbar.view :refer [toolbar-with-search]] + [status-im.utils.listview :refer [to-datasource]] + [status-im.new-group.views.contact :refer [new-group-contact]] + [status-im.new-group.styles :as st] + [status-im.i18n :refer [label]])) + +(defn contact-list-toolbar [contacts-count show-search?] + (toolbar-with-search + {:show-search? (= show-search? :contact-group-list) + :search-key :contact-group-list + :title (str (label :t/new-group) " (" contacts-count ")") + :search-placeholder (label :t/search-for)})) + +(defview contact-group-list [] + [contacts [:all-added-group-contacts-filtered] + selected-contacts-count [:selected-contacts-count] + show-search [:get-in [:toolbar-search :show]]] + [view st/new-group-container + [status-bar] + [contact-list-toolbar selected-contacts-count show-search] + [view {:flex 1} + [list-view + {:dataSource (to-datasource contacts) + :renderRow (fn [row _ _] + (list-item ^{:key row} [new-group-contact row])) + :style st/contacts-list + :keyboardShouldPersistTaps true}]] + (when (pos? selected-contacts-count) + [confirm-button (label :t/next) #(dispatch [:navigation-replace :contact-group])])]) diff --git a/src/status_im/participants/views/contact.cljs b/src/status_im/participants/views/contact.cljs index d474fb3305..1b3829b835 100644 --- a/src/status_im/participants/views/contact.cljs +++ b/src/status_im/participants/views/contact.cljs @@ -19,4 +19,4 @@ [item-checkbox {:onToggle (on-toggle whisper-identity) :checked checked :size 30}] - [contact-inner-view contact]]) + [contact-inner-view {:contact contact}]]) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 12916d3c2f..290a41f1ca 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -10,6 +10,7 @@ :offline "Offline" :search-for "Search for..." :cancel "Cancel" + :next "Next" ;drawer :invite-friends "Invite friends" @@ -141,8 +142,10 @@ ;contacts :contacts "Contacts" - :new-contact "New Contact" - :remove-contact "Remove contact" + :new-contact "New contact" + :delete-contact "Delete contact" + :remove-from-group "Remove from group" + :edit-contacts "Edit contacts" :show-all "SHOW ALL" :contacts-group-dapps "ÐApps" :contacts-group-people "People" @@ -150,6 +153,7 @@ :no-contacts "No contacts yet" :show-qr "Show QR" :enter-address "Enter address" + :more "more" ;group-settings :remove "Remove" @@ -185,6 +189,13 @@ :group-chat-name "Chat name" :empty-group-chat-name "Please enter a name" :illegal-group-chat-name "Please select another name" + :new-group "New Group" + :reorder-groups "Reorder Group" + :group-name "Group name" + :edit-group "Edit Group" + :delete-group "DELETE GROUP" + :delete-group-prompt "This will not affect group members" + :group-members "Group members" ;participants :add-participants "Add Participants" diff --git a/src/status_im/translations/ru.cljs b/src/status_im/translations/ru.cljs index a2239510e3..501b1d68a3 100644 --- a/src/status_im/translations/ru.cljs +++ b/src/status_im/translations/ru.cljs @@ -8,6 +8,8 @@ :chat-name "Имя чата" :notifications-title "Уведомления и звуки" :offline "Оффлайн" + :cancel "Отмена" + :next "Продолжить" ;drawer :invite-friends "Пригласить друзей" @@ -119,6 +121,7 @@ ;contacts :contacts "Контакты" :new-contact "Новый контакт" + :edit-contacts "Редактирование контактов" :show-all "ПОКАЗАТЬ ВСЕ" :contacts-group-dapps "ÐApps" :contacts-group-people "Люди" @@ -161,6 +164,9 @@ :group-chat-name "Имя чата" :empty-group-chat-name "Введите имя" :illegal-group-chat-name "Выберите другое имя" + :new-group "Новая группа" + :group-name "Название группы" + :reorder-groups "Упорядочить группы" ;participants :add-participants "Добавить участников" From 210a4823c9330966c4a418412eaff1083a05143f Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Wed, 1 Mar 2017 17:02:48 +0300 Subject: [PATCH 02/48] implemented custom title for toolbar with search added dapp icon to contact, fixed styles, fixed context menu warning, implemented search input clearing, fixed styles, reworked styles fixes for https://github.com/status-im/status-react/pull/826 code review revert toolbar contacts styles. global toolbar styles toolbar style and small fixes for contacts group contacts edit mode groups reorder screen --- .re-natal | 1 + .../res/drawable-hdpi/icon_back_white.png | Bin 202 -> 284 bytes .../res/drawable-hdpi/icon_close_dark.png | Bin 0 -> 469 bytes .../main/res/drawable-hdpi/icon_grab_gray.png | Bin 0 -> 219 bytes .../res/drawable-mdpi/icon_back_white.png | Bin 174 -> 236 bytes .../res/drawable-mdpi/icon_close_dark.png | Bin 0 -> 335 bytes .../main/res/drawable-mdpi/icon_grab_gray.png | Bin 0 -> 138 bytes .../res/drawable-xhdpi/icon_back_white.png | Bin 233 -> 344 bytes .../res/drawable-xhdpi/icon_close_dark.png | Bin 0 -> 622 bytes .../res/drawable-xhdpi/icon_grab_gray.png | Bin 0 -> 237 bytes .../res/drawable-xxhdpi/icon_back_white.png | Bin 370 -> 498 bytes .../res/drawable-xxhdpi/icon_close_dark.png | Bin 0 -> 841 bytes .../res/drawable-xxhdpi/icon_grab_gray.png | Bin 0 -> 371 bytes .../res/drawable-xxxhdpi/icon_back_white.png | Bin 467 -> 716 bytes .../res/drawable-xxxhdpi/icon_close_dark.png | Bin 0 -> 1149 bytes .../res/drawable-xxxhdpi/icon_grab_gray.png | Bin 0 -> 519 bytes ios/SF-UI-Text-Semibold.otf | Bin 0 -> 327904 bytes ios/StatusIm.xcodeproj/project.pbxproj | 4 + .../icon_back_white.png | Bin 370 -> 344 bytes .../icon_close_dark.imageset/Contents.json | 21 +++ .../icon_close_dark.png | Bin 0 -> 622 bytes .../icon_grab_gray.imageset/Contents.json | 21 +++ .../icon_grab_gray.png | Bin 0 -> 237 bytes .../icon_options_dark.imageset/Contents.json | 2 +- .../icon_dots_horizontal_dark.png | Bin 251 -> 0 bytes .../icon_options_dark.png | Bin 0 -> 362 bytes .../icon_options_gray.imageset/Contents.json | 2 +- .../icon_dots_horizontal_gray.png | Bin 250 -> 0 bytes .../icon_options_gray.png | Bin 0 -> 330 bytes ios/StatusIm/Info.plist | 5 +- package.json | 1 + src/status_im/android/core.cljs | 4 +- src/status_im/android/platform.cljs | 61 ++++++- src/status_im/chat/screen.cljs | 4 +- src/status_im/chats_list/screen.cljs | 4 +- src/status_im/chats_list/styles.cljs | 1 + src/status_im/commands/handlers/loading.cljs | 25 --- .../components/chat_icon/screen.cljs | 27 ++- .../components/chat_icon/styles.cljs | 26 +-- src/status_im/components/confirm_button.cljs | 5 +- src/status_im/components/context_menu.cljs | 10 +- .../components/sortable_list_view.cljs | 20 +++ src/status_im/components/styles.cljs | 35 ++-- .../components/text_field/styles.cljs | 5 +- src/status_im/components/text_field/view.cljs | 48 +++--- src/status_im/components/toolbar/actions.cljs | 23 +-- src/status_im/components/toolbar/styles.cljs | 41 +++-- src/status_im/components/toolbar/view.cljs | 20 +-- .../components/toolbar_new/actions.cljs | 47 ++++++ .../components/toolbar_new/styles.cljs | 82 +++++++++ .../components/toolbar_new/view.cljs | 114 +++++++++++++ src/status_im/contacts/handlers.cljs | 50 ++++-- src/status_im/contacts/screen.cljs | 94 +++++------ src/status_im/contacts/styles.cljs | 76 ++++----- src/status_im/contacts/subs.cljs | 5 +- src/status_im/contacts/views/contact.cljs | 9 +- .../contacts/views/contact_inner.cljs | 2 +- .../contacts/views/contact_list.cljs | 87 ++++++---- src/status_im/ios/core.cljs | 2 + src/status_im/ios/platform.cljs | 78 ++++++++- src/status_im/new_group/handlers.cljs | 35 +++- src/status_im/new_group/screen_private.cljs | 73 +++++--- src/status_im/new_group/screen_public.cljs | 4 +- src/status_im/new_group/styles.cljs | 157 +++++++++++++----- src/status_im/new_group/subs.cljs | 6 +- src/status_im/new_group/views/contact.cljs | 4 +- .../new_group/views/contact_list.cljs | 34 +++- .../new_group/views/reorder_groups.cljs | 76 +++++++++ src/status_im/qr_scanner/styles.cljs | 3 +- src/status_im/translations/en.cljs | 12 +- 70 files changed, 1070 insertions(+), 396 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_close_dark.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_grab_gray.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_close_dark.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_grab_gray.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_close_dark.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_grab_gray.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_close_dark.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_grab_gray.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_close_dark.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_grab_gray.png create mode 100644 ios/SF-UI-Text-Semibold.otf create mode 100644 ios/StatusIm/Images.xcassets/icon_close_dark.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_close_dark.imageset/icon_close_dark.png create mode 100644 ios/StatusIm/Images.xcassets/icon_grab_gray.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_grab_gray.imageset/icon_grab_gray.png delete mode 100644 ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_dots_horizontal_dark.png create mode 100644 ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_options_dark.png delete mode 100644 ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_dots_horizontal_gray.png create mode 100644 ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_options_gray.png create mode 100644 src/status_im/components/sortable_list_view.cljs create mode 100644 src/status_im/components/toolbar_new/actions.cljs create mode 100644 src/status_im/components/toolbar_new/styles.cljs create mode 100644 src/status_im/components/toolbar_new/view.cljs create mode 100644 src/status_im/new_group/views/reorder_groups.cljs diff --git a/.re-natal b/.re-natal index 8f9b7f3b7c..bcad9e346e 100644 --- a/.re-natal +++ b/.re-natal @@ -26,6 +26,7 @@ "react-native-fs", "react-native-dialogs", "react-native-popup-menu", + "react-native-sortable-listview", "react-native-image-resizer", "react-native-image-crop-picker", "react-native-webview-bridge", diff --git a/android/app/src/main/res/drawable-hdpi/icon_back_white.png b/android/app/src/main/res/drawable-hdpi/icon_back_white.png index 6bd5aec7c425ed9cca7027d64360ea32ccde6fba..1f8c88cefec59e7d63d911229947a845828d2e55 100644 GIT binary patch literal 284 zcmV+%0ptFOP)Px#)=5M`R9Fe^m(2>oFc5@miwZ*D&Uf*D-(reYQiy^naR|)EtuKn i_owY;N=*d*6ZisE6bcGQc1zR%0000p@J`NsRJvc!yoRBgAB`)7U*<2Df~AHI~pMp$I{iApdqKkRonQk zg`Iyw?_Fbs`;4md84Y#@JN&>&;M#IFX)3%@8S@EWmLGkBHt yXZ`qJulMaiW7nc~p}3<8o(tN-6#nrZF=wo`ub7p2<#Q^~Jq(_%elF{r5}E+Qlti%r diff --git a/android/app/src/main/res/drawable-hdpi/icon_close_dark.png b/android/app/src/main/res/drawable-hdpi/icon_close_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..34ee7bce50e83896ee9a9e46e79589848af647e7 GIT binary patch literal 469 zcmV;`0V@89P)Px$k4Z#9R9Fe^mS0K(F%ZU+#cOzl9>hKg7N4ZBcnm=b9zzPnC#m35J%|Tt%;z|4 zVkWzj2tLg|>?V_MW`6ye{o|Y+=72e14wwU(13sHoChMEK&Dr?}Ke+eP>tW};4;5(^ z4k7sU?e;O8-SyzY)9LNym%m*Ep)`YVuH-?VUx{zBeY(1(#~U_5`Qfbcytm8rw9MuN&~ zu(G_Wfbek@UHSBb-$`%yvTRiUIE5VKQVmIIF>}BiFbB+mSqHuVjc@@LEz4FX00000 LNkvXXu0mjf69Umu literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_grab_gray.png b/android/app/src/main/res/drawable-hdpi/icon_grab_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..0dbfd5a066c41943d702fc8979770852ec5adb64 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`O!ahe42j@; zJLMp6vjLCm+ZBs1B<^CGey+_WvN6@l+b$yJ;7P{L)1MW)-pFg$^(D7CGB61=Ft8{T zXfvMQ0NYSSrQb2k1wT9o$m z%+Dq3SEuGled7wwUEOhS+SX43{RB|IOz=F8t@y6uIqcKo>K3y85}Sb4q9e04U#Fm;e9( literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^96-#+!3HFS!eXZZDaPU;cPEB*=VV?2IT@ZVjv*3~ z$q5IT{{8Px$2}wjjR7ef&Q#%rZFc95{g&$fkprxnK(jKiWobgZ=&R9@66n3_pf|dhlt0fcj zh#6!j0cNmFiUf9F-rKxQi2U#l^mRbE2sY9FOeE%03U*0ydD?JMbeO%VxDv_yp2SBR zW?%~b)C7|tH(bpN^a1oi6CbPV0xE~jV| z;N*X8vW?u_mZqFOVKqB@@O`1>J?B46+D hz?!&Uy#xPu-~+`_pAv3-ot^*y002ovPDHLkV1f_`iz@&C literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_grab_gray.png b/android/app/src/main/res/drawable-mdpi/icon_grab_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..afd9670f895905538953cc8680b99034c50dacf1 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Ts&PILp*qs z6C_v{D;h{Knea2Z<(TP2Y$`qd|NsBJ8&5tIN=`|+GfUv{+h)DPx$5=lfsRA>e5m_Z7{Fc3w9f)-ra3wR$9+!VTX;ZeMR$MX^{+=w8?KVl(-G(sUv zMt)!@nbzdZn<8zUN%%`8sy897By(R@+8nZ;qgL&Ohe@_11H z|Gd-%&Fd-Y0B)+#QSoSYCw0yuhD^ qys0C=8^qcaG+}9g258_v4ZHy*7axOJ!PzkY0000$ f8YRM#Ef^TCMfKf?kCK`ObS{IZtDnm{r-UW|5sOu5 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_close_dark.png b/android/app/src/main/res/drawable-xhdpi/icon_close_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..331c130b4a6213f075bb1f4efac682010bc1dacf GIT binary patch literal 622 zcmV-!0+IcRP)Px%C`m*?RA>e5SUXO{Fc2MQMGc350wDw^pyyLSfwn+U!x^B2J5Vp8Shj$IPtO66 zwgANE5O9FqVV;p8it@3&PJx(6tHiPA&3n)GBv~Ro)B$xs9Z(0<0d+tf_`eRAQ0eR4 z-FY6HQzD+G%pBeJd)J{D`SEMry$u@kF_HN+8Smfp&z|%BP1jk|fMP$$GxG{FElJ|5 z)$P4*ag1-<#tH_oET%QaH~M>AxB#XZmqHSE4Dor42*e;37!J?Q>TkpADp-K&(4jFj za_BK4%E((xS&|Od_ncGj7xMNve4SlbevyP*65$NU(8m4ur{QBAQWbe7vvYURyR3^X z>kAeD5Ri-!QA>W%>z5I1x)&uNMnoIr!6RBgh={hxgG2Ch071p0jv&Sss|_}+UGtI4 zCZ9iv0035rKwrL8rX&ySiIxxm+)=f$rQcO5N=+WQlL-J=g$Q)DLLRt3?x67(kEAnD zwhwZqct7lNF^!kW1eB4-nwK973pdlrMI@<0Rpe1BVPTtPbmAGPBY!7#zG7o1n~8}8 zG?8};xJ?n!0({B0Eh0)lDET%;1Pj17tYIF+z8=&qr@6)D2Yhch!9HhK-h9T|F+8G^ zSn@6jHa991%B;I*G402_yW@8b79dGK95e{TzEzfqkb?W^uzk4+g<0Q!mD-?`XV^z``8gDco4hWvJNJ8aDY*hOG&(9yJh%s>}G%&!4 z1C~r;y??(QPM)^^X`Ji%KOyO6syA1!oS*!prb}e4sosB){5tMWS*N+o#OfSA>^pq= z5Whj>@;`fzTAz`ecSY>HB12<0hXMP)e-kSMjM%@0%w(?CdZUPB0RvOHSOmkf%X-}9 TnHS7~PG<0Q^>bP0l+XkKO21XN literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_back_white.png b/android/app/src/main/res/drawable-xxhdpi/icon_back_white.png index 166bc865a4588a56795a9e66e53e00ed57fed9ed..40801489f463f40f8cae4fb845bdabad50ac213a 100644 GIT binary patch literal 498 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D%z*Lb=(hEy=V zy=~~l>?m^VTfRO*J1m2Tg{5d=Md*@mD^qMEF6C))9KNYG z)A9epKU-oY-^MVg&UsRDT_=FyxqG(WY!mHi9W-I(Pb)pblDi&y1kLrBH)zkJ*sUaJ^y%6PQ5IB;<^ zvIO}kZ0IuPT+-l>z&VvA$U$L4ix-oof-YNjv`cT7U;OSN{dJ|}xx*&&{&o0kPRTyHw&|4RBJ1r=42&!S f4iKU-khQG5%dtdO;?OE!BrPx$EJ;K`R7eeDV4wo{|Np-n5HADb8$i4ch}EcIECU13AZ;Li1;ohU1&|}eOoF=!NF%BOO_-@=8C?rOM0vrmo4~igia-IUvUHA$i^3pNLB|wAMBYcj*0vSxY zi(y^_Y6jIB*Z^e)LtXwBo5?`23qZ^ba|Bs5(15!*3Pf(l)3rYwY zf=>Yf3+(afB}xuzK_`&@2gEQi0i>CcC=-ZK1T<9>sLTL}uQ4(*UIb|Y08X8X1*a~y Q8vpU}pAoaSW+o ze0$5jTi8*8?ZeF8goPPP6Os!jxe2mdymahY(bVu4qD?oVTtqhd%L=sqU_A0J;KHdN ztT{zjMaz53w}or`U>D>&+go|1QRPien%es}GWRy0RoiU*{`a~5vnl40OLqh|Fo`T+ zVAXJ7dV^TT1?ZTV#0nUj@_JlK*E`K0duSF28(F?5on+Vhh-cuqHkWEvG@07*#HZ*hE5;(+28jHvo{usapxvE z{D_!(bqdo;A$C`bEX~#VVY4L!uE~TOc`li0u~=zUR^inbS>nuxntDu+PxW9r$B*dNm+_F&RQEGd&|GrI!n5(2>n(nZlZ{Ce zzj6ENIxO^f5nuJYf%*ToE87js_`i9Iz5K}XZR`8U#(z7~Ha%YUz4Vbnd9H)Uv*wn% zb!+ovt^{fe2pv;;df+6JNb?kKb?E?(AU~Nanq`~268=99`z^(C$ji)8Jz!BF-nGx-ha#^7`>QZzmgE0yMU2@tXl`2~zp+xy>U@Of ziWCPS;VB)4`e8x}Cp$flbsZF9_cB~4VpzM;r7_4)CH0M#&cxGtP4#|@rfqs`nA&iG(7tgarhNLRI=`Sb* P<_!i>$8;;VuWOVx9wQ>AT5B*AIva%BZHkbN1EBYY@PD@OOW*c#oK>(6f3v)sK=D3;t@yYAYqlTV(XNP9km zY1U)5&B-pEC$4xfx*pLp{vmU-PX1KSKsoZKl_Np~&Fr>gTe~DWM4fw_1@t literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_back_white.png b/android/app/src/main/res/drawable-xxxhdpi/icon_back_white.png index 8992428891cd90e9368205e08d22812f38e90bac..c4ae1d0ee6726e01dfabe039d2608e2e6e3cd0c2 100644 GIT binary patch literal 716 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>U~2PpaSW+o ze0#@M-^EenSfO@c$8?vcs)C(P3&l;MTF-C2@Ay_)BQtdMrBxvzN*OLH*Ni7ky=_o@ z!#LgepSh*Z_mp#c_or*@@bN8FXkcLCz)C#OyHGseK#{ra@WVBFsqR}>?RxdK>bh`I z=G*wT5BwqKtKJnZ;(vB~|L+IZBA+I{+NyoOvR0<1GPnQygXJ>!LcMdfS?MdL+b_%vk5MEU$rW_uG&A7d(rHC_40M~{q-9^{nb48$8*60?T5a$ zFD*m(^c#IRYS-^vb6YTgPx$jY&j7R9Fe^nN3OrK@5d$MRe=9a<+otIn*2JR(GDlGk69OZ=m>xC@5}p=ik!y z3rs^3f=SsKM65ulu2ky1O6K*@Gu_Ng(b~3M0Dc?a!sqd0e7|X$SH|fWq$~I-uI-k< zXl@#`0FS{v!q*M_C1N8ZJ}d;ORCcf5zH1Ozp*+$F@wLUGVnQkp<#`6+qaxAMd{T}tPnk`i zjL$$$SqkOd=n{>&RJ~D#>|_JDXAoJTTyhxXcDk^bj95DP7?Oy(U@`Y}aSW+o zd^^WG?}~v;`&-U66INW|z0+t~(5w`o8ey=aW4b{41Ccq5igAk;cQ#~-`D?tgUu^fJNgOEdV~leX;s{`9T;Wy^)%R0Ruu zADrx;q_pjpqqio%OX%I-yZ%0NudaUe)H?cne%G&x@Pqq}rhoUyssH`w-@`lGIJ7Ua zE_il5>C-~vGR=P{ULA7N<7~Kp<@kM9WxevF;hh&B-`L+07=BD~`@)-%v*u}8F!*FY zywv>Y&4z>S>yF)EZWWDXxK)$9Mp9+R0rxZ4ZuGJi-650tD}>1ORzy5m}cve$=3``*x_bCPDr z)QT)w_?wBt((2UA?Rx(=RT?pJD6n_PRO&U~-Dcf4@={OF$g zmER0IXY}RPa(oDEd%`qf<@}bkwJZOsoOy8l_vv*7f`?yD`I%)?DO?g&u=PQ>_tS}M zRz+{SEtdXa_SUkvxu<77R9?1*Nx;E_)44gmr6EA5jbpzAW34KWXk8%FIh6&UOEUMT z*D{@RR)1UEw^rV9*2-mXY7Zni{>|EKGi%;^#WgBFI`&#Ha-8yJ^4s8hDVHVHTkY6C zCDsKC4yuUo$UoHya}eNcJ**$+pwG$NV9&v*?J2=gGe!6GUWJr5#=Wn0eYBK2zOJY* zUrw=4e;2<4qxo_F{3}i?+}&l?@!oQ|vVMV3QgZ(DyXU_>yELs^Y=cpaZzY3Jm*@rQ ze-0`lnhFws7(F!B2_IvfQ9OJ7EQzll&b=vXX}fD0{+Iod%dObm#d+GV#2=J?t-iF6 zd0xN4boFm3K8vp1z>o+_!kEcEirx ziR*)ERUT~B`r37A>y7-AF7j>X?m3+2mtR!dwqk`rNA0>MmxxY1hV}oWANR$4zWwvJ zXF>Q+1NY;WD#a_;+#&@&tN3p1)+ba#}pu@7JDS>VT{;y@xQxX1a2o!3~- Vq*!sI4X`|6@O1TaS?83{1OTH21GNAE literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_grab_gray.png b/android/app/src/main/res/drawable-xxxhdpi/icon_grab_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..640e8c98bab2c33eb9e996ae2f3a60311db85699 GIT binary patch literal 519 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-D%z4|=*dhEy=V zy}8$y*-?P)LM(TWr(y~J4i=q>feaH>R~>Mjq2X57Zy@I{V+HZN=S<03c z^4u*j-=>W4XaYOSp?Y_7+nxLo^_w0t7szk0tJ`e!C%ol%gD(GqJo`NH#PwnA-^Kp1 zy%9}6z2O~mRFkWIxx9extwr;GH;6?n^uEj9Ql#ZZPRN16yU|(b2fLta+->R1n;gKH OW$<+Mb6Mw<&;$T(FuQL6 literal 0 HcmV?d00001 diff --git a/ios/SF-UI-Text-Semibold.otf b/ios/SF-UI-Text-Semibold.otf new file mode 100644 index 0000000000000000000000000000000000000000..c11fa416de9542367457f00452382308dc992a28 GIT binary patch literal 327904 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≠*Jm(ae`!gH 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

pqK^_B2eqCEin8Q#}1V$UX?(5S)YS3VvS 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 literal 0 HcmV?d00001 diff --git a/ios/StatusIm.xcodeproj/project.pbxproj b/ios/StatusIm.xcodeproj/project.pbxproj index 181680ec94..5889ef5053 100644 --- a/ios/StatusIm.xcodeproj/project.pbxproj +++ b/ios/StatusIm.xcodeproj/project.pbxproj @@ -68,6 +68,7 @@ E0AD9E8F495A4907B65104BF /* libRCTImageResizer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BEE3436791D42248F853999 /* libRCTImageResizer.a */; }; EC8998BFE2C04023A860C065 /* libRNNetworkInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 74B7BDFF464F43D3BA8EA040 /* libRNNetworkInfo.a */; }; EF2B5857B4A34E0C9707FB3F /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B3B19223008342D096AA356E /* Octicons.ttf */; }; + F9238D6C1E5F055900C047B9 /* SF-UI-Text-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = F9238D6B1E5F055900C047B9 /* SF-UI-Text-Semibold.otf */; }; FD4F213C3873473CB703B1D2 /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674B3D9595A047AB8D518F4E /* libRNFS.a */; }; /* End PBXBuildFile section */ @@ -468,6 +469,7 @@ F090E261B9854867A728CE4F /* RealmReact.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RealmReact.xcodeproj; path = "../node_modules/realm/react-native/ios/RealmReact.xcodeproj"; sourceTree = ""; }; F3548417D8DA4362B6796A54 /* RNInstabug.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNInstabug.xcodeproj; path = "../node_modules/instabug-reactnative/ios/RNInstabug.xcodeproj"; sourceTree = ""; }; F93B6663A59F4B26BD4DA525 /* RNNetworkInfo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNNetworkInfo.xcodeproj; path = "../node_modules/react-native-network-info/ios/RNNetworkInfo.xcodeproj"; sourceTree = ""; }; + F9238D6B1E5F055900C047B9 /* SF-UI-Text-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Semibold.otf"; sourceTree = ""; }; FC1CBCFE6C906043D6CCEEE1 /* libPods-StatusImTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-StatusImTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -671,6 +673,7 @@ 2028E0111D4275BD00227DCD /* SF */ = { isa = PBXGroup; children = ( + F9238D6B1E5F055900C047B9 /* SF-UI-Text-Semibold.otf */, 9ED2F4601D9D577B00B36508 /* SF-UI-Text-Bold.otf */, 9E0B01A01DDC5DA7002B0359 /* SF-UI-Text-Light.otf */, 9ED2F45D1D9D52DD00B36508 /* SF-UI-Text-Regular.otf */, @@ -1471,6 +1474,7 @@ 9ED2F45F1D9D535A00B36508 /* SF-UI-Text-Medium.otf in Resources */, 2028DFFA1D4275B600227DCD /* SF-UI-Display-Regular.otf in Resources */, 2028DFF91D4275B600227DCD /* SF-UI-Display-Medium.otf in Resources */, + F9238D6C1E5F055900C047B9 /* SF-UI-Text-Semibold.otf in Resources */, 2028DFFC1D4275B600227DCD /* SF-UI-Display-Thin.otf in Resources */, 2028DFFB1D4275B600227DCD /* SF-UI-Display-Semibold.otf in Resources */, D28AEFB4C39548EB80416889 /* Entypo.ttf in Resources */, diff --git a/ios/StatusIm/Images.xcassets/icon_back_white.imageset/icon_back_white.png b/ios/StatusIm/Images.xcassets/icon_back_white.imageset/icon_back_white.png index 166bc865a4588a56795a9e66e53e00ed57fed9ed..66efe8d2167382cfa3b8037b70e46241709609dd 100644 GIT binary patch literal 344 zcmV-e0jK_nP)Px$5=lfsRA>e5m_Z7{Fc3w9f)-ra3wR$9+!VTX;ZeMR$MX^{+=w8?KVl(-G(sUv zMt)!@nbzdZn<8zUN%%`8sy897By(R@+8nZ;qgL&Ohe@_11H z|Gd-%&Fd-Y0B)+#QSoSYCw0yuhD^ qys0C=8^qcaG+}9g258_v4ZHy*7axOJ!PzkY0000Px$EJ;K`R7eeDV4wo{|Np-n5HADb8$i4ch}EcIECU13AZ;Li1;ohU1&|}eOoF=!NF%BOO_-@=8C?rOM0vrmo4~igia-IUvUHA$i^3pNLB|wAMBYcj*0vSxY zi(y^_Y6jIB*Z^e)LtXwBo5?`23qZ^ba|Bs5(15!*3Pf(l)3rYwY zf=>Yf3+(afB}xuzK_`&@2gEQi0i>CcC=-ZK1T<9>sLTL}uQ4(*UIb|Y08X8X1*a~y Q8vpPx%C`m*?RA>e5SUXO{Fc2MQMGc350wDw^pyyLSfwn+U!x^B2J5Vp8Shj$IPtO66 zwgANE5O9FqVV;p8it@3&PJx(6tHiPA&3n)GBv~Ro)B$xs9Z(0<0d+tf_`eRAQ0eR4 z-FY6HQzD+G%pBeJd)J{D`SEMry$u@kF_HN+8Smfp&z|%BP1jk|fMP$$GxG{FElJ|5 z)$P4*ag1-<#tH_oET%QaH~M>AxB#XZmqHSE4Dor42*e;37!J?Q>TkpADp-K&(4jFj za_BK4%E((xS&|Od_ncGj7xMNve4SlbevyP*65$NU(8m4ur{QBAQWbe7vvYURyR3^X z>kAeD5Ri-!QA>W%>z5I1x)&uNMnoIr!6RBgh={hxgG2Ch071p0jv&Sss|_}+UGtI4 zCZ9iv0035rKwrL8rX&ySiIxxm+)=f$rQcO5N=+WQlL-J=g$Q)DLLRt3?x67(kEAnD zwhwZqct7lNF^!kW1eB4-nwK973pdlrMI@<0Rpe1BVPTtPbmAGPBY!7#zG7o1n~8}8 zG?8};xJ?n!0({B0Eh0)lDET%;1Pj17tYIF+z8=&qr@6)D2Yhch!9HhK-h9T|F+8G^ zSn@6jHa991%B;I*G402_yW@8b79dGK95e{TzEzfqkb?W^uzk4+g<0Q!mD-?`XV^z``8gDco4hWvJNJ8aDY*hOG&(9yJh%s>}G%&!4 z1C~r;y??(QPM)^^X`Ji%KOyO6syA1!oS*!prb}e4sosB){5tMWS*N+o#OfSA>^pq= z5Whj>@;`fzTAz`ecSY>HB12<0hXMP)e-kSMjM%@0%w(?CdZUPB0RvOHSOmkf%X-}9 TnHS7~PG<0Q^>bP0l+XkKO21XN literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json index b74610d665..86a16e4e7f 100644 --- a/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json +++ b/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon_dots_horizontal_dark.png", + "filename" : "icon_options_dark.png", "scale" : "1x" }, { diff --git a/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_dots_horizontal_dark.png b/ios/StatusIm/Images.xcassets/icon_options_dark.imageset/icon_dots_horizontal_dark.png deleted file mode 100644 index 846998d7558a3c4549955df6ced0e746b64e7a32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`Z1r?;42j@; zJIR)>*?^~2w#BND>)nx4rY}Mi`wq>rF6{D)y%e=FHMwq?#^uvO`mDbI-q$oz8m>RHn03#%0xd mg=i&LFJgmP$k2F-W#2jHNXo!n~MoRsiR(!}H|kK7^S8Ce-y*gvo|NmMWWzvN*rGo>2+t* zHM2~CKfKQV*Z;eg?wy&Z#3R7Kh>j}!ncmIZ_WSU~=O3r|a%ok)DStBUYm`yknPt}6 z_S^n%OWVMB?~LN67zUTnTZ?*{>y@ z=TIj-_e8e$=A=p4nPG1x#+%G+j(6x;Z^bVCfcf|RXS!#*Johb)+~{6+F@?|Uz;<5w z2+tko?836HA9(K#G{8Mn_QLD8X_j6g$R;4yf*`njxgN@xNA-9d>3 literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/Contents.json index c675431cd9..99ebd99f46 100644 --- a/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/Contents.json +++ b/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon_dots_horizontal_gray.png", + "filename" : "icon_options_gray.png", "scale" : "1x" }, { diff --git a/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_dots_horizontal_gray.png b/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_dots_horizontal_gray.png deleted file mode 100644 index 01b2320081f207da0249810e0faad2756032b022..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`Z1Hq)42j@; zJIRo**?`BDb5+6vk-63KZtEC@o%=6M{9W=+QzC)$XY*41)rnn3e|0wQugiIT)OWEm zlac}yg>tsUY|s5&_WNUXyMS6nQqTN__3Ix0uzKsO*?;x$-v=$pJd;0J@+N(nV{)XM zbE!=jfB9+7<8IIVw4XkdyV-an#P}Rv%iNF66=$D+s6PArzs()>-OdpSZ+dFExtt## mUuqK*ypf}$0g6J@3K)5fN~F^6Ft`ET&*16m=d#Wzp$Py9FkvVF diff --git a/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_options_gray.png b/ios/StatusIm/Images.xcassets/icon_options_gray.imageset/icon_options_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..cd0f71346e86690bba1fd3bf09142c7210c53c44 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^T@U;GEFr2h6 z=Ot@5hdf6E13Jo?%&@e*^{;^qX%bYI8o%y^}dC!dJ+Ao83-d$xYx%Hy??4~OM@jWvgviI&>_m8dQ z)Qc^N&jPPy$1OH*{PN*i)oq3x0R~2NbVI9Ae$&b_&HX#_3xI*c;OXk;vd$@?2>=90 BgpmLM literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Info.plist b/ios/StatusIm/Info.plist index 2a71f7e0f5..28aac58eed 100644 --- a/ios/StatusIm/Info.plist +++ b/ios/StatusIm/Info.plist @@ -46,8 +46,8 @@ - NSMicrophoneUsageDescription - Need microphone access for Instabug and Audio Messages + NSMicrophoneUsageDescription + Need microphone access for Instabug and Audio Messages NSCameraUsageDescription We need to access your camera NSContactsUsageDescription @@ -58,6 +58,7 @@ We need to access your photo storage to give you an ability to select photos UIAppFonts + SF-UI-Text-Semibold.otf SF-UI-Text-Bold.otf SF-UI-Text-Regular.otf SF-UI-Text-Medium.otf diff --git a/package.json b/package.json index b56cea2ea1..d67c3adb00 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "react-native-qrcode": "^0.2.2", "react-native-randombytes": "^2.1.0", "react-native-share": "1.0.17", + "react-native-sortable-listview": "^0.1.1", "react-native-splash-screen": "1.0.9", "react-native-swiper": "1.5.3", "react-native-tcp": "^2.0.4", diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 5bfd5d6fc0..556f124009 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -25,8 +25,9 @@ [status-im.transactions.screen :refer [confirm]] [status-im.chats-list.screen :refer [chats-list]] [status-im.new-group.screen-public :refer [new-public-group]] - [status-im.new-group.screen-private :refer [new-group contact-group]];; TODO: confusion with names + [status-im.new-group.screen-private :refer [new-group contact-group]] [status-im.new-group.views.contact-list :refer [contact-group-list]] + [status-im.new-group.views.reorder-groups :refer [reorder-groups]] [status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.remove :refer [remove-participants]] [status-im.group-settings.screen :refer [group-settings]] @@ -114,6 +115,7 @@ :contact-list main-tabs :contact-list-search-results contacts-search-results :group-contacts contact-list + :reorder-groups reorder-groups :new-contact new-contact :qr-scanner qr-scanner :chat chat diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 2875810d98..a6ba5f302c 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -8,6 +8,9 @@ :main {:height 0 :bar-style "dark-content" :color styles/color-white} + :gray {:height 0 + :bar-style "dark-content" + :color styles/color-light-gray} :transparent {:height 20 :bar-style "light-content" :translucent? true @@ -15,6 +18,13 @@ :modal {:height 0 :bar-style "light-content" :color styles/color-black}} + :toolbar-new {:height 55 + :padding-top 18 + :padding-left 16 + :padding-right 16} + :toolbar-title-container {:padding-left 30} + :toolbar-title-center? false + :toolbar-with-search-content {:padding-left 30} :sized-text {:margin-top 0 :additional-height 0} :chat {:new-message {:border-top-color styles/color-transparent @@ -35,6 +45,12 @@ :font-size 14}}} :contacts {:subtitle {:color styles/color-gray4 :font-size 14} + :subtitle-count {:color styles/color-gray4 + :font-size 14} + :info-container {:margin-left 16} + :contact-inner-container {:height 56} + :contacts-list-container {:padding-top 8 + :padding-bottom 8} :separator {:height 0} :icon-check {:border-radius 2 :width 17 @@ -43,7 +59,43 @@ :alignItems :center :height 56 :padding-top 10 - :backgroundColor styles/color-light-gray}} + :padding-left 16 + :padding-right 14 + :backgroundColor styles/color-light-gray} + :show-all {:padding-left 72 + :height 56} + :show-all-text {:fontSize 14 + :color styles/color-blue + :letter-spacing 0.5} + :show-all-text-font :medium + :contact-container {:padding-right 16} + :name-text {:fontSize 16 + :line-height 24 + :color styles/text1-color}} + :new-group {:group-name-text {:font-size 12} + :members-text {:font-size 14} + :members-text-count {:font-size 14} + :add-text {:margin-left 16 + :letter-spacing 0.5 + :font-size 14} + :delete-group-text {:letter-spacing 0.5 + :font-size 14} + :delete-group-prompt-text {:font-size 14} + :contact-container {:height 56} + :delete-group-container {:padding-left 72}} + :reorder-groups {:order-item-container {:height 56 + :background-color styles/color-white} + :order-item-icon {:padding-right 16} + :order-item-label {:padding-left 16 + :font-size 16 + :color styles/color-black + :line-height 24} + :reorder-list-container {:padding-top 16} + :order-item-contacts {:font-size 16 + :line-height 24}} + :confirm-button-label {:color styles/color-white + :font-size 14 + :letter-spacing 0.5} :bottom-gradient {:height 3} :input-label {:left 4} :input-error-text {:margin-left 4} @@ -55,8 +107,7 @@ :toolbar-last-activity {:color styles/text2-color :background-color :transparent :top 0 - :font-size 12} - :toolbar-title-container {:padding-left 16}}) + :font-size 12}}) (def fonts {:light {:font-family "sans-serif-light"} @@ -86,11 +137,13 @@ :tabs {:tab-shadows? true} :chats {:action-button? true :new-chat-in-toolbar? false} + :uppercase? true :contacts {:action-button? true :new-contact-in-toolbar? false - :uppercase-subtitles? false :group-block-shadows? true} :discover {:uppercase-subtitles? false} :public-group-icon-container {:margin-top 4} :private-group-icon-container {:margin-top 6} + :group-chat-focus-line-color styles/color-light-blue + :group-chat-focus-line-height 2 :public-group-chat-hash-style {:top 10 :left 4}}) diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index a1c4ab5321..37f4b6d666 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -117,8 +117,8 @@ [status-bar] [toolbar {:hide-nav? (or (empty? accounts) show-actions? creating?) :custom-content [toolbar-content-view] - :custom-action [toolbar-action] - :style (get-in platform-specific [:component-styles :toolbar])}] + :style (get-in platform-specific [:component-styles :toolbar]) + :custom-action [toolbar-action]}] [add-contact-bar]]) (defn get-intro-status-message [all-messages] diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index 35bb1e1b0a..31c3666e47 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -37,8 +37,8 @@ :title (label :t/chats) :search-placeholder (label :t/search-for) :nav-action (act/hamburger open-drawer) - :actions actions - :style (st/toolbar chats-scrolled?)}])) + :style (st/toolbar chats-scrolled?) + :actions actions}])) (defn chats-action-button [] [action-button {:button-color color-blue diff --git a/src/status_im/chats_list/styles.cljs b/src/status_im/chats_list/styles.cljs index 3524c7d69b..0de3732b68 100644 --- a/src/status_im/chats_list/styles.cljs +++ b/src/status_im/chats_list/styles.cljs @@ -17,6 +17,7 @@ toolbar-background2)} (get-in p/platform-specific [:component-styles :toolbar]))) + (def gradient-top-bottom-shadow ["rgba(24, 52, 76, 0.165)" "rgba(24, 52, 76, 0.03)" diff --git a/src/status_im/commands/handlers/loading.cljs b/src/status_im/commands/handlers/loading.cljs index be3341493d..91472244f8 100644 --- a/src/status_im/commands/handlers/loading.cljs +++ b/src/status_im/commands/handlers/loading.cljs @@ -166,28 +166,3 @@ (reg-handler ::clear-commands-callbacks (fn [db [chat-id]] (assoc-in db [::commands-callbacks chat-id] nil))) - -(reg-handler :load-default-contacts! - (u/side-effect! - (fn [{:keys [chats groups]}] - (let [default-contacts js-res/default-contacts - default-dapps-group-contacts (mapv #(hash-map :identity (clojure.core/name (first %))) - (filter #(true? (:dapp? (second %))) default-contacts))] - (doseq [[id {:keys [name photo-path public-key add-chat? - dapp? dapp-url dapp-hash]}] default-contacts] - (let [id' (clojure.core/name id)] - (when-not (chats id') - (when add-chat? - (dispatch [:add-chat id' {:name (:en name)}])) - (dispatch [:add-contacts [{:whisper-identity id' - :name (:en name) - :photo-path photo-path - :public-key public-key - :dapp? dapp? - :dapp-url (:en dapp-url) - :dapp-hash dapp-hash}]])))) - (dispatch [:add-groups [{:group-id "dapps" - :name (label :t/contacts-group-dapps) - :order 0 - :timestamp (random/timestamp) - :contacts default-dapps-group-contacts}]]))))) diff --git a/src/status_im/components/chat_icon/screen.cljs b/src/status_im/components/chat_icon/screen.cljs index 4d943e4a02..95e576c848 100644 --- a/src/status_im/components/chat_icon/screen.cljs +++ b/src/status_im/components/chat_icon/screen.cljs @@ -24,15 +24,14 @@ (get resources/contacts)) {:uri photo-path})] [image {:source photo - :style (merge st/default-image-style - (st/image-style size))}])) + :style (st/image-style size)}])) -(defn dapp-badge [styles] - [view (:online-view-wrapper styles) - [view (:online-view styles) +(defn dapp-badge [{:keys [online-view-wrapper online-view online-dot-left online-dot-right]}] + [view online-view-wrapper + [view online-view [view - [view (:online-dot-left styles)] - [view (:online-dot-right styles)]]]]) + [view online-dot-left] + [view online-dot-right]]]]) (defn contact-badge [type styles] (when (= type :edit) @@ -127,19 +126,19 @@ :default-chat-icon (st/default-chat-icon-message-status color) :default-chat-icon-text st/message-status-icon-text}]) -(defn contact-icon-view [contact styles] - (let [photo-path (:photo-path contact) - ;; TODO: stub - type :online] - [view (:container styles) +(defn contact-icon-view [{:keys [photo-path name dapp?]} {:keys [container] :as styles}] + (let [photo-path photo-path] + [view container (if-not (s/blank? photo-path) [chat-icon photo-path styles] - [default-chat-icon (:name contact) styles]) - [contact-badge type styles]])) + [default-chat-icon name styles]) + (when dapp? + [dapp-badge styles])])) (defn contact-icon-contacts-tab [contact] [contact-icon-view contact {:container st/container-chat-list + :online-view-wrapper st/online-view-wrapper :online-view st/online-view :online-dot-left st/online-dot-left :online-dot-right st/online-dot-right diff --git a/src/status_im/components/chat_icon/styles.cljs b/src/status_im/components/chat_icon/styles.cljs index 9f30e1159d..de0c8248ff 100644 --- a/src/status_im/components/chat_icon/styles.cljs +++ b/src/status_im/components/chat_icon/styles.cljs @@ -89,10 +89,10 @@ (def online-view-wrapper {:position :absolute - :bottom -1 - :right 0 - :width 22 - :height 22 + :bottom -2 + :right -2 + :width 17 + :height 17 :border-radius 11 :background-color :white}) @@ -109,8 +109,8 @@ {:position :absolute :bottom 2 :right 2 - :width 18 - :height 18 + :width 13 + :height 13 :border-radius 9 :background-color online-color}) @@ -130,13 +130,13 @@ (def online-dot {:position :absolute - :top 7 - :width 4 - :height 4 + :top 5 + :width 3 + :height 3 :border-radius 2 :background-color color-white}) -(def online-dot-left (merge online-dot {:left 4})) -(def online-dot-right (merge online-dot {:left 10})) +(def online-dot-left (merge online-dot {:left 2.8})) +(def online-dot-right (merge online-dot {:left 7.2})) (def photo-pencil {:margin-left 8 @@ -172,8 +172,8 @@ :height 44}) (def container-chat-list - {:width 48 - :height 48}) + {:width 40 + :height 40}) (def container-menu-item {:width 32 diff --git a/src/status_im/components/confirm_button.cljs b/src/status_im/components/confirm_button.cljs index 799d82b36d..1becdba24d 100644 --- a/src/status_im/components/confirm_button.cljs +++ b/src/status_im/components/confirm_button.cljs @@ -1,5 +1,6 @@ (ns status-im.components.confirm-button (:require [status-im.components.styles :as st] + [status-im.utils.platform :refer [platform-specific]] [status-im.components.react :refer [view text touchable-highlight]])) @@ -7,4 +8,6 @@ (defn confirm-button [label on-press] [touchable-highlight {:on-press on-press} [view st/confirm-button - [text {:style st/confirm-button-label} label]]]) \ No newline at end of file + [text {:style (get-in platform-specific [:component-styles :confirm-button-label]) + :uppercase? (get-in platform-specific [:uppercase?])} + label]]]) \ No newline at end of file diff --git a/src/status_im/components/context_menu.cljs b/src/status_im/components/context_menu.cljs index 293eedad60..3719b3c88d 100644 --- a/src/status_im/components/context_menu.cljs +++ b/src/status_im/components/context_menu.cljs @@ -4,7 +4,7 @@ [status-im.i18n :refer [label]] [status-im.utils.platform :refer [platform-specific ios?]] [re-frame.core :refer [dispatch]] - [status-im.components.react :refer [view touchable-highlight]])) + [status-im.components.react :refer [view touchable-highlight text]])) (def react-native-popup-menu (js/require "react-native-popup-menu")) @@ -43,7 +43,9 @@ trigger]] [menu {:onSelect #(when % (do (%) nil))} [menu-trigger trigger] - [menu-options st/context-menu - (for [option options] + [menu-options st/context-menu-options + (for [{:keys [style value] :as option} options] ^{:key option} - [menu-option option])]])) \ No newline at end of file + [menu-option {:value value} + [text {:style (merge st/context-menu-text style)} + (:text option)]])]])) \ No newline at end of file diff --git a/src/status_im/components/sortable_list_view.cljs b/src/status_im/components/sortable_list_view.cljs new file mode 100644 index 0000000000..bda52af1b4 --- /dev/null +++ b/src/status_im/components/sortable_list_view.cljs @@ -0,0 +1,20 @@ +(ns status-im.components.sortable-list-view + (:require [reagent.core :as r] + [status-im.components.react :refer [view + touchable-highlight + list-item]])) + +(def sortable-list-view-class (r/adapt-react-class (js/require "react-native-sortable-listview"))) + +(defn sortable-list-view [{:keys [on-row-moved render-row] :as props}] + [sortable-list-view-class + (assoc props :on-row-moved #(on-row-moved (js->clj % :keywordize-keys true)) + :render-row #(render-row (js->clj % :keywordize-keys true)))]) + +(defn touchable [inner] + [touchable-highlight (js->clj (.-props (r/current-component))) + [view + inner]]) + +(defn sortable-item [inner] + (list-item [touchable inner])) \ No newline at end of file diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index f0df443e8e..9c04928129 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -3,7 +3,7 @@ (def color-transparent "transparent") (def color-blue "#7099e6") (def color-blue-transparent "#7099e632") -(def color-black "#000000de") +(def color-black "#000000") (def color-purple "#a187d5") (def color-gray "#838c93de") (def color-gray2 "#8f838c93") @@ -24,12 +24,12 @@ (def text1-disabled-color "#555555") (def text2-color color-gray) (def text3-color color-blue) -(def online-color color-blue) +(def online-color color-light-blue) (def new-messages-count-color color-blue-transparent) (def chat-background color-light-gray) (def selected-message-color "#E4E9ED") (def selected-contact-color color-light-blue2) -(def separator-color color-gray4) +(def separator-color "#0000001f") (def default-chat-color color-purple) (def flex @@ -45,8 +45,8 @@ :color :white}) (def icon-back - {:width 24 - :height 24}) + {:width 8 + :height 14}) (def icon-default {:width 24 @@ -96,17 +96,18 @@ :align-items :center :background-color color-light-blue}) -(def confirm-button-label - {:color color-white - :font-size 17 - :line-height 20 - :letter-spacing -0.2}) - -(def context-menu - {:customStyles {:optionsContainer {:padding-top 8 +(def context-menu-options + {:customStyles {:optionsContainer {:elevation 2 + :margin-top 30 + :padding-top 8 + :width 164 :padding-bottom 8} - :optionWrapper {:padding-left 16 + :optionWrapper {:padding-left 16 + :padding-right 16 :justify-content :center - :height 48} - :text {:font-size 15 - :line-height 20}}}) + :height 48}}}) + +(def context-menu-text + {:font-size 15 + :line-height 20 + :color text1-color}) diff --git a/src/status_im/components/text_field/styles.cljs b/src/status_im/components/text_field/styles.cljs index 99f8a8ae71..abe1148428 100644 --- a/src/status_im/components/text_field/styles.cljs +++ b/src/status_im/components/text_field/styles.cljs @@ -29,12 +29,11 @@ (defn underline-container [background-color] {:background-color background-color - :height 1 :align-items :center}) -(defn underline [background-color width] +(defn underline [background-color width height] {:background-color background-color - :height 1 + :height height :width width}) (defn error-text [color] diff --git a/src/status_im/components/text_field/view.cljs b/src/status_im/components/text_field/view.cljs index 6fcab178ab..b1ba7ae6a7 100644 --- a/src/status_im/components/text_field/view.cljs +++ b/src/status_im/components/text_field/view.cljs @@ -29,6 +29,7 @@ :label-color "#838c93" :line-color separator-color :focus-line-color separator-color + :focus-line-height 1 :error-color "#d50000" :secure-text-entry false :on-focus #() @@ -38,14 +39,16 @@ :auto-capitalize :sentences}) (defn field-animation [{:keys [top to-top font-size to-font-size - line-width to-line-width]}] + line-width to-line-width line-height to-line-height]}] (let [duration (:label-animation-duration config) animation (anim/parallel [(anim/timing top {:toValue to-top :duration duration}) (anim/timing font-size {:toValue to-font-size :duration duration}) (anim/timing line-width {:toValue to-line-width - :duration duration})])] + :duration duration}) + (anim/timing line-height {:toValue to-line-height + :duration duration})])] (anim/start animation (fn [arg] (when (.-finished arg) (log/debug "Field animation finished")))))) @@ -58,6 +61,7 @@ :label-top 0 :label-font-size 0 :line-width (anim/create-value 0) + :line-height (anim/create-value 1) :max-line-width 100}) ; Invoked once, both on the client and server, immediately before the initial @@ -80,7 +84,8 @@ (log/debug "input focused") (r/set-state component {:has-focus true :float-label? true}) - (field-animation animation) + (field-animation (merge animation + {:to-line-width (:max-line-width (r/state component))})) (when onFocus (onFocus)))) (defn on-input-blur [{:keys [component value animation onBlur]}] @@ -101,14 +106,14 @@ label-top label-font-size line-width + line-height current-value - max-line-width valid-value temp-value max-length]} (r/state component) - {:keys [wrapper-style input-style label-hidden? line-color focus-line-color secure-text-entry - label-color error-color error label value on-focus on-blur validator auto-focus - on-change-text on-change on-end-editing editable placeholder auto-capitalize]} + {:keys [wrapper-style input-style label-hidden? line-color focus-line-color focus-line-height + secure-text-entry label-color error-color error label value on-focus on-blur validator + auto-focus on-change-text on-change on-end-editing editable placeholder auto-capitalize]} (merge default-props (r/props component)) line-color (if error error-color line-color) focus-line-color (if error error-color focus-line-color) @@ -125,21 +130,24 @@ :secure-text-entry secure-text-entry :auto-capitalize auto-capitalize :on-focus #(on-input-focus {:component component - :animation {:top label-top - :to-top (:label-top config) - :font-size label-font-size - :to-font-size (:label-font-small config) - :line-width line-width - :to-line-width max-line-width} + :animation {:top label-top + :to-top (:label-top config) + :font-size label-font-size + :to-font-size (:label-font-small config) + :line-width line-width + :line-height line-height + :to-line-height focus-line-height} :onFocus on-focus}) :on-blur #(on-input-blur {:component component :value (or current-value value) - :animation {:top label-top - :to-top (:label-bottom config) - :font-size label-font-size - :to-font-size (:label-font-large config) - :line-width line-width - :to-line-width 0} + :animation {:top label-top + :to-top (:label-bottom config) + :font-size label-font-size + :to-font-size (:label-font-large config) + :line-width line-width + :line-height line-height + :to-line-width 0 + :to-line-height 1} :onBlur on-blur}) :on-change-text (fn [text] (r/set-state component {:current-value text}) @@ -159,7 +167,7 @@ :auto-focus (true? auto-focus)}] [view {:style (st/underline-container line-color) :onLayout #(r/set-state component {:max-line-width (get-width %)})} - [animated-view {:style (st/underline focus-line-color line-width)}]] + [animated-view {:style (st/underline focus-line-color line-width line-height)}]] [text {:style (st/error-text error-color)} error]])) (defn text-field [_ _] diff --git a/src/status_im/components/toolbar/actions.cljs b/src/status_im/components/toolbar/actions.cljs index ecf66d40e1..e778f8646e 100644 --- a/src/status_im/components/toolbar/actions.cljs +++ b/src/status_im/components/toolbar/actions.cljs @@ -3,34 +3,29 @@ (def nothing {:image {:source nil - :style st/action-default}}) + :style st/action-search}}) (defn hamburger [handler] - {:image {:source {:uri :icon_hamburger_dark} - :style st/action-default} + {:image {:source {:uri :icon_hamburger} + :style st/action-hamburger} :handler handler}) (defn add [handler] {:image {:source {:uri :icon_add} - :style st/action-default} - :handler handler}) - -(defn opts [handler] - {:image {:source {:uri :icon_options_dark} - :style st/action-default} + :style st/action-add} :handler handler}) (defn search [handler] - {:image {:source {:uri :icon_search_dark} - :style st/action-default} + {:image {:source {:uri :icon_search} + :style st/action-search} :handler handler}) (defn back [handler] {:image {:source {:uri :icon_back_dark} - :style st/action-default} + :style st/action-back} :handler handler}) (defn back-white [handler] {:image {:source {:uri :icon_back_white} - :style st/action-default} - :handler handler}) + :style st/action-back} + :handler handler}) \ No newline at end of file diff --git a/src/status_im/components/toolbar/styles.cljs b/src/status_im/components/toolbar/styles.cljs index eabc5fce60..b111d3acb4 100644 --- a/src/status_im/components/toolbar/styles.cljs +++ b/src/status_im/components/toolbar/styles.cljs @@ -2,17 +2,15 @@ (:require [status-im.components.styles :refer [text1-color color-white color-light-gray - color-gray5 color-blue - color-black]] - [status-im.utils.platform :as p])) + color-black]])) (def toolbar-background1 color-white) (def toolbar-background2 color-light-gray) (def toolbar-height 56) -(def toolbar-icon-width 24) -(def toolbar-icon-spacing 24) +(def toolbar-icon-width 32) +(def toolbar-icon-spacing 8) (def toolbar-gradient {:height 4}) @@ -25,11 +23,6 @@ {:flex-direction :row :height toolbar-height}) -(def toolbar-line - {:height 1 - :background-color color-gray5 - :opacity 0.4}) - (defn toolbar-nav-actions-container [actions] {:width (when (and actions (> (count actions) 0)) (-> (+ toolbar-icon-width toolbar-icon-spacing) @@ -45,9 +38,9 @@ :padding-right 12}) (def toolbar-title-container - (merge (get-in p/platform-specific [:component-styles :toolbar-title-container]) - {:flex 1 - :justifyContent :center})) + {:flex 1 + :alignItems :center + :justifyContent :center}) (def toolbar-title-text {:margin-top 0 @@ -68,11 +61,12 @@ :justify-content :center}) (def toolbar-with-search - {:background-color toolbar-background1 + {:background-color toolbar-background2 :elevation 0}) (def toolbar-with-search-content {:flex 1 + :align-items :center :justify-content :center}) (def toolbar-search-input @@ -85,8 +79,25 @@ (def toolbar-with-search-title {:color color-black + :align-self :center + :text-align :center :font-size 16}) -(def action-default + +;; Specific actions + +(def action-hamburger + {:width 16 + :height 12}) + +(def action-add + {:width 17 + :height 17}) + +(def action-search + {:width 17 + :height 17}) + +(def action-back {:width 24 :height 24}) diff --git a/src/status_im/components/toolbar/view.cljs b/src/status_im/components/toolbar/view.cljs index 9210c9c735..bb6778bec2 100644 --- a/src/status_im/components/toolbar/view.cljs +++ b/src/status_im/components/toolbar/view.cljs @@ -7,7 +7,7 @@ image touchable-highlight]] [status-im.components.sync-state.gradient :refer [sync-state-gradient-view]] - [status-im.components.styles :refer [icon-default + [status-im.components.styles :refer [icon-back icon-search]] [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :as st] @@ -34,8 +34,8 @@ [touchable-highlight {:on-press #(dispatch [:navigate-back]) :accessibility-label id/toolbar-back-button} [view (get-in platform-specific [:component-styles :toolbar-nav-action]) - [image {:source {:uri :icon_back_dark} - :style icon-default}]]]))] + [image {:source {:uri :icon_back} + :style icon-back}]]]))] (or custom-content [view {:style st/toolbar-title-container} [text {:style st/toolbar-title-text @@ -50,8 +50,7 @@ [view st/toolbar-action [image action-image]]]) custom-action)]] - [sync-state-gradient-view] - [view st/toolbar-line]])) + [sync-state-gradient-view]])) (defn- toolbar-search-submit [on-search-submit] (let [text @(subscribe [:get-in [:toolbar-search :text]])] @@ -68,7 +67,10 @@ {:style st/toolbar-search-input :auto-focus true :placeholder search-placeholder - :on-change-text #(dispatch [:set-in [:toolbar-search :text] %])}] + :return-key-type "search" + :on-blur #(dispatch [:set-in [:toolbar-search :show] nil]) + :on-change-text #(dispatch [:set-in [:toolbar-search :text] %]) + :on-submit-editing #(toolbar-search-submit on-search-submit)}] [view [text {:style st/toolbar-with-search-title :font :toolbar-title} @@ -81,11 +83,9 @@ style on-search-submit] :as opts}] - (let [toggle-search-fn #(do - (dispatch [:set-in [:toolbar-search :show] %]) - (dispatch [:set-in [:toolbar-search :text] ""])) + (let [toggle-search-fn #(dispatch [:set-in [:toolbar-search :show] %]) actions (if-not show-search? - (into [(act/search #(toggle-search-fn search-key))] actions))] + (into actions [(act/search #(toggle-search-fn search-key))]))] [toolbar {:style (merge st/toolbar-with-search style) :nav-action (if show-search? (act/back #(toggle-search-fn nil)) diff --git a/src/status_im/components/toolbar_new/actions.cljs b/src/status_im/components/toolbar_new/actions.cljs new file mode 100644 index 0000000000..7153620901 --- /dev/null +++ b/src/status_im/components/toolbar_new/actions.cljs @@ -0,0 +1,47 @@ +(ns status-im.components.toolbar-new.actions + (:require [status-im.components.toolbar-new.styles :as st])) + +(def nothing + {:image {:source nil + :style st/action-default}}) + +(defn hamburger [handler] + {:image {:source {:uri :icon_hamburger_dark} + :style st/action-default} + :handler handler}) + +(defn add [handler] + {:image {:source {:uri :icon_add} + :style st/action-default} + :handler handler}) + +(defn opts [options] + {:image {:source {:uri :icon_options_dark} + :style st/action-default} + :options options}) + +(defn search [handler] + {:image {:source {:uri :icon_search_dark} + :style st/action-default} + :handler handler}) + +(defn search-icon [] + {:image {:source {:uri :icon_search_dark} + :style (merge st/action-default + {:opacity 0.4})}}) + +(defn back [handler] + {:image {:source {:uri :icon_back_dark} + :style st/action-default} + :handler handler}) + +(defn back-white [handler] + {:image {:source {:uri :icon_back_white} + :style st/action-default} + :handler handler}) + +(defn close [handler] + {:image {:source {:uri :icon_close_dark} + :style st/action-default} + :handler handler}) + diff --git a/src/status_im/components/toolbar_new/styles.cljs b/src/status_im/components/toolbar_new/styles.cljs new file mode 100644 index 0000000000..f56874efdb --- /dev/null +++ b/src/status_im/components/toolbar_new/styles.cljs @@ -0,0 +1,82 @@ +(ns status-im.components.toolbar-new.styles + (:require [status-im.components.styles :refer [text1-color + color-white + color-light-gray + color-gray5 + color-blue + color-black]] + [status-im.utils.platform :as p])) + +(def toolbar-background1 color-white) + +(def toolbar-icon-width 24) +(def toolbar-icon-height 24) +(def toolbar-icon-spacing 24) + +(def toolbar-gradient + {:height 4}) + +(defn toolbar-wrapper [background-color] + {:backgroundColor (or background-color toolbar-background1) + :elevation 2}) + +(def toolbar + (merge {:flex-direction :row} + (get-in p/platform-specific [:component-styles :toolbar-new]))) + +(defn toolbar-nav-actions-container [actions] + (let [center? (get-in p/platform-specific [:component-styles :toolbar-title-center?])] + (merge {:flex-direction :row} + (when center? + {:width (when (and actions (pos? (count actions))) + (-> (+ toolbar-icon-width toolbar-icon-spacing) + (* (count actions))))})))) + +(def toolbar-title-container + (merge (get-in p/platform-specific [:component-styles :toolbar-title-container]) + {:flex 1 + :align-self :stretch})) + +(def toolbar-title-text + {:color text1-color + :letter-spacing -0.2 + :font-size 17}) + +(def toolbar-border-container + (get-in p/platform-specific [:component-styles :toolbar-border-container])) + +(def toolbar-border + (get-in p/platform-specific [:component-styles :toolbar-border])) + +(defn toolbar-actions-container [actions-count custom] + (merge {:flex-direction :row} + (when (and (zero? actions-count) (not custom)) + {:width (+ toolbar-icon-width toolbar-icon-spacing)}))) + +(def toolbar-action + {:width toolbar-icon-width + :height toolbar-icon-height + :margin-left toolbar-icon-spacing + :align-items :center + :justify-content :center}) + +(def toolbar-with-search + {:background-color toolbar-background1}) + +(def toolbar-with-search-content + (merge (get-in p/platform-specific [:component-styles :toolbar-with-search-content]) + {:flex 1})) + +(def toolbar-search-input + (merge (get-in p/platform-specific [:component-styles :toolbar-search-input]) + {:flex 1 + :padding-bottom 10 + :font-size 17 + :padding-top 0 + :align-self :stretch + :color color-black})) + +(def action-default + {:width 24 + :height 24}) + diff --git a/src/status_im/components/toolbar_new/view.cljs b/src/status_im/components/toolbar_new/view.cljs new file mode 100644 index 0000000000..885afbe5f9 --- /dev/null +++ b/src/status_im/components/toolbar_new/view.cljs @@ -0,0 +1,114 @@ +(ns status-im.components.toolbar-new.view + (:require [re-frame.core :refer [subscribe dispatch]] + [status-im.components.react :refer [view + icon + text + text-input + image + touchable-highlight]] + [status-im.components.sync-state.gradient :refer [sync-state-gradient-view]] + [status-im.components.styles :refer [icon-default + icon-search]] + [status-im.components.context-menu :refer [context-menu]] + [status-im.components.toolbar-new.actions :as act] + [status-im.components.toolbar-new.styles :as st] + [status-im.accessibility-ids :as id] + [status-im.utils.platform :refer [platform-specific]] + [reagent.core :as r])) + +(defn toolbar [{title :title + nav-action :nav-action + hide-nav? :hide-nav? + actions :actions + custom-action :custom-action + background-color :background-color + custom-content :custom-content + style :style}] + (let [style (merge (st/toolbar-wrapper background-color) style)] + [view {:style style} + [view st/toolbar + [view (st/toolbar-nav-actions-container actions) + (when-not hide-nav? + (if nav-action + [touchable-highlight {:on-press (:handler nav-action)} + [view + [image (:image nav-action)]]] + [touchable-highlight {:on-press #(dispatch [:navigate-back]) + :accessibility-label id/toolbar-back-button} + [view + [image {:source {:uri :icon_back_dark} + :style icon-default}]]]))] + (or custom-content + [view {:style st/toolbar-title-container} + [text {:style st/toolbar-title-text + :font :toolbar-title} + title]]) + [view (st/toolbar-actions-container (count actions) custom-action) + (if actions + (for [{action-image :image + action-options :options + action-handler :handler} actions] + (with-meta + (cond (= action-image :blank) + [view st/toolbar-action] + action-options + [context-menu + [view st/toolbar-action + [image action-image]] + action-options] + :else + [touchable-highlight {:on-press action-handler} + [view st/toolbar-action + [image action-image]]]) + {:key (str "action-" action-image)})) + custom-action)]] + [sync-state-gradient-view] + [view st/toolbar-border-container + [view st/toolbar-border]]])) + +(def search-text-input (r/atom nil)) + +(defn- toolbar-with-search-content [{:keys [show-search? + search-placeholder + title + custom-title + on-search-submit]}] + [view st/toolbar-with-search-content + (if show-search? + [text-input + {:style st/toolbar-search-input + :ref #(reset! search-text-input %) + :auto-focus true + :placeholder search-placeholder + :on-change-text #(dispatch [:set-in [:toolbar-search :text] %])}] + (or custom-title + [view + [text {:style st/toolbar-title-text + :font :toolbar-title} + title]]))]) + +(defn toolbar-with-search [{:keys [show-search? + search-text + search-key + nav-action + actions + style + on-search-submit] + :as opts}] + (let [toggle-search-fn #(do + (dispatch [:set-in [:toolbar-search :show] %]) + (dispatch [:set-in [:toolbar-search :text] ""])) + actions (if show-search? + (if (pos? (count search-text)) + [(act/close #(do + (.clear @search-text-input) + (dispatch [:set-in [:toolbar-search :text] ""])))] + [(act/search-icon)]) + (into [(act/search #(toggle-search-fn search-key))] actions))] + [toolbar {:style style + :nav-action (if show-search? + (act/back #(toggle-search-fn nil)) + nav-action) + :custom-content [toolbar-with-search-content opts] + :actions actions}])) + diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index 5a6284e9e0..e61557dde7 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -46,8 +46,16 @@ [db [_ _ click-handler]] (-> db (assoc-in [:toolbar-search :show] nil) + (assoc-in [:contact-list-ui-props :edit?] false) (assoc :contacts-click-handler click-handler))) +(defmethod nav/preload-data! :reorder-groups + [db [_ _]] + (assoc db :groups-order (->> (vals (:contact-groups db)) + (remove :pending?) + (sort-by :order >) + (map :group-id)))) + (register-handler :remove-contacts-click-handler (fn [db] (dissoc db @@ -208,21 +216,29 @@ (register-handler :load-default-contacts! (u/side-effect! - (fn [{:keys [chats]}] - (doseq [[id {:keys [name photo-path public-key add-chat? - dapp? dapp-url dapp-hash]}] js-res/default-contacts] - (let [id' (clojure.core/name id)] - (when-not (chats id') - (when add-chat? - (dispatch [:add-chat id' {:name (:en name)}])) - (dispatch [:add-contacts [{:whisper-identity id' - :address (public-key->address id') - :name (:en name) - :photo-path photo-path - :public-key public-key - :dapp? dapp? - :dapp-url (:en dapp-url) - :dapp-hash dapp-hash}]]))))))) + (fn [{:keys [chats groups]}] + (let [default-contacts js-res/default-contacts + default-dapps-group-contacts (mapv #(hash-map :identity (clojure.core/name (first %))) + (filter #(true? (:dapp? (second %))) default-contacts))] + (doseq [[id {:keys [name photo-path public-key add-chat? + dapp? dapp-url dapp-hash]}] default-contacts] + (let [id' (clojure.core/name id)] + (when-not (chats id') + (when add-chat? + (dispatch [:add-chat id' {:name (:en name)}])) + (dispatch [:add-contacts [{:whisper-identity id' + :address (public-key->address id') + :name (:en name) + :photo-path photo-path + :public-key public-key + :dapp? dapp? + :dapp-url (:en dapp-url) + :dapp-hash dapp-hash}]])))) + (dispatch [:add-groups [{:group-id "dapps" + :name (label :t/contacts-group-dapps) + :order 0 + :timestamp (random/timestamp) + :contacts default-dapps-group-contacts}]]))))) (register-handler :add-contacts (after save-contacts!) @@ -326,8 +342,8 @@ (register-handler :remove-contact-from-group (u/side-effect! - (fn [_ [_ {:keys [whisper-identity]} group]] - (let [group' (update group :contacts (remove-contact-from-group whisper-identity))] + (fn [{:keys [contact-groups]} [_ {:keys [whisper-identity]} {:keys [group-id]}]] + (let [group' (update (contact-groups group-id) :contacts (remove-contact-from-group whisper-identity))] (dispatch [:update-group group']))))) (register-handler :remove-contact diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index f56dc110af..099cfe729a 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -15,9 +15,9 @@ [status-im.components.action-button :refer [action-button action-button-item]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar-with-search toolbar]] - [status-im.components.toolbar.actions :as act] - [status-im.components.toolbar.styles :as tst] + [status-im.components.toolbar-new.view :refer [toolbar]] + [status-im.components.toolbar-new.actions :as act] + [status-im.components.toolbar-new.styles :as tst] [status-im.components.drawer.view :refer [open-drawer]] [status-im.components.icons.custom-icons :refer [ion-icon]] [status-im.components.context-menu :refer [context-menu]] @@ -31,31 +31,24 @@ (def contacts-limit 5) (def toolbar-options - [{:text (label :t/new-contact) :value #(dispatch [:navigate-to :new-contact])} - {:text (label :t/edit) :value #(dispatch [:set-in [:contacts-ui-props :edit?] true])} - {:text (label :t/new-group) :value #(dispatch [:open-contact-group-list])}]) + [{:text (label :t/new-contact) :value #(dispatch [:navigate-to :new-contact])} + {:text (label :t/edit) :value #(dispatch [:set-in [:contacts-ui-props :edit?] true])} + {:text (label :t/new-group) :value #(dispatch [:open-contact-group-list])} + {:text (label :t/reorder-groups) :value #(dispatch [:navigate-to :reorder-groups])}]) (defn toolbar-actions [] (let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?])] - [view st/toolbar-actions - [touchable-highlight - {:on-press #(dispatch [:navigate-to :group-contacts nil :show-search])} - [view st/search-btn - [icon :search_dark]]] - [view st/more-btn - [context-menu - [icon :options_dark] - (if new-contact? toolbar-options (rest toolbar-options))]]])) + [(act/search #(dispatch [:navigate-to :group-contacts nil :show-search])) + (act/opts (if new-contact? toolbar-options (rest toolbar-options)))])) (defn toolbar-view [] - [toolbar {:style tst/toolbar-with-search - :title (label :t/contacts) + [toolbar {:title (label :t/contacts) :nav-action (act/hamburger open-drawer) - :custom-action (toolbar-actions)}]) + :actions (toolbar-actions)}]) (defn toolbar-edit [] - [toolbar {:style tst/toolbar-with-search - :nav-action (act/back #(dispatch [:set-in [:contacts-ui-props :edit?] false])) + [toolbar {:nav-action (act/back #(dispatch [:set-in [:contacts-ui-props :edit?] false])) + :actions [{:image :blank}] :title (label :t/edit-contacts)}]) (defn options-btn [group] @@ -67,16 +60,15 @@ (defn subtitle-view [subtitle contacts-count group extended?] [view (get-in platform-specific [:component-styles :contacts :group-header]) - [text {:style (merge st/contact-group-subtitle - (get-in platform-specific [:component-styles :contacts :subtitle])) - :uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?]) + [text {:style (get-in platform-specific [:component-styles :contacts :subtitle]) :font :medium} subtitle] [text {:style (merge st/contact-group-count - (get-in platform-specific [:component-styles :contacts :subtitle])) + (get-in platform-specific [:component-styles :contacts :subtitle-count])) :uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?]) :font :medium} (str contacts-count)] + [view {:flex 1}] (when extended? [options-btn group])]) @@ -88,10 +80,6 @@ [linear-gradient {:style st/contact-group-header-gradient-top :colors st/contact-group-header-gradient-top-colors}]) -(defn on-scroll-animation [e show-toolbar-shadow?] - (let [offset (.. e -nativeEvent -contentOffset -y)] - (reset! show-toolbar-shadow? (pos? offset)))) - (defn contact-group-form [{:keys [contacts contacts-count group edit? click-handler]}] (let [shadows? (get-in platform-specific [:contacts :group-block-shadows?]) subtitle (:name group)] @@ -100,27 +88,36 @@ [subtitle-view subtitle contacts-count group edit?]) (when (and subtitle shadows?) [group-top-view]) - [view + [view st/contacts-list (doall (map (fn [contact] ^{:key contact} - [contact-view - {:contact contact - :extended? edit? - :on-click (when-not edit? click-handler) - :extend-options (when group - [{:value #(dispatch [:hide-contact contact]) - :text (label :t/delete-contact)} - {:value #(dispatch [:remove-contact-from-group contact group]) - :text (label :t/remove-from-group)}])}]) + [view + [contact-view + {:contact contact + :extended? edit? + :on-click (when-not edit? click-handler) + :extend-options (when group + [{:value #(dispatch [:hide-contact contact]) + :text (label :t/delete-contact) + :style st/delete-contact-text} + {:value #(dispatch [:remove-contact-from-group contact group]) + :text (label :t/remove-from-group)}])}] + (when-not (= contact (last contacts)) + [view st/contact-item-separator-wrapper + [view st/contact-item-separator]])]) contacts))] (when (< contacts-limit contacts-count) - [view st/show-all - [touchable-highlight (when-not edit? {:on-press #(dispatch [:navigate-to :group-contacts group])}) - [view - [text {:style st/show-all-text - :font :medium} - (str (- contacts-count contacts-limit) " " (label :t/more))]]]]) + [view + [view st/contact-item-separator-wrapper + [view st/contact-item-separator]] + [view st/show-all + [touchable-highlight (when-not edit? {:on-press #(dispatch [:navigate-to :group-contacts group])}) + [view + [text {:style st/show-all-text + :uppercase? (get-in platform-specific [:uppercase?]) + :font (get-in platform-specific [:component-styles :contacts :show-all-text-font])} + (str (- contacts-count contacts-limit) " " (label :t/more))]]]]]) (when shadows? [group-bottom-view])])) @@ -148,18 +145,13 @@ contacts-count [:added-contacts-count] click-handler [:get :contacts-click-handler] edit? [:get-in [:contacts-ui-props :edit?]] - groups [:all-added-groups] - show-toolbar-shadow? (r/atom false)] + groups [:all-added-groups]] [view st/contacts-list-container (if edit? [toolbar-edit] [toolbar-view]) - (when @show-toolbar-shadow? - [linear-gradient {:style st/contact-group-header-gradient-bottom - :colors st/contact-group-header-gradient-bottom-colors}]) (if (pos? (+ (count groups) contacts-count)) - [scroll-view {:style st/contact-groups - :onScroll #(on-scroll-animation % show-toolbar-shadow?)} + [scroll-view {:style st/contact-groups} (when (pos? contacts-count) [contact-group-form {:contacts contacts :contacts-count contacts-count diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index b3841b33b2..c7fbd79ddc 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -5,16 +5,15 @@ color-white color-separator color-gray2 + color-gray4 + color-blue + color-light-red color-gray]] [status-im.components.toolbar.styles :refer [toolbar-background1 toolbar-background2]] [status-im.utils.platform :as p])) ;; Contacts list -(def toolbar-shadow - {:height 2 - :background-color toolbar-background2}) - (def toolbar-actions {:flex-direction :row}) @@ -26,6 +25,10 @@ (merge (get-in p/platform-specific [:component-styles :main-tab-list]) {:flex 1})) +(def contacts-list + (merge (get-in p/platform-specific [:component-styles :contacts :contacts-list-container]) + {:background-color color-white})) + (def empty-contact-groups (merge contact-groups {:align-items :center @@ -40,18 +43,11 @@ :font-size 16 :color color-gray2}) -(def contacts-list - {:backgroundColor color-white}) - (def contact-group {:flex-direction :column}) -(def contact-group-subtitle - {:margin-left 16}) - (def contact-group-count - {:flex 1 - :margin-left 8 + {:margin-left 8 :opacity 0.6}) (def contact-group-header-gradient-top @@ -74,24 +70,25 @@ "rgba(24, 52, 76, 0.05)"]) (def show-all - {:flexDirection :row - :alignItems :center - :height 56 - :backgroundColor color-white}) + (merge (get-in p/platform-specific [:component-styles :contacts :show-all]) + {:flexDirection :row + :alignItems :center + :backgroundColor color-white})) (def show-all-text - {:marginLeft 72 - :fontSize 14 - :color text3-color - ;; ios only: - :letterSpacing 0.5}) + (get-in p/platform-specific [:component-styles :contacts :show-all-text])) -(def contact-separator-container +(def contact-item-separator-wrapper {:background-color color-white}) +(def contact-item-separator + (get-in p/platform-specific [:component-styles :contacts :separator])) + (def contact-container - {:flex-direction :row - :background-color color-white}) + (merge (get-in p/platform-specific [:component-styles :contacts :contact-container]) + {:flex-direction :row + :align-items :center + :background-color color-white})) (def letter-container {:paddingTop 11 @@ -102,10 +99,6 @@ {:fontSize 24 :color text3-color}) -(def contact-photo-container - {:marginTop 4 - :marginLeft 12}) - (def option-inner-container {:flex 1 :flex-direction :row @@ -139,21 +132,20 @@ :height 8}) (def contact-inner-container - {:flex 1 - :flexDirection :row - :height 56 - :margin-right 16 - :backgroundColor color-white}) + (merge (get-in p/platform-specific [:component-styles :contacts :contact-inner-container]) + {:flex 1 + :flexDirection :row + :align-items :center + :padding-left 16 + :backgroundColor color-white})) (def info-container - {:flex 1 - :flexDirection :column - :margin-left 12 - :justifyContent :center}) + (merge (get-in p/platform-specific [:component-styles :contacts :info-container]) + {:flex 1 + :flexDirection :column})) (def name-text - {:fontSize 15 - :color text1-color}) + (get-in p/platform-specific [:component-styles :contacts :name-text])) (def info-text {:marginTop 1 @@ -162,8 +154,7 @@ (def more-btn {:width 24 - :height 56 - :margin-right 14 + :height 24 :alignItems :center :justifyContent :center}) @@ -231,3 +222,6 @@ :background-color color-white :align-items :center :justify-content :center}) + +(def delete-contact-text + {:color color-light-red}) \ No newline at end of file diff --git a/src/status_im/contacts/subs.cljs b/src/status_im/contacts/subs.cljs index 6d34d6fa9e..64ad06d2fe 100644 --- a/src/status_im/contacts/subs.cljs +++ b/src/status_im/contacts/subs.cljs @@ -30,12 +30,15 @@ (sort-contacts) (reaction))))) +(defn filter-group-contacts [group-contacts contacts] + (filter #(group-contacts (:whisper-identity %)) contacts)) + (register-sub :all-added-group-contacts (fn [db [_ group-id]] (let [contacts (subscribe [:all-added-contacts]) group-contacts (reaction (into #{} (map #(:identity %) (get-in @db [:contact-groups group-id :contacts]))))] - (reaction (filter #(@group-contacts (:whisper-identity %)) @contacts))))) + (reaction (filter-group-contacts @group-contacts @contacts))))) (register-sub :all-added-group-contacts-with-limit (fn [db [_ group-id limit]] diff --git a/src/status_im/contacts/views/contact.cljs b/src/status_im/contacts/views/contact.cljs index 67cc593ae9..7f319d9129 100644 --- a/src/status_im/contacts/views/contact.cljs +++ b/src/status_im/contacts/views/contact.cljs @@ -18,7 +18,8 @@ [text {:style st/letter-text} letter])]) (defn options-btn [contact more-options] - (let [options [{:value #(dispatch [:hide-contact contact]) :text (label :t/delete-contact)}]] + (let [options [{:value #(dispatch [:hide-contact contact]) :text (label :t/delete-contact) + :style st/delete-contact-text}]] [view st/more-btn [context-menu [icon :options_gray] @@ -26,7 +27,7 @@ ;;TODO: maybe it's better to have only one global component contact-view with the types: default, extended and toggle ;;TODO: at the moment toggle in the other component new-group-contact -(defview contact-view [{{:keys [whisper-identity letter dapp?] :as contact} :contact +(defview contact-view [{{:keys [whisper-identity letter] :as contact} :contact :keys [extended? letter? on-click extend-options info]}] [chat [:get-chat whisper-identity]] [touchable-highlight @@ -38,6 +39,4 @@ [letter-view letter]) [contact-inner-view {:contact contact :info info}] (when extended? - [options-btn contact extend-options])] - [view st/contact-separator-container - [view (get-in platform-specific [:component-styles :contacts :separator])]]]]) + [options-btn contact extend-options])]]]) diff --git a/src/status_im/contacts/views/contact_inner.cljs b/src/status_im/contacts/views/contact_inner.cljs index df185d5310..752c7a3752 100644 --- a/src/status_im/contacts/views/contact_inner.cljs +++ b/src/status_im/contacts/views/contact_inner.cljs @@ -6,7 +6,7 @@ [status-im.i18n :refer [get-contact-translated label]])) (defn contact-photo [contact] - [view st/contact-photo-container + [view [contact-icon-contacts-tab contact]]) (defn contact-inner-view diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index 0025f6c045..61779192f1 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -3,15 +3,16 @@ (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] [status-im.components.react :refer [view text image + icon touchable-highlight list-view list-item]] [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.text-field.view :refer [text-field]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar-with-search toolbar]] - [status-im.components.toolbar.actions :as act] - [status-im.components.toolbar.styles :refer [toolbar-background1]] + [status-im.components.toolbar-new.view :refer [toolbar-with-search toolbar]] + [status-im.components.toolbar-new.actions :as act] + [status-im.components.toolbar-new.styles :refer [toolbar-background1]] [status-im.components.drawer.view :refer [drawer-view open-drawer]] [status-im.components.image-button.view :refer [scan-button]] [status-im.contacts.styles :as st] @@ -42,14 +43,20 @@ [text {:style st/name-text} (label :t/new-public-group-chat)]]]]]]) -(defn render-row [chat-modal click-handler action params] +(defn render-row [chat-modal click-handler action params group edit?] (fn [row _ _] (list-item ^{:key row} - [contact-view {:contact row - :letter? chat-modal - :on-click (when click-handler - #(click-handler row action params))}]))) + [contact-view {:contact row + :letter? chat-modal + :extended? edit? + :extend-options (when group + [{:value #(dispatch [:hide-contact row]) + :text (label :t/delete-contact)} + {:value #(dispatch [:remove-contact-from-group row group]) + :text (label :t/remove-from-group)}]) + :on-click (when (and (not edit?) click-handler) + #(click-handler row action params))}]))) (defn contact-list-entry [{:keys [click-handler icon icon-style label]}] [touchable-highlight @@ -63,23 +70,36 @@ :number-of-lines 1} label]]]]]) -(defview contact-list-toolbar [] - [group [:get :contacts-group] - modal [:get :modal] - show-search [:get-in [:toolbar-search :show]]] - [view - [status-bar] - (toolbar-with-search - {:show-search? (= show-search :contact-list) - :search-key :contact-list - :title (if-not group - (label :t/contacts) - (or (:name group) (label :t/contacts-group-new-chat))) - :search-placeholder (label :t/search-for) - :actions (when modal - (act/back #(dispatch [:navigate-back])))})]) +(defview contact-list-toolbar-edit [group] + [toolbar {:nav-action (act/back #(dispatch [:set-in [:contact-list-ui-props :edit?] false])) + :actions [{:image :blank}] + :title (if-not group + (label :t/contacts) + (or (:name group) (label :t/contacts-group-new-chat)))}]) -(defview contacts-list-view [group modal click-handler action] +(defview contact-list-toolbar [group] + [modal [:get :modal] + show-search [:get-in [:toolbar-search :show]] + search-text [:get-in [:toolbar-search :text]]] + (toolbar-with-search + {:show-search? (= show-search :contact-list) + :search-text search-text + :search-key :contact-list + :title (if-not group + (label :t/contacts) + (or (:name group) (label :t/contacts-group-new-chat))) + :search-placeholder (label :t/search-contacts) + :actions (if modal + (act/back #(dispatch [:navigate-back])) + [(act/opts [{:text (label :t/edit) + :value #(dispatch [:set-in [:contact-list-ui-props :edit?] true])}])])})) + +(defn render-separator [_ row-id _] + (list-item ^{:key row-id} + [view st/contact-item-separator-wrapper + [view st/contact-item-separator]])) + +(defview contacts-list-view [group modal click-handler action edit?] [contacts [:all-added-group-contacts-filtered (:group-id group)] params [:get :contacts-click-params]] (let [show-new-group-chat? (and (= group :people) @@ -87,25 +107,30 @@ (when contacts [list-view {:dataSource (lw/to-datasource contacts) :enableEmptySections true - :renderRow (render-row modal click-handler action params) + :renderRow (render-row modal click-handler action params group edit?) :bounces false :keyboardShouldPersistTaps true :renderHeader #(list-item [view - (if show-new-group-chat? - [new-group-chat-view]) - [view st/spacing-top]]) + (when show-new-group-chat? + [new-group-chat-view])]) :renderFooter #(list-item [view st/spacing-bottom]) + :renderSeparator render-separator :style st/contacts-list}]))) (defview contact-list [] [action [:get :contacts-click-action] modal [:get :modal] + edit? [:get-in [:contact-list-ui-props :edit?]] click-handler [:get :contacts-click-handler] group [:get :contacts-group]] [drawer-view - [view st/contacts-list-container - [contact-list-toolbar] + [view {:flex 1} + [view + [status-bar] + (if edit? + [contact-list-toolbar-edit group] + [contact-list-toolbar group])] ;; todo add stub (when modal [view @@ -122,4 +147,4 @@ :label (label (if (= :request action) :t/show-qr :t/scan-qr))}]]) - [contacts-list-view group modal click-handler action]]]) + [contacts-list-view group modal click-handler action edit?]]]) diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 6c3c20fb67..15e6b409fe 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -24,6 +24,7 @@ [status-im.chats-list.screen :refer [chats-list]] [status-im.new-group.screen-private :refer [new-group contact-group]] [status-im.new-group.views.contact-list :refer [contact-group-list]] + [status-im.new-group.views.reorder-groups :refer [reorder-groups]] [status-im.new-group.screen-public :refer [new-public-group]] [status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.remove :refer [remove-participants]] @@ -93,6 +94,7 @@ :contact-list main-tabs :contact-list-search-results contacts-search-results :group-contacts contact-list + :reorder-groups reorder-groups :contact-group contact-group :contact-group-list contact-group-list :new-contact new-contact diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 6a2d8d4627..8b39a797a8 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -16,6 +16,13 @@ :color "#2f3031"}} :toolbar {:border-bottom-color styles/color-gray3 :border-bottom-width 0.5} + :toolbar-new {:height 56 + :padding-top 20 + :padding-left 16 + :padding-right 16} + :toolbar-title-container {:align-items :center} + :toolbar-title-center? true + :toolbar-with-search-content {:align-items :center} :sized-text {:margin-top -5 :additional-height 5} :actions-list-view {:border-bottom-color styles/color-gray3 @@ -40,34 +47,87 @@ :icon {:padding-top 0 :bottom -4 :justify-content :flex-end}}} - :contacts {:subtitle {:color styles/color-black + :contacts {:subtitle {:color styles/text1-color :font-size 16 :letter-spacing -0.2} - :separator {:margin-left 68 + :subtitle-count {:color styles/color-gray4 + :font-size 16 + :letter-spacing -0.2} + :separator {:margin-left 72 :height 1 :background-color styles/color-gray5 - :opacity 0.4} + :opacity 0.5} + :info-container {:margin-left 16} + :contact-inner-container {:height 63} :icon-check {:border-radius 50 :width 24 :height 24} :group-header {:flexDirection :row :alignItems :center :margin-top 24 + :padding-left 16 + :padding-right 16 :height 53 - :backgroundColor styles/color-white}} + :backgroundColor styles/color-white} + :show-all {:padding-left 72 + :height 64} + :show-all-text {:fontSize 16 + :color styles/color-gray4 + :letter-spacing -0.2} + :show-all-text-font :default + :contact-container {:padding-right 16} + :name-text {:fontSize 17 + :line-height 20 + :letter-spacing -0.2 + :color styles/text1-color}} + :new-group {:group-name-text {:font-size 13} + :members-text {:letter-spacing -0.2 + :font-size 16} + :members-text-count {:letter-spacing -0.2 + :font-size 16} + :add-text {:margin-left 14 + :letter-spacing -0.2 + :font-size 17 + :line-height 20} + :delete-group-text {:letter-spacing -0.2 + :font-size 17 + :line-height 20} + :delete-group-prompt-text {:font-size 13 + :letter-spacing -0.1} + :contact-container {:height 63} + :delete-group-container {:padding-left 68}} + :reorder-groups {:order-item-separator {:margin-left 16 + :opacity 0.5} + :order-item-container {:height 63} + :order-item-icon {:padding-right 20} + :order-item-label {:padding-left 16 + :font-size 17 + :line-height 20 + :letter-spacing -0.2} + :order-item-contacts {:font-size 17 + :line-height 20 + :letter-spacing -0.2}} + :confirm-button-label {:color styles/color-white + :font-size 17 + :line-height 20 + :letter-spacing -0.2} :bottom-gradient {:height 1} :input-label {:left 0} :input-error-text {:margin-left 0} :main-tab-list {:margin-bottom 72} + :toolbar-search-input {:padding-left 10} :toolbar-nav-action {:width 46 :height 56 :align-items :center :justify-content :center} + :toolbar-border-container {:background-color styles/color-white} + :toolbar-border {:height 1 + :background-color styles/color-gray5 + :opacity 0.5} :toolbar-last-activity {:color styles/text2-color :background-color :transparent :top 0 - :font-size 14} - :toolbar-title-container {:align-items :center}}) + :font-size 14}}) (def fonts {:light {:font-family "SFUIText-Light"} @@ -75,7 +135,7 @@ :medium {:font-family "SFUIText-Medium"} :bold {:font-family "SFUIText-Bold"} - :toolbar-title {:font-family "SFUIText-Medium"}}) + :toolbar-title {:font-family "SFUIText-Semibold"}}) ;; Dialogs @@ -96,12 +156,14 @@ :tabs {:tab-shadows? false} :chats {:action-button? false :new-chat-in-toolbar? true} + :uppercase? false :contacts {:action-button? false :new-contact-in-toolbar? true - :uppercase-subtitles? true :group-block-shadows? false} :discover {:uppercase-subtitles? true} :public-group-icon-container {:margin-top 2} :private-group-icon-container {:margin-top 2} + :group-chat-focus-line-color styles/color-gray5 + :group-chat-focus-line-height 1 :public-group-chat-hash-style {:top 6 :left 3}}) diff --git a/src/status_im/new_group/handlers.cljs b/src/status_im/new_group/handlers.cljs index 836d6858bf..15835f4293 100644 --- a/src/status_im/new_group/handlers.cljs +++ b/src/status_im/new_group/handlers.cljs @@ -218,8 +218,7 @@ (-> (fn [db [_ new-group]] (assoc db :new-group new-group)) ((enrich update-group)) - ((after update-group!)) - ((after show-contact-list!)))) + ((after update-group!)))) (defn save-groups! [{:keys [new-groups]} _] (groups/save-all new-groups)) @@ -258,3 +257,35 @@ (defmethod nav/preload-data! :new-public-group [db] (dissoc db :public-group/topic)) + +(defn move-item [v from to] + (if (< from to) + (concat (subvec v 0 from) + (subvec v (inc from) (inc to)) + [(v from)] + (subvec v (inc to))) + (concat (subvec v 0 to) + [(v from)] + (subvec v to from) + (subvec v (inc from))))) + +(register-handler :change-group-order + (fn [{:keys [groups-order] :as db} [_ from to]] + (if (>= to 0) + (assoc db :groups-order (move-item (vec groups-order) from to)) + db))) + +(register-handler :update-groups + (after save-groups!) + (fn [db [_ new-groups]] + (-> db + (update :contact-groups merge (map #(vector (:group-id %) %) new-groups)) + (assoc db :new-groups new-groups)))) + +(register-handler :save-group-order + (u/side-effect! + (fn [{:keys [groups-order contact-groups] :as db} _] + (let [new-groups (mapv #(assoc (contact-groups (second %)) :order (first %)) + (map-indexed vector (reverse groups-order)))] + (dispatch [:update-groups new-groups]) + (dispatch [:navigate-to-clean :contact-list]))))) diff --git a/src/status_im/new_group/screen_private.cljs b/src/status_im/new_group/screen_private.cljs index debb4d4a20..eeddd43de4 100644 --- a/src/status_im/new_group/screen_private.cljs +++ b/src/status_im/new_group/screen_private.cljs @@ -3,6 +3,7 @@ (:require [re-frame.core :refer [subscribe dispatch]] [status-im.resources :as res] [status-im.contacts.views.contact :refer [contact-view]] + [status-im.contacts.styles :as cst] [status-im.components.react :refer [view text image @@ -12,10 +13,9 @@ list-item]] [status-im.components.text-field.view :refer [text-field]] [status-im.components.confirm-button :refer [confirm-button]] - [status-im.components.styles :refer [color-blue - separator-color]] + [status-im.components.styles :refer [color-blue color-gray5]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar-with-search toolbar]] + [status-im.components.toolbar-new.view :refer [toolbar]] [status-im.utils.platform :refer [platform-specific]] [status-im.utils.listview :refer [to-datasource]] [status-im.new-group.views.contact :refer [new-group-contact]] @@ -40,17 +40,19 @@ [new-chat-name [:get :new-chat-name]] [view [text-field - {:error (when - (not (s/valid? ::v/not-illegal-name new-chat-name)) - (label :t/illegal-group-chat-name)) - :wrapper-style st/group-chat-name-wrapper - :error-color color-blue - :line-color separator-color - :label-hidden? true - :input-style st/group-chat-name-input - :auto-focus true - :on-change-text #(dispatch [:set :new-chat-name %]) - :value new-chat-name}]]) + {:error (when + (not (s/valid? ::v/not-illegal-name new-chat-name)) + (label :t/illegal-group-chat-name)) + :error-color color-blue + :wrapper-style st/group-chat-name-wrapper + :line-color color-gray5 + :focus-line-color st/group-chat-focus-line-color + :focus-line-height st/group-chat-focus-line-height + :label-hidden? true + :input-style st/group-chat-name-input + :auto-focus true + :on-change-text #(dispatch [:set :new-chat-name %]) + :value new-chat-name}]]) (defview new-group [] [contacts [:all-added-contacts]] @@ -71,35 +73,50 @@ [list-view {:dataSource (to-datasource contacts) :renderRow (fn [row _ _] - (list-item [new-group-contact row])) - :style st/contacts-list}]]]) + (list-item [new-group-contact row]))}]]]) (defview new-contacts-group-toolbar [edit?] [view [status-bar] [toolbar - {:title (label (if edit? :t/edit-group :t/new-group))}]]) + {:title (label (if edit? :t/edit-group :t/new-group)) + :actions [{:image :blank}]}]]) (defn chat-name-view [contacts-count] [view st/chat-name-container - [text {:style st/group-name-text - :font :medium} + [text {:style st/group-name-text} (label :t/group-name)] [group-name-input] - [text {:style st/members-text - :font :medium} - (str (label :t/group-members) " " contacts-count)] + [view st/members-container + [text {:style st/members-text + :font :medium} + (label :t/group-members)] + [text {:style st/members-text-count + :font :medium} + contacts-count]] [touchable-highlight {:on-press #(dispatch [:navigate-forget :contact-group-list])} [view st/add-container - [icon :add_blue st/add-icon] - [text {:style st/add-text} (label :t/add-members)]]]]) + [view st/add-icon-container + [icon :add_blue st/add-icon]] + [text {:style st/add-text + :font :medium + :uppercase? (get-in platform-specific [:uppercase?])} + (label :t/add-members)]]]]) (defn delete-btn [on-press] [touchable-highlight {:on-press on-press} [view st/delete-group-container - [text {:style st/delete-group-text} (label :t/delete-group)] + [text {:style st/delete-group-text + :font :medium + :uppercase? (get-in platform-specific [:uppercase?])} + (label :t/delete-group)] [text {:style st/delete-group-prompt-text} (label :t/delete-group-prompt)]]]) +(defn render-separator [_ row-id _] + (list-item ^{:key row-id} + [view cst/contact-item-separator-wrapper + [view cst/contact-item-separator]])) + ;;TODO: should be refactored into one common function for group chats and contact groups (defview contact-group [] [contacts [:selected-group-contacts] @@ -119,9 +136,11 @@ :extend-options [{:value #(dispatch [:deselect-contact (:whisper-identity row)]) :text (label :t/remove-from-group)}] :extended? true}])) - :style st/contacts-list}] + :renderSeparator render-separator}] (when group - [delete-btn #(dispatch [:update-group (assoc group :pending? true)])]) + [delete-btn #(do + (dispatch [:update-group (assoc group :pending? true)]) + (dispatch [:navigate-to-clean :contact-list]))]) (when save-btn-enabled? [confirm-button (label :t/save) (if group #(dispatch [:update-group-after-edit group group-name]) diff --git a/src/status_im/new_group/screen_public.cljs b/src/status_im/new_group/screen_public.cljs index 30116df920..1f2f8bbbdd 100644 --- a/src/status_im/new_group/screen_public.cljs +++ b/src/status_im/new_group/screen_public.cljs @@ -11,7 +11,7 @@ list-item]] [status-im.components.text-field.view :refer [text-field]] [status-im.components.styles :refer [color-blue - separator-color]] + color-gray4]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar.view :refer [toolbar]] [status-im.utils.listview :refer [to-datasource]] @@ -45,7 +45,7 @@ (label :t/topic-format)) :wrapper-style st/group-chat-name-wrapper :error-color color-blue - :line-color separator-color + :line-color color-gray4 :label-hidden? true :input-style st/group-chat-topic-input :auto-focus true diff --git a/src/status_im/new_group/styles.cljs b/src/status_im/new_group/styles.cljs index 25615149f0..1ba85033aa 100644 --- a/src/status_im/new_group/styles.cljs +++ b/src/status_im/new_group/styles.cljs @@ -5,9 +5,17 @@ text2-color color-light-blue color-light-red + color-light-gray selected-contact-color - color-gray4]] - [status-im.utils.platform :refer [platform-specific]])) + color-gray4 + color-gray5]] + [status-im.utils.platform :refer [platform-specific] :as p])) + +(defn ps-reorder [item] + (get-in platform-specific [:component-styles :reorder-groups item])) + +(defn ps-new-group [item] + (get-in platform-specific [:component-styles :new-group item])) (defn toolbar-icon [enabled?] {:width 20 @@ -19,12 +27,23 @@ :flex-direction :column :background-color color-white}) +(def reorder-groups-container + {:flex 1 + :flex-direction :column + :background-color color-light-gray}) + +(def reorder-list-container + (merge {:flex 1} + (ps-reorder :reorder-list-container))) + (def chat-name-container - {:margin-left 16}) + {:margin-top 21 + :margin-left 16}) (def group-chat-name-input - {:font-size 14 - :color text1-color}) + {:font-size 17 + :letter-spacing -0.2 + :color text1-color}) (def group-chat-topic-input {:font-size 14 @@ -38,31 +57,46 @@ :position :absolute} (get-in platform-specific [:public-group-chat-hash-style]))) +(def group-chat-focus-line-color + (get-in platform-specific [:group-chat-focus-line-color])) + +(def group-chat-focus-line-height + (get-in platform-specific [:group-chat-focus-line-height])) + (def group-chat-name-wrapper - {:padding-top 0}) + {:padding-top 0 + :height 40 + :padding-bottom 0}) (def group-name-text - {:margin-top 11 - :margin-bottom 10 - :letter-spacing -0.1 - :color color-gray4 - :font-size 13 - :line-height 20}) + (merge (ps-new-group :group-name-text) + {:letter-spacing -0.1 + :color color-gray4})) + +(def members-container + {:flex-direction :row + :padding-top 20}) (def members-text - {:margin-top 10 - :margin-bottom 8 - :letter-spacing -0.2 - :color color-gray4 - :font-size 16 - :line-height 19}) + (merge (ps-new-group :members-text) + {:color color-gray4})) + +(def members-text-count + (merge (ps-new-group :members-text-count) + {:margin-left 8 + :color color-gray4 + :opacity 0.6})) (def add-container {:flex-direction :row :align-items :center - :margin-top 16 - :margin-bottom 16 - :margin-right 20}) + :height 64 + :margin-top 12}) + +(def add-icon-container + {:width 40 + :align-items :center + :justify-content :center}) (def add-icon {:align-items :center @@ -70,31 +104,22 @@ :height 24}) (def add-text - {:margin-left 32 - :color color-light-blue - :letter-spacing -0.2 - :font-size 17 - :line-height 20}) + (merge (ps-new-group :add-text) + {:color color-light-blue})) (def delete-group-text - {:color color-light-red - :letter-spacing 0.5 - :font-size 14 - :line-height 20}) + (merge (ps-new-group :delete-group-text) + {:color color-light-red})) (def delete-group-prompt-text - {:color color-gray4 - :font-size 14 - :line-height 20}) - -(def contacts-list - {:background-color :white}) + (merge (ps-new-group :delete-group-prompt-text) + {:color color-gray4})) (def contact-container - {:flex-direction :row - :justify-content :center - :align-items :center - :height 56}) + (merge (ps-new-group :contact-container) + {:flex-direction :row + :justify-content :center + :align-items :center})) (def selected-contact {:background-color selected-contact-color}) @@ -115,6 +140,52 @@ :height 12}) (def delete-group-container - {:height 56 - :padding-left 72 - :margin-top 15}) \ No newline at end of file + (merge (ps-new-group :delete-group-container) + {:height 64 + :padding-top 12})) + +(def order-item-container + {:background-color color-white}) + +(def order-item-inner-container + (merge {:flex-direction :row + :align-items :center} + (ps-reorder :order-item-container))) + +(def order-item-label + (ps-reorder :order-item-label)) + +(def order-item-contacts + (merge (ps-reorder :order-item-contacts) + {:padding-left 8 + :color color-gray4})) + +(def order-item-icon + (ps-reorder :order-item-icon)) + +(def order-item-separator-wrapper + {:background-color color-white}) + +(def order-item-separator + (merge {:height 1 + :background-color color-gray5} + (ps-reorder :order-item-separator))) + +(def toolbar-title-with-count-text + {:color text1-color + :letter-spacing -0.2 + :font-size 17}) + +(def toolbar-title-with-count-text-count + (merge toolbar-title-with-count-text + {:color "#628fe3"})) + +(def toolbar-title-with-count + {:flex-direction :row}) + +(def toolbar-title-with-count-container + {:padding-left 6}) + + + + diff --git a/src/status_im/new_group/subs.cljs b/src/status_im/new_group/subs.cljs index 738b55ac04..a7a332db47 100644 --- a/src/status_im/new_group/subs.cljs +++ b/src/status_im/new_group/subs.cljs @@ -11,9 +11,11 @@ (let [contacts (subscribe [:get :selected-contacts])] (reaction (count @contacts))))) +(defn filter-contacts [selected-contacts added-contacts] + (filter #(selected-contacts (:whisper-identity %)) added-contacts)) + (register-sub :selected-group-contacts (fn [_ _] (let [selected-contacts (subscribe [:get :selected-contacts]) added-contacts (subscribe [:all-added-contacts])] - (reaction (do @selected-contacts ;;TODO: doesn't work without this line :( - (filter #(@selected-contacts (:whisper-identity %)) @added-contacts)))))) + (reaction (filter-contacts @selected-contacts @added-contacts))))) diff --git a/src/status_im/new_group/views/contact.cljs b/src/status_im/new_group/views/contact.cljs index 20fca109ff..7097a797c7 100644 --- a/src/status_im/new_group/views/contact.cljs +++ b/src/status_im/new_group/views/contact.cljs @@ -24,6 +24,4 @@ [view (merge st/icon-check-container {:background-color (if checked color-light-blue color-gray5)}) (when checked - [icon :check_on st/check-icon])]]] - [view cst/contact-separator-container - [view (get-in platform-specific [:component-styles :contacts :separator])]]]]) + [icon :check_on st/check-icon])]]]]]) diff --git a/src/status_im/new_group/views/contact_list.cljs b/src/status_im/new_group/views/contact_list.cljs index 69d08511bb..3de834a44f 100644 --- a/src/status_im/new_group/views/contact_list.cljs +++ b/src/status_im/new_group/views/contact_list.cljs @@ -7,32 +7,52 @@ list-item]] [status-im.components.confirm-button :refer [confirm-button]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar-with-search]] + [status-im.components.toolbar-new.view :refer [toolbar-with-search]] [status-im.utils.listview :refer [to-datasource]] [status-im.new-group.views.contact :refer [new-group-contact]] [status-im.new-group.styles :as st] + [status-im.contacts.styles :as cst] [status-im.i18n :refer [label]])) -(defn contact-list-toolbar [contacts-count show-search?] +(defn title-with-count [title count-value] + [view st/toolbar-title-with-count + [text {:style st/toolbar-title-with-count-text + :font :toolbar-title} + title] + (when (pos? count-value) + [view st/toolbar-title-with-count-container + [text {:style st/toolbar-title-with-count-text-count + :font :toolbar-title} + count-value]])]) + +(defn contact-list-toolbar [contacts-count show-search? search-text] (toolbar-with-search {:show-search? (= show-search? :contact-group-list) + :search-text search-text :search-key :contact-group-list - :title (str (label :t/new-group) " (" contacts-count ")") - :search-placeholder (label :t/search-for)})) + :custom-title (title-with-count (label :t/new-group) contacts-count) + :search-placeholder (label :t/search-contacts)})) + +(defn render-separator [_ row-id _] + (list-item ^{:key row-id} + [view cst/contact-item-separator-wrapper + [view cst/contact-item-separator]])) (defview contact-group-list [] [contacts [:all-added-group-contacts-filtered] selected-contacts-count [:selected-contacts-count] - show-search [:get-in [:toolbar-search :show]]] + show-search [:get-in [:toolbar-search :show]] + search-text [:get-in [:toolbar-search :text]]] [view st/new-group-container [status-bar] - [contact-list-toolbar selected-contacts-count show-search] + [contact-list-toolbar selected-contacts-count show-search search-text] [view {:flex 1} [list-view {:dataSource (to-datasource contacts) :renderRow (fn [row _ _] (list-item ^{:key row} [new-group-contact row])) - :style st/contacts-list + :renderSeparator render-separator + :style cst/contacts-list :keyboardShouldPersistTaps true}]] (when (pos? selected-contacts-count) [confirm-button (label :t/next) #(dispatch [:navigation-replace :contact-group])])]) diff --git a/src/status_im/new_group/views/reorder_groups.cljs b/src/status_im/new_group/views/reorder_groups.cljs new file mode 100644 index 0000000000..803fce4683 --- /dev/null +++ b/src/status_im/new_group/views/reorder_groups.cljs @@ -0,0 +1,76 @@ +(ns status-im.new-group.views.reorder-groups + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [dispatch dispatch-sync]] + [status-im.components.react :refer [view + text + icon + linear-gradient + touchable-highlight + list-item]] + [status-im.components.confirm-button :refer [confirm-button]] + [status-im.components.status-bar :refer [status-bar]] + [status-im.components.toolbar-new.view :refer [toolbar]] + [status-im.components.sortable-list-view :refer [sortable-list-view sortable-item]] + [status-im.utils.listview :refer [to-datasource]] + [status-im.utils.platform :refer [android?]] + [status-im.new-group.styles :as st] + [status-im.contacts.styles :as cst] + [status-im.i18n :refer [label label-pluralize]] + [status-im.utils.platform :refer [platform-specific]] + [reagent.core :as r])) + +(defn toolbar-view [] + [toolbar {:actions [{:image :blank}] + :title (label :t/reorder-groups)}]) + +(defn group-item [{:keys [name contacts] :as group}] + (let [cnt (count contacts)] + [view st/order-item-container + [view st/order-item-inner-container + [text {:style st/order-item-label} + name] + [text {:style st/order-item-contacts} + (str cnt " " (label-pluralize cnt :t/contact-s))] + [view {:flex 1}] + [view st/order-item-icon + [icon :grab_gray]]]])) + +(defn top-shaddow [] + [linear-gradient {:style cst/contact-group-header-gradient-bottom + :colors cst/contact-group-header-gradient-bottom-colors}]) + +(defn bottom-shaddow [] + [linear-gradient {:style cst/contact-group-header-gradient-top + :colors cst/contact-group-header-gradient-top-colors}]) + +(defn render-separator [last shadows?] + (fn [_ row-id _] + (list-item + (if (= row-id last) + (when shadows? + ^{:key "bottom-shaddow"} + [bottom-shaddow]) + ^{:key row-id} + [view st/order-item-separator-wrapper + [view st/order-item-separator]])))) + +(defview reorder-groups [] + [groups [:get :contact-groups] + order [:get :groups-order] + shadows? (get-in platform-specific [:contacts :group-block-shadows?])] + (let [this (r/current-component)] + [view st/reorder-groups-container + [status-bar] + [toolbar-view] + [view st/reorder-list-container + (when shadows? + [top-shaddow]) + [sortable-list-view + {:data groups + :order order + :on-row-moved #(do (dispatch-sync [:change-group-order (:from %) (:to %)]) + (.forceUpdate this)) + :render-row (fn [row] + (sortable-item [group-item row])) + :render-separator (render-separator (last order) shadows?)}]] + [confirm-button (label :t/save) #(dispatch [:save-group-order])]])) diff --git a/src/status_im/qr_scanner/styles.cljs b/src/status_im/qr_scanner/styles.cljs index 7e92540003..97e81d5b95 100644 --- a/src/status_im/qr_scanner/styles.cljs +++ b/src/status_im/qr_scanner/styles.cljs @@ -1,6 +1,7 @@ (ns status-im.qr-scanner.styles (:require [status-im.components.styles :refer [color-white]] - [status-im.components.toolbar.styles :refer [toolbar-height]])) + [status-im.components.toolbar.styles :refer [toolbar-height]] + [status-im.utils.platform :as p])) (def barcode-scanner-container {:flex 1 diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 290a41f1ca..912cc2f8e8 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -146,6 +146,7 @@ :delete-contact "Delete contact" :remove-from-group "Remove from group" :edit-contacts "Edit contacts" + :search-contacts "Search contacts" :show-all "SHOW ALL" :contacts-group-dapps "ÐApps" :contacts-group-people "People" @@ -189,14 +190,15 @@ :group-chat-name "Chat name" :empty-group-chat-name "Please enter a name" :illegal-group-chat-name "Please select another name" - :new-group "New Group" - :reorder-groups "Reorder Group" + :new-group "New group" + :reorder-groups "Reorder groups" :group-name "Group name" - :edit-group "Edit Group" - :delete-group "DELETE GROUP" + :edit-group "Edit group" + :delete-group "Delete group" :delete-group-prompt "This will not affect group members" :group-members "Group members" - + :contact-s {:one "contact" + :other "contacts"} ;participants :add-participants "Add Participants" :remove-participants "Remove Participants" From 9345f77dd8c964247a02fbf83ecaefd26aa29189 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Mon, 13 Mar 2017 12:21:27 +0300 Subject: [PATCH 03/48] fixed list paddings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixed android styles group chat contacts management refactored contact group contacts, deletion, implemented group chat settings reworked contacts screens, implemented “add contacts” screen and “edit contacts” screen group chat ui refresh --- .../drawable-hdpi/icon_arrow_right_red.png | Bin 0 -> 469 bytes .../res/drawable-hdpi/icon_close_blue.png | Bin 0 -> 462 bytes .../main/res/drawable-hdpi/icon_close_red.png | Bin 0 -> 466 bytes .../res/drawable-hdpi/icon_speaker_blue.png | Bin 0 -> 1007 bytes .../drawable-mdpi/icon_arrow_right_red.png | Bin 0 -> 351 bytes .../res/drawable-mdpi/icon_close_blue.png | Bin 0 -> 337 bytes .../main/res/drawable-mdpi/icon_close_red.png | Bin 0 -> 323 bytes .../res/drawable-mdpi/icon_speaker_blue.png | Bin 0 -> 639 bytes .../drawable-xhdpi/icon_arrow_right_red.png | Bin 0 -> 531 bytes .../res/drawable-xhdpi/icon_close_blue.png | Bin 0 -> 562 bytes .../res/drawable-xhdpi/icon_close_red.png | Bin 0 -> 568 bytes .../res/drawable-xhdpi/icon_speaker_blue.png | Bin 0 -> 1182 bytes .../drawable-xxhdpi/icon_arrow_right_red.png | Bin 0 -> 721 bytes .../res/drawable-xxhdpi/icon_close_red.png | Bin 0 -> 747 bytes .../res/drawable-xxhdpi/icon_speaker_blue.png | Bin 0 -> 1756 bytes .../drawable-xxxhdpi/icon_arrow_right_red.png | Bin 0 -> 902 bytes .../res/drawable-xxxhdpi/icon_close_blue.png | Bin 0 -> 1133 bytes .../res/drawable-xxxhdpi/icon_close_red.png | Bin 0 -> 1155 bytes .../drawable-xxxhdpi/icon_speaker_blue.png | Bin 0 -> 2311 bytes .../Contents.json | 21 ++ .../icon_arrow_right_red.png | Bin 0 -> 531 bytes .../icon_close_blue.imageset/Contents.json | 21 ++ .../icon_close_blue.png | Bin 0 -> 562 bytes .../icon_close_red.imageset/Contents.json | 21 ++ .../icon_close_red.png | Bin 0 -> 568 bytes .../icon_speaker_blue.imageset/Contents.json | 21 ++ .../icon_speaker_blue.png | Bin 0 -> 1182 bytes src/status_im/android/core.cljs | 19 +- src/status_im/android/platform.cljs | 21 +- src/status_im/chats_list/screen.cljs | 2 +- src/status_im/contacts/handlers.cljs | 30 +-- src/status_im/contacts/screen.cljs | 15 +- src/status_im/contacts/styles.cljs | 12 +- src/status_im/contacts/subs.cljs | 36 +++- .../contacts/views/contact_list.cljs | 51 +++-- src/status_im/data_store/contact_groups.cljs | 9 + .../data_store/realm/contact_groups.cljs | 29 ++- src/status_im/group_settings/handlers.cljs | 3 +- src/status_im/ios/core.cljs | 21 +- src/status_im/ios/platform.cljs | 22 +- src/status_im/new_group/handlers.cljs | 81 +++++-- src/status_im/new_group/screen_private.cljs | 197 +++++++----------- src/status_im/new_group/screen_public.cljs | 3 +- src/status_im/new_group/styles.cljs | 57 +++-- src/status_im/new_group/subs.cljs | 20 +- .../new_group/views/chat_group_settings.cljs | 77 +++++++ src/status_im/new_group/views/contact.cljs | 27 --- .../new_group/views/contact_list.cljs | 115 ++++++---- .../new_group/views/contact_toggle_list.cljs | 117 +++++++++++ src/status_im/new_group/views/group.cljs | 111 ++++++++++ .../new_group/views/toggle_contact.cljs | 38 ++++ src/status_im/translations/en.cljs | 6 +- 52 files changed, 893 insertions(+), 310 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_arrow_right_red.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_close_blue.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_close_red.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_speaker_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_arrow_right_red.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_close_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_close_red.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_speaker_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_arrow_right_red.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_close_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_close_red.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_speaker_blue.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_arrow_right_red.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_close_red.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_speaker_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_arrow_right_red.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_close_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_close_red.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_speaker_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/icon_arrow_right_red.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_close_blue.imageset/icon_close_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_red.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_close_red.imageset/icon_close_red.png create mode 100644 ios/StatusIm/Images.xcassets/icon_speaker_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_speaker_blue.imageset/icon_speaker_blue.png create mode 100644 src/status_im/new_group/views/chat_group_settings.cljs delete mode 100644 src/status_im/new_group/views/contact.cljs create mode 100644 src/status_im/new_group/views/contact_toggle_list.cljs create mode 100644 src/status_im/new_group/views/group.cljs create mode 100644 src/status_im/new_group/views/toggle_contact.cljs diff --git a/android/app/src/main/res/drawable-hdpi/icon_arrow_right_red.png b/android/app/src/main/res/drawable-hdpi/icon_arrow_right_red.png new file mode 100644 index 0000000000000000000000000000000000000000..568c62fc5acc2550ff48f3195c246e52b48845d5 GIT binary patch literal 469 zcmV;`0V@89P)Px$k4Z#9R9Fe^lfO>GFc8LlPFuS51z1U0JHQ(-HLAoAi3!$r;LpH{!~ic)CSZgC zAt6;tvhWnF6d?v40I@VuAwJHLQmTl=CiMW4v&82+pMUx83uE@N3RnfK0#<>)tpJ$9 z8+%?~Fm}KJuG}Cvt=gAYJ(xd7Fh>lrErd9E>~@Fwyl!j^h?Kd_E=9(6t3nwAT4^>9 z0pMm)C}SRyAn5zfIF7FoaVrC(3(ne6w3o%Iw^1N@*`iQdKu^71ClO+Ye9};TVG4y< zBZF^~mzHMr0K?TV+@Hk-3oRfr=qoi}F6g1X&Fl4!I~qNd9ndm0!Mv3<(aDkFg-DWj zRc%dGAoC5!*_a}FObD%!0p~5MJ`x#TH5GDxD^WbH%mWRq3WVw&YPx$h)G02R9Fe^R?BU}FbtJ~jNz`3U3$m@X?iU(fPo@F1_*j>+68*(E}g-1l;u-R zLry50N`L|dsEcIkiSOZ2ABW)09dHNS0e4{JKpcG)J|2$Uny1=G^!d7L_Ay2(Ku2LB zijT+cnPR->iNo8j`4|C|kEIgRLMv5M99rMu(tc1{$;F!sc2Hi0NGzU9QTf)*P4 zc?`}-jK0Gr5iy~}&ig?OV`VPSAu+8lCe6Vr!6Lk$o|+4%YOpznj7@?7wh&n`LR{+2 zg62eFK9w>rQ^CcO7{sdtVL{1-G(h~VN@8$90>H<95Y^x4IF%Qdr-;^ibIGQ}$h&62 zXd?2MNl*<@4K^1dW78>1zYxa#0k_f{*Y7J3p?t_8q*J{~Q2#%Z@>n*jD(d&2Xi7_( zGYMkkfl0m?yw_fMjYULZ4b~!uhVz&^;10M0?!b%#KdaUn!!?kiivR!s07*qoM6N<$ Ef~w%i$N&HU literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_close_red.png b/android/app/src/main/res/drawable-hdpi/icon_close_red.png new file mode 100644 index 0000000000000000000000000000000000000000..aff378e3a4ac757b697157001d7027bc848a1bb9 GIT binary patch literal 466 zcmV;@0WJQCP)Px$j7da6R9Fe^mOXC6FbsvQBG<^;cFIKp4;gxaBF89D6v#1(ULZpTBX>!=_8=;s zU^=o*+LRM?qK4@2iTv^`*{Uip?tnYs4!8q72STr>bS~TNO92wa7@7+ye!GEFdjSmA6$4?B2!#nQ3t_N)5fB!tP&dFJuJzbM`!8jY zL#jKBe1l8HKq3qQB$hjDYSX8K|F{N&7bG-v?6JAhrvf$lv}W}3Px&sYygZR9Fe^SWQS&Q53%Sy&3-sNuu&+W+7^eAP6C96+{scl@J;2A{EWFQ6bt$ zG*YfwjH78f`9qtCivEd+BB*^u3m5)i=!}XIrr|g_0qvGXDrZXQ>EljDQ1<4Ps` zmH{aNHF634%8YzX3DtGZ>`_?s76KjsAcfjw#xxa`?*10X-L)O@bc|EN$AOSiGe1K@ zHQuQcQ5JoQGc$3rVMC(tockQjhJz_|>NfS2&Y!uM)&cxBnTByG{Xr$#F6TH-x)0<2 z+2E$jP>8J@!p!7z96UYa#GZM4pke3O2IHEB(`5*=vsd$`^iev=a9kZBN6T0c>vI(hqkcx%Lh{Fz zFy>yh8>%}3!voDlJz_kb#OG#=zhkir*Tm5LGSiB*$a zvCxtx#4&u0gS&5PG6AB|;pe-{p8B0l6*!arw0B5+CXT z(VwVHnGgrUGPYeJv;~*wH@8tTJWajMCdX}VTWOX~zPx$8A(JzR7eeDU>F6XAwc&Kxas2~eLE;fhFFW4h*bzv_n(2`*xz5jZr<_pbA*ZE zqe->^XxMs&|NpuE{QI|s7)u!O*^W)_|NsAtw|sqP0qGP5M#gU}OiVs1n>OvorWPcI z(*lq|_rk*XuxVua{hRUEpFcBzYQhOwg3|(EWF7(?0;w|+pTZk)&VW? zW@Kc1!@|t$q`YzCWtcoNO|k`~7!IPx$3rR#lR7ef&Q?U+$Fc57;62oqygNu%S1%8C?#>GM7rx;xvjJsdKSFpM`nCQ+V z)_WkPsXZ`(u^ph?J>I*%-U;EBbD*vRk|UUJuSY55Flc$R{ks3K;a0m_H+iLJCDi4# z87yp=mMw@Fk&l#8VUj*05Sh4)oN~aR5HnwVvjSB4l#UlGA;zZ2mz;9I;FJZS`DQHw z@Q282hloQE!WlWmI17O-6#&2#LF`|0U@HXx(nUT$#X&{oz+tg>kf-ZED^H+T56>al zm_;TzY=J-{muw?1x}_|K0`$e+K|Z1OR)mn>@h7k>n-iL5omAhm0vLZOWyE#MVcEMQ j2Mn+}soOgTnswj}VKt)?S|^Fp00000NkvXXu0mjfU$cwD literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_close_red.png b/android/app/src/main/res/drawable-mdpi/icon_close_red.png new file mode 100644 index 0000000000000000000000000000000000000000..c25f1b2398ecaf9761a3797d3256104fe4e15779 GIT binary patch literal 323 zcmV-J0lfZ+P)Px#{YgYYR7ef&Q#%rZFc3{(C_?WA{EUUCz?K@lfXDIz4h0o8r?7CG;Q-o0r7=&* z46~C3XP`_9cC!0;Z}T=0!Y}W@R0kwSa7)v(7GfF3@o|&qPZ#c?}w1wy3`Qp&5=dPhYpIcmV*l$MZ2)*=8YQJ_?U zJOnK{a-4<04hjH3MUeZK9N19-fchfepNuVIodbu(&fr&`{vAC*zk3W6lCxPv$!8t1 zi`?Fpp&B)nodI4bX9a}9DB9b10xTuAdse^Px%IY~r8R7efgRX=D`VGzIjlIjptnyDl&1(&XMQgIQnF1A)2+N~W-b?&*W?D=#lE)TIwz?(*H;?{|Or z?g1S12iq;+`fRnkp{Y+rV6!lhTyGWM7C}1y?IbknZwcU-04u=zFEY+_5Qz#hnzkFy zD=E_T*Dg5XN3jvmEz`$O4@Gciek=BCmsS|D3jo)}(h8b+?T;WCYzo%O*5^y3t<$;S6XZ}SgHC&u@-g!ao zNUH+L+y#x`KykuZZ3n2CuT_DU`TqhJQj4Hj7W+B32)N%>0ZZr0{rdqmWB1HJE$|$s zs6lV8&Xim~cgPsIU6@R~G6TcvRt2d<;sK(1>{TKlJeT8I>&5hJ`FvPV)6c3PJB+{C zc=zAy`Z4e$z6XP)Px$%}GQ-RA>e5RJ}{XP!P|v)<|%$gF1+Vf)(9Man!jjU5bM!ody4g;w(70ITjbK zmD0L*^H1<=u(ONpAha6O^PZ6KhC=hgyHw!;OB!4zL64 zz`u1sP&4loi}RnZdn|G6Wb%Bq(de1PoH99V)T}Spy~g~ByfMCiEfkhU)kV#b3jiUu zeR5z~o37`zO^P5FAONm>0rF{D1i65;;~WVg?x;kNAL3uvOQo5Ye!mU?IaLUPKPD52 zowa83P0j1Xu?V0P5t{%i5s?IR%H>(F+g;Fk)j=(Q?RnlM9_DP2!yxMCq%Gh%mpilo zE|7q&5-<@XnTM3)WEX3-kFfLfw-CT71$jvr=Wg`|gZ;4NWu3MF1nKGk=++L0!*`vY zX`NzOi#z=Q*WnpHS9E**dhDOWIOYEio{yi?S+}{>g+-`TVZDCxgzY>;OB!4zL6406V}AumgYAfge?o Vz8<2Eu`>Vw002ovPDHLkV1kb?^(X)U literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_close_blue.png b/android/app/src/main/res/drawable-xhdpi/icon_close_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..30eeb57b2a6f4ff7fe136e847e7927aaca223627 GIT binary patch literal 562 zcmV-20?qx2P)Px$>`6pHRA>e5STRz=Fc3T?>7fQbK*bO80tz|`+AsrMsG)?Kl+2Kpf{ub0@B=D7 z0MzgRM`#V_aWayvla!gvaB3u5ckA7?BuggJq7JA7>VP_+4yXg_!2fl?NTpA1KliPv z?yNOiLqk{h)4gXYMmzp=_I_Adx;Dms8#_FkU+lcK`}^91zJS&KU-C32vIiB>(`5E> zyc!dGja*;=%UT)(J2sc&!~%%SHYby{!v)!g6cNZlE-)AmZ-ZiNfi+y56qPLB%Z|VOc#;)boY_t+I31!JKxt%7632_AxW%{ zXy{&+fLIahB9G^13+NMp{?*k6^9N%-G}Mq2TZ#z4!$L0CL|RK_N%FuhCIDbw5$NDj z(D??E8>Q-?h&7N0XYqHSl+aQ*I)vCs@6d6>rtaVLNgN_yZ#kTTjb28($n!cM6T@#( zT4&7x2{B2mL`1TH6hbLEePWUX<-AlzK5r=u zxxfGxF!5VuDL^mO0d+tfPzTfjbwC|Z2Ra@20iy$SPW46beE}M{P)Px$@<~KNRA>e5SW8aBFc6JP)h(Q&h!r>B1g%6@EOG%j11!rOxIh=IiqxKf8?Zw3 z6tJy?%)G=SgxUscZfE)8=s)!JIB3!1-C-Ed^XS#@-Z@14J*Q`@=n)$x#WB~w^5R%0Dh=!gG z5)domP~_46U;%w1@Se)A)yB=AGBnicl(=&i0cfhjW%@={%WcIdCwTy7696!u2t4PK zn>=u{3IJe8#39I|J@Iz{Nyk*O_CUye7JP_a$R@x?-Vr|jN!&rcbnYMTGTKF+*ZG(j z9%j;d&=8Uklf+6yBnwC(l#Us2;Vx@S;?H6Mw5WeFywrKlL+ulRKNHQEm}{|s(Rh4EPx(SV=@dRA>e5Sxt--MHH^rGYiU!5fTk-&ty-ci7_H45M!>pe&(!jK6$s*FRlki+CF?9T(X({4I-qc1wZdesvCxVywv;@4_rqev{I#)};9nk4@m%yWrkTwE1 zN#0e#jZE8hU+L=D|FW$mAV~bI0=ZvwvYkjm{~jPCFSxwbC4tl7_Ipdt)&1kuuL1cY z1KD{aN}q;#?ssu`Yi$H_qZ{)$m^D1hou=|u=`p90MDy?R(;S6 ziDi)7i;q|5h9|9O!v?MD*AkF}jvsvHMlNN(Nk(K4M1J&cY*mqL%S(ERX-hk0(3mM2gtUoS6A1KfNqj1 z&!yr=5Si1e46%6Q>Ox_nTGnKbj6odDEeRgJ8*VfUNyLAVmwMcbzw_RU4M8K`doi+@ zjA*5tOvim;@Erk(B(sZ_)pP#M576W z{%;omA`->UK0A1dVaJ6h&y6DNq8EM1ItqW1_>d z?G{90(_LCTH#lC{?8;;%CA2 zNEq=xa~LlEp)MpQ`F`w&HZI@kmM0#xy85GI>ar2qf`07*qoM6N<$f~XNP%m4rY literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_arrow_right_red.png b/android/app/src/main/res/drawable-xxhdpi/icon_arrow_right_red.png new file mode 100644 index 0000000000000000000000000000000000000000..8d7a645016e902e18bf8e58fa84ea5b99630ac12 GIT binary patch literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-HD>VCwdCaSW+o ze0yVmwuqw$`-ho3MFd^+IT!_7L;|fH`Eu6ezT3v(G3)W9FP^E2)2>HKU9@-LiICua z*wwJLcfyy>aF&Di54vPzq>UfX?ruCi@$5U@{PKH;%DaCXS{vuzd;YB~Elg8Jpn-u! zfq{|3fq@Bw*;vFkSDI)T6F!~ zE%V8mS!>JXOr)e0C%j-6DvQ`{X{+=+=K1x1|J>_KedlZcs(#6MS*R%L{*G0C8Y+bj zZm;#j8GmjP@Oael>htIIFOK~P=9*-&;OO1E!oln9r#GqOiS6D|^y}?6U2BP&axdGx z8nf&4lgos;pBSnrbh1rqP?6Ix2~urvQrgJ;H!^akao6MBcAD=V=dUe`j{H4S%;o#! zU(faxo>yg^we?T==A8yXSJAZYz`1B`+qrDsH}Ek@)=G#ovcaPtMOu4wL^@b${K; z$v;K31D>t0)V{?3q354fwaMB0J};U?j~`#b6TmU&6hrHwl`H`sG9Mil7P>Hd9uVYK zVRcuz5V-p5jBh3Or{yxRd(F>dBpG-!HRYE6JZrAS%YUsp oK68_!D%RMCrU{2u)_;ssR%zUrdfKQSm_`{qUHx3vIVCg!0DVt5@&Et; literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_close_red.png b/android/app/src/main/res/drawable-xxhdpi/icon_close_red.png new file mode 100644 index 0000000000000000000000000000000000000000..9d4f05701225c6d5ae799e7c063877d5970e7f6f GIT binary patch literal 747 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-HD>U|QFJ7z-Qg4G?09{Vh2OR=Q; zZHzp#poQm1dD-QT%vX1}iLpC5on-VpcB}1TSq!TOm!>J-v4w0VBAMa^R~mmQz2))~ zSrDMICBM4nK;7mH`$IEqB39QOedDq(o%Pp)vIFn3^N$~KyqDqN@vOO}Y@MnZ->VL; zmX_LyK@U_IUo}tRQkM+i2=bD-qWMjyE#ZG*XB{t7(u-1!r;#GE8Y0K%OkFu)5!2VB zo}D7RC)nB3ISszObGs z#GBQlC}GmZUkRPenLHlK%k-ydOnByCl3bqHY1{o!m;3BXN#i;1|KAPpzP`Y@uaohi zsK{Gsn|PHgLQNO0hViV}$Gxvaby7{=C&yQ-j)pGI-Y;?C+0&)dbS7D-{V`Js*IibB zB8q24TSbQ2wF8EhyC&SqGW_dwebMF{dV8AKWmaxK?PPd!9*&eFa-+O4e&z0Iemq?# RSb?dR!PC{xWt~$(699A*KZXDR literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_speaker_blue.png b/android/app/src/main/res/drawable-xxhdpi/icon_speaker_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..b97385b1c85cdae2d5a836a0bcbdd9013abe1a5c GIT binary patch literal 1756 zcmV<21|#{2P)Px*mPtfGRCodHTw7>dMHrqryPH^>P!o-|d+CGLT0v3q!Gc9vZ;43o!5W{ckZcl5 z((FbNqDTxXY!o%SxlpsoMr;GxsEFhx!CR4nEut+bVruoly@)m@N=Y|n_nh&cV-}K= zIhWl%=j_RP2DaV#=l1{K{_}rxX66JTJJ|@>2-pbN2-pbN2$U%T*vfXb4<>Ho1-yqK zR0oRAk*cb1V*YIlX6kH7fLaIQ4+$9e5<>P$z(`{bhe=gsXriU=lBCR#tmOdmN8&w# zfI>>vVvJAM)H?5f{fX^MO7-+8T&OYH?w%j%^!~}J10GbvlItlenFq}#lW)KR zuz_U^cup2!^w?OZ_dKiIOj$`h$RA0x5kvxVhQie8iUqu%$(5TaHyt3#STL=I6^tAi z@Ae*5C^xmpRDdXB!L<5Njd7-jID)9<<>$75e_=1qolTD}Sm*?m|T9e^Z3?4u` z5fQrN6f%mj1nN1Ggo*H^M5LN6*n|8-iF<`CdK}#M9!!u2XuFy<8X=&nOoGMW@OaQ5 z#v*9DbXaht9a5QEK5u|pM*i4^GAm<3mh2ZhhfzfjRvSrDP8qA-?Fq&ta;s(Y0;nyL z+Q+Z_^DzLzWFoD`dD9RlMh* z?;TFGZ#3Z3m9dNjNYfPiFCeeRoIJGwmRbO>ISax3c>NB~?R1-%D2Cx*C!qp(}}que@4$!GxS0fw;wryuw%D`rv69V`9dNbQjxBEr-Vfq1- z6!jeVyykU#UtsB=B!hP5q}2xf;P5=F2EKX6yR`Jjz1JG=M~qx~}^f0D2VMKEuL*GTX1`ti^1m0z^R>@AjR9 zxuSGKz5|%;Fblv^$V>-_8aWa4jltR}B4@Bs%qBOUlDs4UQHAO~o@ZdH&9IcqF`E@0 zYz<`qmho$4s?4_TRRpr}RRp+=9}D`5x{9+_AJ+Ghc@R}5$87Mp!hY2Nk=@zL{F&t} zdY7dLPg%(UqQ+=oHnz=}Q@XLw zZj-0f5&%)1MP|d?tD5!4=%ZMd=d9-X1y-~SKvaKtuhc8vu|9S_YGMz&+SK2n+Cs1sroi y)z+`g{=)(imF%pIfQ^8SfQ^8SfQ>-;An-3RyAnn)FI8Cp0000V0Q3yaSW+o ze0$qATf|X<{X=Eh`&AlFR`C-GW-JNyzZ~JQ!DD0M{-zm9nSZ!WIr7|y)|9vqWf3{a zNfSDHk1D!Dx7}v?#=YN|ElKJDqe}r3@i!^ zj2sROOacwWG7khdp3kg0y2nQMe3V#ZbgQY{vX?pAHR80^s`q=VTdi=tc&S(C_J>-H zN6Z#JlhVRh_VdKPKB~5;i8*pcTzviI+wX2aKe4^3ZLNCvE6e%CT=%~$+}bB{@m1X< z8<}nAwfe>78Ite5Wmi*V`N=5o_l0;v=672lGvn_+f5snjO+Og)di(7k>ffAFfv)d-?VFDyIUu1ONW~;qlJ@xGLq%)*X9yfc8# z)`qt{lD-=iD01E{{oVcM-wYk^zU<%gzxv0soo_dJJ!i~Vx^I_E!{>dS`*!YW`^@m; zv`(=l!}VHsm)z;sfo8ido%e}hTP)w9(EBx?-&{I!q-*s*-~H#(9iJ&x6>hv|X%+P- z-u=7h>;Io+5?%$oQrq7bDHA5|u~Iufy|UL`WnZC=?j7wMZ^N4K`yC!Rvo8{Lt6Eck_Yo?Ds#GxqW0j(tFIvx!$1Ja&vCz z#(DM6W;y?tI8wAFZ|kCS=gu*mZ%ONAVBchTHD_JW>QEltCSj7(Cnzm9#5BgcR-_%| T^%BtpW-JCzS3j3^P6U{UvUaSW+o zd^^WJ|B8W3+uYsKtHXA++Bf+h;Hhagx+KUV+%B-QQ=!R#`|DJm~J5Ss1ubVgL?GoQ9k6f5k97seT_6uqxg}%6X@x1!c zr%#<@?`;V=dOa!o_0>N=&t79|y*a+8KYyOys`dWWTffs6U;KFc@9g(&wQW)2 zt_R+HINrWVM?RJ_cEx?+rQhP@@BFJtt$d=d&$s`6{HjM0&v%FE?$YS$|J)qizxuRO z4WAxE`o1W=`&ZlauQ++%@Kt5}pg+YbaOtgeXU*m8dH;G#Toto1aJ@@xAp=9l zFWy7CxvlHFx24HzL=`YvJ-;%`w2?*p$LllS-dyY2xt2$dK{hXYN{5imgV)neDpqGd zeIv~x-f*$+lI%L$wm50WCjOd~xYT^!d-=@|m<+BQ$#4(PxF}`1fW`lZgv^_x5^C)7 ztdcKe8F5ZuFmV@qGRUQEr-Z=9!t zYMD-)eY~aiJfqz!fmjBvuM-2bwm#No{IJpgv8bNY49$;ME54|mxFTIVe{%@Ct+eiJ+0_5$5sSiugWAD)QYCVWt2^cAv-GBI}Zx-28R{e6A3iR|k0pHi4=9x|`V{G2O# z%=Z5r6_w1UT?fAZP4?e2pL^D$)We)z4L|c{9kQnzwTnVnrh{9;kT)s(3h1f@OG6>$VoibL!n(ef-@g%N-1|r+(RW%=o~o zz|VQ@&9jQyX9rmy92NIv3_f5U8KZJz)9lAz=CX@7lYryh@!PC{xWt~$(69B_Y B_7eaA literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_close_red.png b/android/app/src/main/res/drawable-xxxhdpi/icon_close_red.png new file mode 100644 index 0000000000000000000000000000000000000000..41d7659552c7076a5dbffff39e647e273050372c GIT binary patch literal 1155 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>V6pXdaSW+o zd^=}v-W3Ot*6WG0Svoy3J)Aj3t~8o+ob~b+=44raF!+O%!i1o;TYM{+J$xCbm_)mB z3C&j1F7AIiQ75@N?afcuey-UI)QdPWIy6*LQD< z5pyk6G1TY(_Wi!Ch5ddm(Rz(@>o;#+{PyhG=$p@%=$u|{?YgmQM_j#x)v?ex0p@-B zV)9Fq^rIJWE2S%iNGthszITCsQN8f6rq` zvsOx4EG%@0#rwzXsNH_QmejmwOIX!;laDQCZqR(S8wc9MGWZOAzu9pIUC3qJF-P`j z&)Qe_xAUbjupD6!R8EtBv+m0RwiYwR(jN~V*79WR?(5bo(SMPCyYlVZDxVz;C(7pK zS+oCG;atEhaOF~q^UjFPMhn~O8JPw1GaQ`@Ebs9geRYca9;>Nq#I{S>j9+8EZ+B(> zmuMVz{r!y(3pH0U3Ou;fa_511VuQADQOo=u#$ewQqIE%RCO!uqWL~NdPiE>ntdLvW zlPBXibK$fX$qu_0OiBam`CF5X85ZUE9Qe1(RV&k^`O?(K%J!bj0fFIaOL*kJ z`dniWS6jkoU&*{|#sua+Iy@4|PI?~#w`=@oRork^slWGx%kezP;+|L*^J;Zlwgp|E zd@f#&jC^!a@arCcjhr%Zm8z@FHFFSPpXp0JO0joW` z@FeM$LdLXP&lh*E+$HI{D?PSX-l#7m_4^xPZOfI$2cEs!&ZOU*!+Ne@!a5$~9V>+| z^`!7fFvp)Q$l0~#ijT*k2F(wl*=Mh|ykOhWFn=>=AbaBU4~a~>RPO9>H(%`YGCDb7 zTkWky>(^+$yvVbmm4Cyk^YW_-{+{qQQ*(LQbnL+Py}c4j#{!%U&T{8Dco--q&t%Gf zFMg##!XfEMj#L* zUz&P37iAZJfAFC5{q~eS{?4z>FDyRXe$gyAfYlOc&cvobzgLy@xG;; zQE$&~Iu1<04Ey#PsOYHFEIoXMWo}vMy(wGEnLj-2wrezepslN>#*-QT)F-yuoZ)`d zfp&eXmOP)h9WN}-MNTquejzTIa9kJUlbdqk)A~^ho#z_rvA? Wb@$8)TLCOp7(8A5T-G@yGywp481)nY literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_speaker_blue.png b/android/app/src/main/res/drawable-xxxhdpi/icon_speaker_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..ec488f8b0cf8995dc38c0d9ccec05c0bd11c7bf3 GIT binary patch literal 2311 zcmV+i3HbJjP)Px-!AV3xRCodHU2SX>MHrshyX*A|RS}8w?jU|4k{D|u27hR*s9=JMF;GbTA@+j; zZE0%)#>8kLCPs<&o3Hi?B#2Uo2_h!=0VVO5V5EwPivCdUt|}@*mFxAoJHB(}l9qO7 zKf9ehW|Pa^?fcH$`##U?%(JtzdkBe5ARrJB2nYlO0s;YnfIvVXAP^7;2m}NI*AfCa zo06?)>bqY?atT6Y9zyswOvqG(@fnQBY3%jx>8LLFj<RHq zKsWd_4?^ZBBz3f|@xl!}q~%%yN?YUeiA)Yax8pMoBq{7i|GsRzoc$$S*#(uho)2Pq z;3R+_Gz|$xm%M=~vv*eBc+qqnHWYN-5m4Vv0$5IdXbF4@9E=(AK%&A13@ugRDgp>0 z_+l)!8{Y4;l=YRugeZ^MQIC~6TtxsVp4Xu17HcI8{c0bQ@Is8G8m2EncQfq{7+pg^ zMRT-RK?n$7Zy2Ksk`EVk)rODfddYiCZ;Ylh?G6}SK>$@evO;!i;einzf-~Rc9o69< zsc(CA_%CJ|f^wO52aMbkux8tzAuP*>0E>VY9?(QjImNTCJvJ+u zB5%P|_QMD+uR$z5K7U~2_O&;~M#g34GZ#kyRXjtN72S$wanL!%GYr1c3o)*wje|;J zc$Ew$2YTrdYXLz6RU^1~~ z%zlGACY=CKJY_s99)h6TQQ0s-MJguUyKNl<=pmU(CYM5MUIG!^4!va%63Ayo1B!=b zPTQ#B!5*}1M@`sy#Y50cwE*>uS88Q5`)wg$^^WreLzj~c&@Yz3K;_9)Zr3}JP)(#J ze9W%;c&f)T0qIo6nM1HhnBx@qQD2a z`HeT=U+CsJ9=&{-B7hFK6VdI!8Ey(o_#Kk(e{g5zj6S_dxY^I}AWWs^u-dUFZRqF! zCUm(VL5GP~+8e13{$fwf?x@8u0coADEj43U@@(|wj&*vs==y1+iZpjfQ3nM76^l>!6KGj*hV8@oB)J=9$m#%-(>mCs$9YkxeL(BE6+8@#jQ$q=6Ke4bO)9{Qg65L8e7x`AG=L^4>u?fl3?C zv7^A4PFw$!z98ef_Aba6J_6E{Z3IQws2Z@s5VSCMHtQUBnatwDyj=@JDb@ZtX;o0Nv7E@I;gS-QD&tb<~ZH1CFK%ps_{j zLTzv)ES-q%h}I8_Ul$#XN1N#9Y~3soKtZ8Lf+x>E7oO3!6Ns?=PDL0Os!N-rYXkud z1n8L1RUfYO<>uZ356Gy3m2Dr>nEpLr3WQ5>ali~9KR;E|32X6%*`qH)0 z8#Le^flih)T!;1|86B)_KDWT>yCPxXSfA>B02uwoid&D(au=lMM_4|cb)g6>N!-lx zp*DJ(&=A3gomNH!qaL-`;0QmVX4AWW(g~n}!utOP7()(f1r73aZa@C7+eu}V;}2{A zwKryw8NEr|@539kV%D;AK>&;w#G5BQ5AR=T1q>uS?xZrJ-D-|Mw-5l|2d_Bok|56a z{XVI1YgI^No<%DgXm;8z&Up;qW0v?5x*N@h@kt1;)AMu`n2UlgTz%`RpEao%aB&1= z;GwNeLf&WKdm^(>?Hy2UfqA1x)$DHB&lLd_w2r!hlMEZv3pZ{F0Px9m!H{lc z^y_JN&KYq_0By{T#W+Dc{->$@)6uxA${V9=b@*}R!ZiUDsjiwCapLj7;}5b^8F5d* zFbTm^9tp34Gg79e&nTmcw&rN?4X!nFiYC?e~_M_^j| zS(sGU-;(KbDX?$xWdCyGIMfPmv zEzt*%OiBRhc_5f>g~yTRr==z#Un9x4CsI4}O!j0eG7$&}1Ox&C0fB%(Kp-Fx5C{ka h1Ofs9fq)wk_#cZm*W*(ULDm2O002ovPDHLkV1h-6D475N literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/Contents.json new file mode 100644 index 0000000000..a8d18a7af9 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_arrow_right_red.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/icon_arrow_right_red.png b/ios/StatusIm/Images.xcassets/icon_arrow_right_red.imageset/icon_arrow_right_red.png new file mode 100644 index 0000000000000000000000000000000000000000..264579208b6b2616b188abbab84f76388ead9125 GIT binary patch literal 531 zcmV+u0_^>XP)Px$%}GQ-RA>e5RJ}{XP!P|v)<|%$gF1+Vf)(9Man!jjU5bM!ody4g;w(70ITjbK zmD0L*^H1<=u(ONpAha6O^PZ6KhC=hgyHw!;OB!4zL64 zz`u1sP&4loi}RnZdn|G6Wb%Bq(de1PoH99V)T}Spy~g~ByfMCiEfkhU)kV#b3jiUu zeR5z~o37`zO^P5FAONm>0rF{D1i65;;~WVg?x;kNAL3uvOQo5Ye!mU?IaLUPKPD52 zowa83P0j1Xu?V0P5t{%i5s?IR%H>(F+g;Fk)j=(Q?RnlM9_DP2!yxMCq%Gh%mpilo zE|7q&5-<@XnTM3)WEX3-kFfLfw-CT71$jvr=Wg`|gZ;4NWu3MF1nKGk=++L0!*`vY zX`NzOi#z=Q*WnpHS9E**dhDOWIOYEio{yi?S+}{>g+-`TVZDCxgzY>;OB!4zL6406V}AumgYAfge?o Vz8<2Eu`>Vw002ovPDHLkV1kb?^(X)U literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_close_blue.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_close_blue.imageset/Contents.json new file mode 100644 index 0000000000..8b6602795e --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_close_blue.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_close_blue.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_close_blue.imageset/icon_close_blue.png b/ios/StatusIm/Images.xcassets/icon_close_blue.imageset/icon_close_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..30eeb57b2a6f4ff7fe136e847e7927aaca223627 GIT binary patch literal 562 zcmV-20?qx2P)Px$>`6pHRA>e5STRz=Fc3T?>7fQbK*bO80tz|`+AsrMsG)?Kl+2Kpf{ub0@B=D7 z0MzgRM`#V_aWayvla!gvaB3u5ckA7?BuggJq7JA7>VP_+4yXg_!2fl?NTpA1KliPv z?yNOiLqk{h)4gXYMmzp=_I_Adx;Dms8#_FkU+lcK`}^91zJS&KU-C32vIiB>(`5E> zyc!dGja*;=%UT)(J2sc&!~%%SHYby{!v)!g6cNZlE-)AmZ-ZiNfi+y56qPLB%Z|VOc#;)boY_t+I31!JKxt%7632_AxW%{ zXy{&+fLIahB9G^13+NMp{?*k6^9N%-G}Mq2TZ#z4!$L0CL|RK_N%FuhCIDbw5$NDj z(D??E8>Q-?h&7N0XYqHSl+aQ*I)vCs@6d6>rtaVLNgN_yZ#kTTjb28($n!cM6T@#( zT4&7x2{B2mL`1TH6hbLEePWUX<-AlzK5r=u zxxfGxF!5VuDL^mO0d+tfPzTfjbwC|Z2Ra@20iy$SPW46beE}M{P)Px$@<~KNRA>e5SW8aBFc6JP)h(Q&h!r>B1g%6@EOG%j11!rOxIh=IiqxKf8?Zw3 z6tJy?%)G=SgxUscZfE)8=s)!JIB3!1-C-Ed^XS#@-Z@14J*Q`@=n)$x#WB~w^5R%0Dh=!gG z5)domP~_46U;%w1@Se)A)yB=AGBnicl(=&i0cfhjW%@={%WcIdCwTy7696!u2t4PK zn>=u{3IJe8#39I|J@Iz{Nyk*O_CUye7JP_a$R@x?-Vr|jN!&rcbnYMTGTKF+*ZG(j z9%j;d&=8Uklf+6yBnwC(l#Us2;Vx@S;?H6Mw5WeFywrKlL+ulRKNHQEm}{|s(Rh4EPx(SV=@dRA>e5Sxt--MHH^rGYiU!5fTk-&ty-ci7_H45M!>pe&(!jK6$s*FRlki+CF?9T(X({4I-qc1wZdesvCxVywv;@4_rqev{I#)};9nk4@m%yWrkTwE1 zN#0e#jZE8hU+L=D|FW$mAV~bI0=ZvwvYkjm{~jPCFSxwbC4tl7_Ipdt)&1kuuL1cY z1KD{aN}q;#?ssu`Yi$H_qZ{)$m^D1hou=|u=`p90MDy?R(;S6 ziDi)7i;q|5h9|9O!v?MD*AkF}jvsvHMlNN(Nk(K4M1J&cY*mqL%S(ERX-hk0(3mM2gtUoS6A1KfNqj1 z&!yr=5Si1e46%6Q>Ox_nTGnKbj6odDEeRgJ8*VfUNyLAVmwMcbzw_RU4M8K`doi+@ zjA*5tOvim;@Erk(B(sZ_)pP#M576W z{%;omA`->UK0A1dVaJ6h&y6DNq8EM1ItqW1_>d z?G{90(_LCTH#lC{?8;;%CA2 zNEq=xa~LlEp)MpQ`F`w&HZI@kmM0#xy85GI>ar2qf`07*qoM6N<$f~XNP%m4rY literal 0 HcmV?d00001 diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 556f124009..1e46ec1312 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -25,8 +25,14 @@ [status-im.transactions.screen :refer [confirm]] [status-im.chats-list.screen :refer [chats-list]] [status-im.new-group.screen-public :refer [new-public-group]] - [status-im.new-group.screen-private :refer [new-group contact-group]] - [status-im.new-group.views.contact-list :refer [contact-group-list]] + [status-im.new-group.screen-private :refer [new-group + edit-group]] + [status-im.new-group.views.chat-group-settings :refer [chat-group-settings]] + [status-im.new-group.views.contact-list :refer [edit-group-contact-list + edit-chat-group-contact-list]] + [status-im.new-group.views.contact-toggle-list :refer [contact-toggle-list + add-contacts-toggle-list + add-participants-toggle-list]] [status-im.new-group.views.reorder-groups :refer [reorder-groups]] [status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.remove :refer [remove-participants]] @@ -108,11 +114,16 @@ :remove-participants remove-participants :chat-list main-tabs :new-group new-group + :edit-group edit-group + :chat-group-settings chat-group-settings + :add-contacts-toggle-list add-contacts-toggle-list + :add-participants-toggle-list add-participants-toggle-list + :edit-group-contact-list edit-group-contact-list + :edit-chat-group-contact-list edit-chat-group-contact-list :new-public-group new-public-group - :contact-group contact-group - :contact-group-list contact-group-list :group-settings group-settings :contact-list main-tabs + :contact-toggle-list contact-toggle-list :contact-list-search-results contacts-search-results :group-contacts contact-list :reorder-groups reorder-groups diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index a6ba5f302c..f7dca942ea 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -49,8 +49,8 @@ :font-size 14} :info-container {:margin-left 16} :contact-inner-container {:height 56} - :contacts-list-container {:padding-top 8 - :padding-bottom 8} + :contact-list-spacing {:background-color styles/color-white + :height 8} :separator {:height 0} :icon-check {:border-radius 2 :width 17 @@ -76,13 +76,17 @@ :members-text {:font-size 14} :members-text-count {:font-size 14} :add-text {:margin-left 16 - :letter-spacing 0.5 - :font-size 14} - :delete-group-text {:letter-spacing 0.5 - :font-size 14} - :delete-group-prompt-text {:font-size 14} + :line-height 24 + :font-size 16} :contact-container {:height 56} - :delete-group-container {:padding-left 72}} + :settings-group-text {:letter-spacing 0.5 + :font-size 16} + :delete-group-prompt-text {:font-size 12} + :settings-group-item {:padding-left 16 + :height 56 + :flex-direction :row + :align-items :center} + :settings-group-container {:margin-top 23}} :reorder-groups {:order-item-container {:height 56 :background-color styles/color-white} :order-item-icon {:padding-right 16} @@ -144,6 +148,5 @@ :discover {:uppercase-subtitles? false} :public-group-icon-container {:margin-top 4} :private-group-icon-container {:margin-top 6} - :group-chat-focus-line-color styles/color-light-blue :group-chat-focus-line-height 2 :public-group-chat-hash-style {:top 10 :left 4}}) diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index 31c3666e47..40f5ab7a97 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -55,7 +55,7 @@ [action-button-item {:title (label :t/new-group-chat) :buttonColor :#1abc9c - :onPress #(dispatch [:navigate-to :new-group])} + :onPress #(dispatch [:open-contact-toggle-list :chat-group])} [icon :private_group_big st/group-icon]] [action-button-item {:title (label :t/new-public-group-chat) diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index e61557dde7..9ce02127ab 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -24,29 +24,20 @@ :show (when show-search? :contact-list) :text ""))) -(defmethod nav/preload-data! :contact-group - [db [_ _ group]] +(defmethod nav/preload-data! :edit-group + [db [_ _ group group-type]] (if group - (-> db - (assoc :contact-group group - :selected-contacts (into #{} (map :identity (:contacts group))) - :new-chat-name (:name group)) - (update :toolbar-search assoc - :show :contact-list - :text "")) + (assoc db :contact-group-id (:group-id group) + :group-type group-type + :new-chat-name (:name group)) db)) -(defmethod nav/preload-data! :new-group - [db _] - (-> db - (assoc :new-group #{}) - (assoc :new-chat-name nil))) - (defmethod nav/preload-data! :contact-list [db [_ _ click-handler]] (-> db (assoc-in [:toolbar-search :show] nil) (assoc-in [:contact-list-ui-props :edit?] false) + (assoc-in [:contacts-ui-props :edit?] false) (assoc :contacts-click-handler click-handler))) (defmethod nav/preload-data! :reorder-groups @@ -342,7 +333,7 @@ (register-handler :remove-contact-from-group (u/side-effect! - (fn [{:keys [contact-groups]} [_ {:keys [whisper-identity]} {:keys [group-id]}]] + (fn [{:keys [contact-groups]} [_ whisper-identity group-id]] (let [group' (update (contact-groups group-id) :contacts (remove-contact-from-group whisper-identity))] (dispatch [:update-group group']))))) @@ -369,11 +360,12 @@ :cancel-text (label :t/cancel)})))) (register-handler - :open-contact-group-list - (after #(dispatch [:navigate-to :contact-group-list])) - (fn [db _] + :open-contact-toggle-list + (after #(dispatch [:navigate-to :contact-toggle-list])) + (fn [db [_ group-type]] (-> (assoc db :contact-group nil + :group-type group-type :selected-contacts #{} :new-chat-name "") (assoc-in [:toolbar-search :show] nil) diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index 099cfe729a..9a3882e267 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -33,7 +33,7 @@ (def toolbar-options [{:text (label :t/new-contact) :value #(dispatch [:navigate-to :new-contact])} {:text (label :t/edit) :value #(dispatch [:set-in [:contacts-ui-props :edit?] true])} - {:text (label :t/new-group) :value #(dispatch [:open-contact-group-list])} + {:text (label :t/new-group) :value #(dispatch [:open-contact-toggle-list :contact-group])} {:text (label :t/reorder-groups) :value #(dispatch [:navigate-to :reorder-groups])}]) (defn toolbar-actions [] @@ -52,7 +52,8 @@ :title (label :t/edit-contacts)}]) (defn options-btn [group] - (let [options [{:value #(dispatch [:navigate-to :contact-group group]) :text (label :t/edit-group)}]] + (let [options [{:value #(dispatch [:navigate-to :edit-group group :contact-group]) + :text (label :t/edit-group)}]] [view st/more-btn [context-menu [icon :options_gray] @@ -89,6 +90,7 @@ (when (and subtitle shadows?) [group-top-view]) [view st/contacts-list + [view st/contact-list-spacing] (doall (map (fn [contact] ^{:key contact} @@ -101,7 +103,9 @@ [{:value #(dispatch [:hide-contact contact]) :text (label :t/delete-contact) :style st/delete-contact-text} - {:value #(dispatch [:remove-contact-from-group contact group]) + {:value #(dispatch [:remove-contact-from-group + (:whisper-identity contact) + (:group-id group)]) :text (label :t/remove-from-group)}])}] (when-not (= contact (last contacts)) [view st/contact-item-separator-wrapper @@ -112,7 +116,10 @@ [view st/contact-item-separator-wrapper [view st/contact-item-separator]] [view st/show-all - [touchable-highlight (when-not edit? {:on-press #(dispatch [:navigate-to :group-contacts group])}) + [touchable-highlight {:on-press #(do + (when edit? + (dispatch [:set-in [:contact-list-ui-props :edit?] true])) + (dispatch [:navigate-to :group-contacts group]))} [view [text {:style st/show-all-text :uppercase? (get-in platform-specific [:uppercase?]) diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index c7fbd79ddc..6138cc7941 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -26,8 +26,7 @@ {:flex 1})) (def contacts-list - (merge (get-in p/platform-specific [:component-styles :contacts :contacts-list-container]) - {:background-color color-white})) + {:background-color color-white}) (def empty-contact-groups (merge contact-groups @@ -123,13 +122,8 @@ (assoc option-inner-image :tint-color color-gray)) -(def spacing-top - {:background-color color-white - :height 8}) - -(def spacing-bottom - {:background-color color-white - :height 8}) +(def contact-list-spacing + (get-in p/platform-specific [:component-styles :contacts :contact-list-spacing])) (def contact-inner-container (merge (get-in p/platform-specific [:component-styles :contacts :contact-inner-container]) diff --git a/src/status_im/contacts/subs.cljs b/src/status_im/contacts/subs.cljs index 64ad06d2fe..c63c233613 100644 --- a/src/status_im/contacts/subs.cljs +++ b/src/status_im/contacts/subs.cljs @@ -40,6 +40,16 @@ (get-in @db [:contact-groups group-id :contacts]))))] (reaction (filter-group-contacts @group-contacts @contacts))))) +(defn filter-not-group-contacts [group-contacts contacts] + (remove #(group-contacts (:whisper-identity %)) contacts)) + +(register-sub :all-not-added-group-contacts + (fn [db [_ group-id]] + (let [contacts (subscribe [:all-added-contacts]) + group-contacts (reaction (into #{} (map #(:identity %) + (get-in @db [:contact-groups group-id :contacts]))))] + (reaction (filter-not-group-contacts @group-contacts @contacts))))) + (register-sub :all-added-group-contacts-with-limit (fn [db [_ group-id limit]] (let [contacts (subscribe [:all-added-group-contacts group-id])] @@ -77,16 +87,30 @@ text (str/lower-case text)] (not= (str/index-of name text) nil))) +(defn search-filter-reaction [contacts] + (let [text (subscribe [:get-in [:toolbar-search :text]])] + (reaction + (if @text + (filter #(search-filter @text %) @contacts) + @contacts)))) + (register-sub :all-added-group-contacts-filtered (fn [_ [_ group-id]] (let [contacts (if group-id (subscribe [:all-added-group-contacts group-id]) - (subscribe [:all-added-contacts])) - text (subscribe [:get-in [:toolbar-search :text]])] - (reaction - (if @text - (filter #(search-filter @text %) @contacts) - @contacts))))) + (subscribe [:all-added-contacts]))] + (search-filter-reaction contacts)))) + +(register-sub :all-group-not-added-contacts-filtered + (fn [db _] + (let [contact-group-id (:contact-group-id @db) + contacts (subscribe [:all-not-added-group-contacts contact-group-id])] + (search-filter-reaction contacts)))) + +(register-sub :contacts-filtered + (fn [db [_ subscription-id]] + (let [contacts (subscribe [subscription-id])] + (search-filter-reaction contacts)))) (register-sub :contacts-with-letters (fn [db _] diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index 61779192f1..aed9ece9c3 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -23,7 +23,7 @@ (defn new-group-chat-view [] [view [touchable-highlight - {:on-press #(dispatch [:navigate-to :new-group])} + {:on-press #(dispatch [:open-contact-toggle-list :chat-group])} [view st/contact-container [view st/option-inner-container [view st/option-inner @@ -53,7 +53,9 @@ :extend-options (when group [{:value #(dispatch [:hide-contact row]) :text (label :t/delete-contact)} - {:value #(dispatch [:remove-contact-from-group row group]) + {:value #(dispatch [:remove-contact-from-group + (:whisper-identity row) + (:group-id group)]) :text (label :t/remove-from-group)}]) :on-click (when (and (not edit?) click-handler) #(click-handler row action params))}]))) @@ -70,6 +72,22 @@ :number-of-lines 1} label]]]]]) +(defn modal-view [action click-handler] + [view + [contact-list-entry {:click-handler #(do + (dispatch [:send-to-webview-bridge + {:event (name :webview-send-transaction)}]) + (dispatch [:navigate-back])) + :icon :icon_enter_address + :icon-style st/enter-address-icon + :label (label :t/enter-address)}] + [contact-list-entry {:click-handler #(click-handler :qr-scan action) + :icon :icon_scan_q_r + :icon-style st/scan-qr-icon + :label (label (if (= :request action) + :t/show-qr + :t/scan-qr))}]]) + (defview contact-list-toolbar-edit [group] [toolbar {:nav-action (act/back #(dispatch [:set-in [:contact-list-ui-props :edit?] false])) :actions [{:image :blank}] @@ -96,8 +114,8 @@ (defn render-separator [_ row-id _] (list-item ^{:key row-id} - [view st/contact-item-separator-wrapper - [view st/contact-item-separator]])) + [view st/contact-item-separator-wrapper + [view st/contact-item-separator]])) (defview contacts-list-view [group modal click-handler action edit?] [contacts [:all-added-group-contacts-filtered (:group-id group)] @@ -112,9 +130,10 @@ :keyboardShouldPersistTaps true :renderHeader #(list-item [view - (when show-new-group-chat? - [new-group-chat-view])]) - :renderFooter #(list-item [view st/spacing-bottom]) + (if show-new-group-chat? + [new-group-chat-view] + [view st/contact-list-spacing])]) + :renderFooter #(list-item [view st/contact-list-spacing]) :renderSeparator render-separator :style st/contacts-list}]))) @@ -123,7 +142,8 @@ modal [:get :modal] edit? [:get-in [:contact-list-ui-props :edit?]] click-handler [:get :contacts-click-handler] - group [:get :contacts-group]] + group [:get :contacts-group] + type [:get :group-type]] [drawer-view [view {:flex 1} [view @@ -133,18 +153,5 @@ [contact-list-toolbar group])] ;; todo add stub (when modal - [view - [contact-list-entry {:click-handler #(do - (dispatch [:send-to-webview-bridge - {:event (name :webview-send-transaction)}]) - (dispatch [:navigate-back])) - :icon :icon_enter_address - :icon-style st/enter-address-icon - :label (label :t/enter-address)}] - [contact-list-entry {:click-handler #(click-handler :qr-scan action) - :icon :icon_scan_q_r - :icon-style st/scan-qr-icon - :label (label (if (= :request action) - :t/show-qr - :t/scan-qr))}]]) + [modal-view action click-handler]) [contacts-list-view group modal click-handler action edit?]]]) diff --git a/src/status_im/data_store/contact_groups.cljs b/src/status_im/data_store/contact_groups.cljs index 4854c5112a..5d45cd6ddc 100644 --- a/src/status_im/data_store/contact_groups.cljs +++ b/src/status_im/data_store/contact_groups.cljs @@ -18,6 +18,15 @@ [groups] (mapv save groups)) +(defn save-property + [group-id property-name value] + (data-store/save-property group-id property-name value)) + (defn delete [group-id] (data-store/delete group-id)) + +(defn add-contacts + [group-id identities] + (data-store/add-contacts group-id identities)) + diff --git a/src/status_im/data_store/realm/contact_groups.cljs b/src/status_im/data_store/realm/contact_groups.cljs index 122e0770c0..bdf43f6936 100644 --- a/src/status_im/data_store/realm/contact_groups.cljs +++ b/src/status_im/data_store/realm/contact_groups.cljs @@ -16,6 +16,14 @@ [group update?] (realm/save @realm/account-realm :contact-group group update?)) +(defn save-property + [group-id property-name value] + (realm/write @realm/account-realm + (fn [] + (-> @realm/account-realm + (realm/get-one-by-field :contact-group :group-id group-id) + (aset (name property-name) value))))) + (defn exists? [group-id] (realm/exists? @realm/account-realm :contact-group {:group-id group-id})) @@ -23,4 +31,23 @@ (defn delete [group-id] (when-let [group (realm/get-one-by-field @realm/account-realm :contact-group :group-id group-id)] - (realm/delete @realm/account-realm group))) \ No newline at end of file + (realm/delete @realm/account-realm group))) + +(defn get-contacts + [group-id] + (-> @realm/account-realm + (realm/get-one-by-field :contact-group :group-id group-id) + (aget "contacts"))) + +(defn- save-contacts + [identities contacts] + (doseq [contact-identity identities] + (if-let [contact (.find contacts (fn [object _ _] + (= contact-identity (aget object "identity"))))] + (.push contacts (clj->js {:identity contact-identity}))))) + +(defn add-contacts + [group-id identities] + (let [contacts (get-contacts group-id)] + (realm/write @realm/account-realm + #(save-contacts identities contacts)))) \ No newline at end of file diff --git a/src/status_im/group_settings/handlers.cljs b/src/status_im/group_settings/handlers.cljs index 6eb4ae4289..d45788e960 100644 --- a/src/status_im/group_settings/handlers.cljs +++ b/src/status_im/group_settings/handlers.cljs @@ -37,10 +37,11 @@ (select-keys [:name :color]))] (assoc db :new-chat-name name :new-chat-color color + :group-type :chat-group :group-settings {}))) (register-handler :show-group-settings - (after (fn [_ _] (dispatch [:navigate-to :group-settings]))) + (after (fn [_ _] (dispatch [:navigate-to :chat-group-settings]))) prepare-chat-settings) (register-handler :set-chat-name diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 15e6b409fe..4cb9735d25 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -22,8 +22,14 @@ [status-im.accounts.screen :refer [accounts]] [status-im.transactions.screen :refer [confirm]] [status-im.chats-list.screen :refer [chats-list]] - [status-im.new-group.screen-private :refer [new-group contact-group]] - [status-im.new-group.views.contact-list :refer [contact-group-list]] + [status-im.new-group.screen-private :refer [new-group + edit-group]] + [status-im.new-group.views.chat-group-settings :refer [chat-group-settings]] + [status-im.new-group.views.contact-list :refer [edit-group-contact-list + edit-chat-group-contact-list]] + [status-im.new-group.views.contact-toggle-list :refer [contact-toggle-list + add-contacts-toggle-list + add-participants-toggle-list]] [status-im.new-group.views.reorder-groups :refer [reorder-groups]] [status-im.new-group.screen-public :refer [new-public-group]] [status-im.participants.views.add :refer [new-participants]] @@ -89,14 +95,19 @@ :remove-participants remove-participants :chat-list main-tabs :new-group new-group + :edit-group edit-group + :chat-group-settings chat-group-settings + :edit-group-contact-list edit-group-contact-list + :edit-chat-group-contact-list edit-chat-group-contact-list + :add-contacts-toggle-list add-contacts-toggle-list + :add-participants-toggle-list add-participants-toggle-list + :reorder-groups reorder-groups :new-public-group new-public-group :group-settings group-settings :contact-list main-tabs + :contact-toggle-list contact-toggle-list :contact-list-search-results contacts-search-results :group-contacts contact-list - :reorder-groups reorder-groups - :contact-group contact-group - :contact-group-list contact-group-list :new-contact new-contact :qr-scanner qr-scanner :chat chat diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 8b39a797a8..abc6e962bd 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -89,13 +89,22 @@ :letter-spacing -0.2 :font-size 17 :line-height 20} - :delete-group-text {:letter-spacing -0.2 - :font-size 17 - :line-height 20} - :delete-group-prompt-text {:font-size 13 - :letter-spacing -0.1} :contact-container {:height 63} - :delete-group-container {:padding-left 68}} + :settings-group-text {:color styles/color-light-blue + :letter-spacing -0.2 + :font-size 17 + :line-height 20} + :settings-group-item {:padding-left 16 + :height 64 + :flex-direction :row + :align-items :center} + :settings-group-container {:margin-top 25} + :settings-icon-container {:background-color "#628fe333" + :border-radius 50} + :delete-group-prompt-text {:font-size 14 + :letter-spacing -0.2} + :delete-icon-container {:background-color "#d84b4b33" + :border-radius 50}} :reorder-groups {:order-item-separator {:margin-left 16 :opacity 0.5} :order-item-container {:height 63} @@ -163,7 +172,6 @@ :discover {:uppercase-subtitles? true} :public-group-icon-container {:margin-top 2} :private-group-icon-container {:margin-top 2} - :group-chat-focus-line-color styles/color-gray5 :group-chat-focus-line-height 1 :public-group-chat-hash-style {:top 6 :left 3}}) diff --git a/src/status_im/new_group/handlers.cljs b/src/status_im/new_group/handlers.cljs index 15835f4293..499ca6fa21 100644 --- a/src/status_im/new_group/handlers.cljs +++ b/src/status_im/new_group/handlers.cljs @@ -13,6 +13,24 @@ [taoensso.timbre :as log] [status-im.navigation.handlers :as nav])) +(defn clear-toolbar-search [db] + (-> db + (assoc-in [:toolbar-search :show] nil) + (assoc-in [:toolbar-search :text] ""))) + +(defmethod nav/preload-data! :add-contacts-toggle-list + [db _] + (-> + (assoc db :selected-contacts #{}) + (clear-toolbar-search))) + + +(defmethod nav/preload-data! :add-participants-toggle-list + [db _] + (-> + (assoc db :selected-participants #{}) + (clear-toolbar-search))) + (defn deselect-contact [db [_ id]] (update db :selected-contacts disj id)) @@ -199,20 +217,6 @@ ((after create-group!)) ((after show-contact-list!)))) -(defn prepare-group-after-edit - [{:keys [selected-contacts] :as db} [_ group group-name]] - (let [contacts (mapv #(hash-map :identity %) selected-contacts) - group' (assoc group :name group-name - :contacts contacts)] - (assoc db :new-group group'))) - -(register-handler - :update-group-after-edit - (-> prepare-group-after-edit - ((enrich update-group)) - ((after update-group!)) - ((after show-contact-list!)))) - (register-handler :update-group (-> (fn [db [_ new-group]] @@ -289,3 +293,52 @@ (map-indexed vector (reverse groups-order)))] (dispatch [:update-groups new-groups]) (dispatch [:navigate-to-clean :contact-list]))))) + +(defn save-property! + [contact-group-id property-name value] + (groups/save-property contact-group-id property-name value)) + +(defn save-group-property! + [db-name property-name] + (fn [{:keys [contact-group-id] :as db} _] + (let [property (db-name db)] + (save-property! contact-group-id property-name property)))) + +(defn update-group-property + [db-name property-name] + (fn [{:keys [contact-group-id] :as db} _] + (let [property (db-name db)] + (assoc-in db [:contact-groups contact-group-id property-name] property)))) + +(register-handler :set-group-name + (after (save-group-property! :new-chat-name :name)) + (update-group-property :new-chat-name :name)) + +(defn add-selected-contacts-to-group + [{:keys [selected-contacts contact-groups contact-group-id] :as db} _] + (let [new-identities (mapv #(hash-map :identity %) selected-contacts)] + (update db [:contact-groups contact-group-id :contacts] concat new-identities))) + +(defn add-selected-contacts-to-group! + [{:keys [contact-group-id selected-contacts]} _] + (groups/add-contacts contact-group-id selected-contacts)) + +(register-handler + :add-selected-contacts-to-group + (-> add-selected-contacts-to-group + ((after add-selected-contacts-to-group!)))) + +(defn delete-group [] + (fn [{:keys [contact-group-id] :as db} _] + (assoc-in db [:contact-groups contact-group-id :pending?] true))) + +(defn delete-group! [] + (fn [{:keys [contact-group-id]} _] + (save-property! contact-group-id :pending? true))) + +(register-handler :delete-group + (after (delete-group!)) + (delete-group)) + + + diff --git a/src/status_im/new_group/screen_private.cljs b/src/status_im/new_group/screen_private.cljs index eeddd43de4..76e9fef227 100644 --- a/src/status_im/new_group/screen_private.cljs +++ b/src/status_im/new_group/screen_private.cljs @@ -1,147 +1,100 @@ (ns status-im.new-group.screen-private (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.resources :as res] + (:require [re-frame.core :refer [dispatch]] [status-im.contacts.views.contact :refer [contact-view]] - [status-im.contacts.styles :as cst] [status-im.components.react :refer [view - text - image - icon - touchable-highlight + scroll-view list-view list-item]] - [status-im.components.text-field.view :refer [text-field]] [status-im.components.confirm-button :refer [confirm-button]] - [status-im.components.styles :refer [color-blue color-gray5]] - [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar-new.view :refer [toolbar]] - [status-im.utils.platform :refer [platform-specific]] [status-im.utils.listview :refer [to-datasource]] - [status-im.new-group.views.contact :refer [new-group-contact]] [status-im.new-group.styles :as st] + [status-im.new-group.views.group :refer [group-toolbar + group-chat-settings-btns + group-name-view + add-btn + more-btn + delete-btn + separator]] [status-im.new-group.validations :as v] [status-im.i18n :refer [label]] [cljs.spec :as s])) -(defview new-chat-group-toolbar [] - [new-chat-name [:get :new-chat-name]] - (let [create-btn-enabled? (s/valid? ::v/name new-chat-name)] - [view - [status-bar] - [toolbar - {:title (label :t/new-group-chat) - :actions [{:image {:source res/v ;; {:uri "icon_search"} - :style (st/toolbar-icon create-btn-enabled?)} - :handler (when create-btn-enabled? - #(dispatch [:create-new-group-chat new-chat-name]))}]}]])) +(def contacts-limit 3) -(defview group-name-input [] - [new-chat-name [:get :new-chat-name]] +(defview group-contacts-view [group] + [contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit] + contacts-count [:all-added-group-contacts-count (:group-id group)]] [view - [text-field - {:error (when - (not (s/valid? ::v/not-illegal-name new-chat-name)) - (label :t/illegal-group-chat-name)) - :error-color color-blue - :wrapper-style st/group-chat-name-wrapper - :line-color color-gray5 - :focus-line-color st/group-chat-focus-line-color - :focus-line-height st/group-chat-focus-line-height - :label-hidden? true - :input-style st/group-chat-name-input - :auto-focus true - :on-change-text #(dispatch [:set :new-chat-name %]) - :value new-chat-name}]]) + (when (pos? contacts-count) + [separator]) + [view + (doall + (map (fn [row] + ^{:key row} + [view + [contact-view + {:contact row + :extend-options [{:value #(dispatch [:remove-contact-from-group + (:whisper-identity row) + (:group-id group)]) + :text (label :t/remove-from-group)}] + :extended? true}] + (when-not (= row (last contacts)) + [separator])]) + contacts))] + (when (< contacts-limit contacts-count) + [more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-group-contact-list])])]) -(defview new-group [] - [contacts [:all-added-contacts]] - [view st/new-group-container - [new-chat-group-toolbar] - [view st/chat-name-container - [text {:style st/members-text - :font :medium} - (label :t/group-chat-name)] - [group-name-input] - [text {:style st/members-text - :font :medium} - (label :t/members-title)] - #_[touchable-highlight {:on-press (fn [])} - [view st/add-container - [icon :add_gray st/add-icon] - [text {:style st/add-text} (label :t/add-members)]]] - [list-view - {:dataSource (to-datasource contacts) - :renderRow (fn [row _ _] - (list-item [new-group-contact row]))}]]]) +(defn save [] + (dispatch [:set-group-name])) -(defview new-contacts-group-toolbar [edit?] - [view - [status-bar] - [toolbar - {:title (label (if edit? :t/edit-group :t/new-group)) - :actions [{:image :blank}]}]]) - -(defn chat-name-view [contacts-count] - [view st/chat-name-container - [text {:style st/group-name-text} - (label :t/group-name)] - [group-name-input] - [view st/members-container - [text {:style st/members-text - :font :medium} - (label :t/group-members)] - [text {:style st/members-text-count - :font :medium} - contacts-count]] - [touchable-highlight {:on-press #(dispatch [:navigate-forget :contact-group-list])} - [view st/add-container - [view st/add-icon-container - [icon :add_blue st/add-icon]] - [text {:style st/add-text - :font :medium - :uppercase? (get-in platform-specific [:uppercase?])} - (label :t/add-members)]]]]) - -(defn delete-btn [on-press] - [touchable-highlight {:on-press on-press} - [view st/delete-group-container - [text {:style st/delete-group-text - :font :medium - :uppercase? (get-in platform-specific [:uppercase?])} - (label :t/delete-group)] - [text {:style st/delete-group-prompt-text} (label :t/delete-group-prompt)]]]) +(defview edit-group [] + [group-name [:get :new-chat-name] + group [:get-contact-group] + type [:get :group-type]] + (let [save-btn-enabled? (and (s/valid? ::v/name group-name) + (not= group-name (:name group)))] + [view st/group-container + [group-toolbar type true] + [group-name-view] + [add-btn #(dispatch [:navigate-to :add-contacts-toggle-list])] + [group-contacts-view group] + [view st/separator] + [delete-btn #(do + (dispatch [:delete-group]) + (dispatch [:navigate-to-clean :contact-list]))] + [view {:flex 1}] + (when save-btn-enabled? + [confirm-button (label :t/save) save])])) (defn render-separator [_ row-id _] (list-item ^{:key row-id} - [view cst/contact-item-separator-wrapper - [view cst/contact-item-separator]])) + [separator])) -;;TODO: should be refactored into one common function for group chats and contact groups -(defview contact-group [] +(defn render-row [row _ _] + (list-item + ^{:key row} + [contact-view {:contact row + :on-click #()}])) + +(defview new-group [] [contacts [:selected-group-contacts] group-name [:get :new-chat-name] - group [:get :contact-group]] + group-type [:get :group-type]] (let [save-btn-enabled? (and (s/valid? ::v/name group-name) (pos? (count contacts)))] - [view st/new-group-container - [new-contacts-group-toolbar (boolean group)] - [chat-name-view (count contacts)] - [list-view - {:dataSource (to-datasource contacts) - :renderRow (fn [row _ _] - (list-item - ^{:key row} - [contact-view - {:contact row - :extend-options [{:value #(dispatch [:deselect-contact (:whisper-identity row)]) - :text (label :t/remove-from-group)}] - :extended? true}])) - :renderSeparator render-separator}] - (when group - [delete-btn #(do - (dispatch [:update-group (assoc group :pending? true)]) - (dispatch [:navigate-to-clean :contact-list]))]) + [view st/group-container + [group-toolbar group-type false] + [group-name-view] + [view {:flex 1} + [list-view {:dataSource (to-datasource contacts) + :enableEmptySections true + :renderRow render-row + :bounces false + :keyboardShouldPersistTaps true + :renderSeparator render-separator}]] (when save-btn-enabled? - [confirm-button (label :t/save) (if group - #(dispatch [:update-group-after-edit group group-name]) - #(dispatch [:create-new-group group-name]))])])) + [confirm-button (label :t/save) + (if (= group-type :contact-group) + #(dispatch [:create-new-group group-name]) + #(dispatch [:create-new-group-chat group-name]))])])) diff --git a/src/status_im/new_group/screen_public.cljs b/src/status_im/new_group/screen_public.cljs index 1f2f8bbbdd..a5aad276f0 100644 --- a/src/status_im/new_group/screen_public.cljs +++ b/src/status_im/new_group/screen_public.cljs @@ -15,7 +15,6 @@ [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar.view :refer [toolbar]] [status-im.utils.listview :refer [to-datasource]] - [status-im.new-group.views.contact :refer [new-group-contact]] [status-im.new-group.styles :as st] [status-im.new-group.validations :as v] [status-im.i18n :refer [label]] @@ -56,7 +55,7 @@ [text {:style st/topic-hash} "#"]]) (defn new-public-group [] - [view st/new-group-container + [view st/group-container [new-group-toolbar] [view st/chat-name-container [text {:style st/members-text diff --git a/src/status_im/new_group/styles.cljs b/src/status_im/new_group/styles.cljs index 1ba85033aa..2a46c058b3 100644 --- a/src/status_im/new_group/styles.cljs +++ b/src/status_im/new_group/styles.cljs @@ -22,7 +22,7 @@ :height 18 :opacity (if enabled? 1 0.3)}) -(def new-group-container +(def group-container {:flex 1 :flex-direction :column :background-color color-white}) @@ -40,8 +40,12 @@ {:margin-top 21 :margin-left 16}) +(def add-button-container + {:margin-left 16}) + (def group-chat-name-input {:font-size 17 + :padding-bottom 0 :letter-spacing -0.2 :color text1-color}) @@ -57,9 +61,6 @@ :position :absolute} (get-in platform-specific [:public-group-chat-hash-style]))) -(def group-chat-focus-line-color - (get-in platform-specific [:group-chat-focus-line-color])) - (def group-chat-focus-line-height (get-in platform-specific [:group-chat-focus-line-height])) @@ -93,27 +94,36 @@ :height 64 :margin-top 12}) -(def add-icon-container - {:width 40 - :align-items :center - :justify-content :center}) +(def settings-icon-container + (merge (ps-new-group :settings-icon-container) + {:width 40 + :height 40 + :align-items :center + :justify-content :center})) (def add-icon {:align-items :center :width 24 :height 24}) -(def add-text - (merge (ps-new-group :add-text) +(def add-group-text + (merge (ps-new-group :settings-group-text) {:color color-light-blue})) +(def settings-group-text + (merge (ps-new-group :settings-group-text))) + +(def settings-group-text-container + {:padding-left 16}) + (def delete-group-text - (merge (ps-new-group :delete-group-text) + (merge (ps-new-group :settings-group-text) {:color color-light-red})) (def delete-group-prompt-text (merge (ps-new-group :delete-group-prompt-text) - {:color color-gray4})) + {:color color-gray4 + :padding-top 5})) (def contact-container (merge (ps-new-group :contact-container) @@ -139,10 +149,18 @@ {:width 12 :height 12}) -(def delete-group-container - (merge (ps-new-group :delete-group-container) - {:height 64 - :padding-top 12})) +(def settings-group-container + (ps-new-group :settings-group-container)) + +(def settings-group-item + (ps-new-group :settings-group-item)) + +(def delete-icon-container + (merge (ps-new-group :delete-icon-container) + {:width 40 + :height 40 + :align-items :center + :justify-content :center})) (def order-item-container {:background-color color-white}) @@ -178,7 +196,7 @@ (def toolbar-title-with-count-text-count (merge toolbar-title-with-count-text - {:color "#628fe3"})) + {:color color-light-blue})) (def toolbar-title-with-count {:flex-direction :row}) @@ -186,6 +204,11 @@ (def toolbar-title-with-count-container {:padding-left 6}) +(def separator + {:background-color color-gray5 + :height 1 + :opacity 0.5}) + diff --git a/src/status_im/new_group/subs.cljs b/src/status_im/new_group/subs.cljs index a7a332db47..04ecbb034f 100644 --- a/src/status_im/new_group/subs.cljs +++ b/src/status_im/new_group/subs.cljs @@ -6,10 +6,20 @@ (register-sub :is-contact-selected? (u/contains-sub :selected-contacts)) +(defn filter-selected-contacts [selected-contacts contacts] + (remove #(true? (:pending? (contacts %))) selected-contacts)) + (register-sub :selected-contacts-count (fn [_ _] - (let [contacts (subscribe [:get :selected-contacts])] - (reaction (count @contacts))))) + (let [selected-contacts (subscribe [:get :selected-contacts]) + contacts (subscribe [:get :contacts])] + ;TODO temporary, contact should be deleted from group after contact deletion from contacts + (reaction (count (filter-selected-contacts @selected-contacts @contacts)))))) + +(register-sub :selected-participants-count + (fn [_ _] + (let [selected-participants (subscribe [:get :selected-participants])] + (reaction (count @selected-participants))))) (defn filter-contacts [selected-contacts added-contacts] (filter #(selected-contacts (:whisper-identity %)) added-contacts)) @@ -19,3 +29,9 @@ (let [selected-contacts (subscribe [:get :selected-contacts]) added-contacts (subscribe [:all-added-contacts])] (reaction (filter-contacts @selected-contacts @added-contacts))))) + +(register-sub :get-contact-group + (fn [db _] + (let [contact-groups (reaction (:contact-groups @db)) + contact-group-id (reaction (:contact-group-id @db))] + (reaction (@contact-groups @contact-group-id))))) diff --git a/src/status_im/new_group/views/chat_group_settings.cljs b/src/status_im/new_group/views/chat_group_settings.cljs new file mode 100644 index 0000000000..f89a27032d --- /dev/null +++ b/src/status_im/new_group/views/chat_group_settings.cljs @@ -0,0 +1,77 @@ +(ns status-im.new-group.views.chat-group-settings + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [dispatch]] + [status-im.contacts.views.contact :refer [contact-view]] + [status-im.components.react :refer [view + scroll-view + icon + touchable-highlight]] + [status-im.components.confirm-button :refer [confirm-button]] + [status-im.new-group.styles :as st] + [status-im.new-group.views.group :refer [group-toolbar + group-chat-settings-btns + group-name-view + add-btn + more-btn + delete-btn + separator]] + [status-im.new-group.validations :as v] + [status-im.i18n :refer [label]] + [cljs.spec :as s])) + +(def contacts-limit 3) + +(defn save-chat-name [] + (dispatch [:set-chat-name])) + +(defview chat-group-contacts-view [admin?] + [contacts [:current-chat-contacts]] + (let [limited-contacts (take contacts-limit contacts) + contacts-count (count contacts)] + [view + (when (and admin? (pos? contacts-count)) + [separator]) + [view + (doall + (map (fn [row] + ^{:key row} + [view + [contact-view + {:contact row + :on-click #() + :extend-options [{:value #(do + (dispatch [:set :selected-participants #{(:whisper-identity row)}]) + (dispatch [:remove-participants])) + :text (label :t/remove)}] + :extended? admin?}] + (when-not (= row (last limited-contacts)) + [separator])]) + limited-contacts))] + (when (< contacts-limit contacts-count) + [more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-chat-group-contact-list])])])) + +(defview chat-group-members [] + [current-pk [:get :current-public-key] + group-admin [:chat :group-admin]] + (let [admin? (= current-pk group-admin)] + [view + (when admin? + [add-btn #(dispatch [:navigate-to :add-participants-toggle-list])]) + [chat-group-contacts-view admin?]])) + +(defview chat-group-settings [] + [new-chat-name [:get :new-chat-name] + chat-name [:chat :name] + type [:get :group-type]] + (let [save-btn-enabled? (and (s/valid? ::v/name new-chat-name) + (not= new-chat-name chat-name))] + [view st/group-container + [view {:flex 1} + [group-toolbar type true] + [scroll-view {:keyboardShouldPersistTaps true} + [group-name-view] + [chat-group-members] + [view st/separator] + [group-chat-settings-btns]]] + (when save-btn-enabled? + [confirm-button (label :t/save) save-chat-name])])) diff --git a/src/status_im/new_group/views/contact.cljs b/src/status_im/new_group/views/contact.cljs deleted file mode 100644 index 7097a797c7..0000000000 --- a/src/status_im/new_group/views/contact.cljs +++ /dev/null @@ -1,27 +0,0 @@ -(ns status-im.new-group.views.contact - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.components.react :refer [view icon touchable-highlight]] - [status-im.contacts.views.contact-inner :refer [contact-inner-view]] - [status-im.new-group.styles :as st] - [status-im.contacts.styles :as cst] - [status-im.components.styles :refer [color-light-blue color-gray5]] - [status-im.utils.platform :refer [platform-specific]])) - -(defn on-toggle [checked? whisper-identity] - (let [action (if checked? :deselect-contact :select-contact)] - (dispatch [action whisper-identity]))) - -;;TODO: maybe it's better to have only one global component contact-view (with the types: default, extended and toggle) -(defview new-group-contact [{:keys [whisper-identity] :as contact}] - [checked [:is-contact-selected? whisper-identity]] - [touchable-highlight {:on-press #(on-toggle checked whisper-identity)} - [view - [view (merge st/contact-container (when checked {:style st/selected-contact})) - [contact-inner-view (merge {:contact contact} - (when checked {:style st/selected-contact}))] - [view st/toggle-container - [view (merge st/icon-check-container - {:background-color (if checked color-light-blue color-gray5)}) - (when checked - [icon :check_on st/check-icon])]]]]]) diff --git a/src/status_im/new_group/views/contact_list.cljs b/src/status_im/new_group/views/contact_list.cljs index 3de834a44f..c4a1a60d2c 100644 --- a/src/status_im/new_group/views/contact_list.cljs +++ b/src/status_im/new_group/views/contact_list.cljs @@ -1,6 +1,7 @@ (ns status-im.new-group.views.contact-list (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [dispatch]] + [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.react :refer [view text list-view @@ -9,50 +10,92 @@ [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search]] [status-im.utils.listview :refer [to-datasource]] - [status-im.new-group.views.contact :refer [new-group-contact]] + [status-im.new-group.views.group :refer [separator]] [status-im.new-group.styles :as st] [status-im.contacts.styles :as cst] - [status-im.i18n :refer [label]])) + [status-im.i18n :refer [label]] + [status-im.components.toolbar-new.actions :as act])) -(defn title-with-count [title count-value] - [view st/toolbar-title-with-count - [text {:style st/toolbar-title-with-count-text - :font :toolbar-title} - title] - (when (pos? count-value) - [view st/toolbar-title-with-count-container - [text {:style st/toolbar-title-with-count-text-count - :font :toolbar-title} - count-value]])]) - -(defn contact-list-toolbar [contacts-count show-search? search-text] +(defview contact-list-toolbar [title] + [show-search [:get-in [:toolbar-search :show]] + search-text [:get-in [:toolbar-search :text]]] (toolbar-with-search - {:show-search? (= show-search? :contact-group-list) + {:show-search? (= show-search :contact-list) :search-text search-text - :search-key :contact-group-list - :custom-title (title-with-count (label :t/new-group) contacts-count) + :search-key :contact-list + :title title :search-placeholder (label :t/search-contacts)})) (defn render-separator [_ row-id _] (list-item ^{:key row-id} - [view cst/contact-item-separator-wrapper - [view cst/contact-item-separator]])) + [separator])) -(defview contact-group-list [] - [contacts [:all-added-group-contacts-filtered] - selected-contacts-count [:selected-contacts-count] - show-search [:get-in [:toolbar-search :show]] - search-text [:get-in [:toolbar-search :text]]] - [view st/new-group-container +(defn render-spacing [] + #(list-item [view cst/contact-list-spacing])) + +(defn render-row [group] + (fn [row _ _] + (list-item + ^{:key row} + [contact-view {:contact row + :extended? true + :extend-options (when group + [{:value #(dispatch [:remove-contact-from-group + (:whisper-identity row) + (:group-id group)]) + :text (label :t/remove-from-group)}]) + :on-click nil}]))) + +(defview contacts-list-view [group] + [contacts [:all-added-group-contacts-filtered (:group-id group)]] + [view {:flex 1} + [list-view {:dataSource (to-datasource contacts) + :enableEmptySections true + :renderRow (render-row group) + :bounces false + :keyboardShouldPersistTaps true + :renderSeparator render-separator + :renderFooter (render-spacing) + :renderHeader (render-spacing)}]]) + +(defview edit-group-contact-list [] + [group [:get-contact-group] + type [:get :group-type]] + [view st/group-container [status-bar] - [contact-list-toolbar selected-contacts-count show-search search-text] - [view {:flex 1} - [list-view - {:dataSource (to-datasource contacts) - :renderRow (fn [row _ _] - (list-item ^{:key row} [new-group-contact row])) - :renderSeparator render-separator - :style cst/contacts-list - :keyboardShouldPersistTaps true}]] - (when (pos? selected-contacts-count) - [confirm-button (label :t/next) #(dispatch [:navigation-replace :contact-group])])]) + [contact-list-toolbar (:name group)] + [contacts-list-view group]]) + +(defn render-chat-row [admin?] + (fn [row _ _] + (list-item + ^{:key row} + [contact-view {:contact row + :extended? admin? + :extend-options [{:value #(do + (dispatch [:set :selected-participants #{(:whisper-identity row)}]) + (dispatch [:remove-participants])) + :text (label :t/remove)}] + :on-click #()}]))) + +(defview chat-contacts-list-view [] + [contacts [:contacts-filtered :current-chat-contacts] + current-pk [:get :current-public-key] + group-admin [:chat :group-admin]] + (let [admin? (= current-pk group-admin)] + [view {:flex 1} + [list-view {:dataSource (to-datasource contacts) + :enableEmptySections true + :renderRow (render-chat-row admin?) + :bounces false + :keyboardShouldPersistTaps true + :renderSeparator render-separator + :renderFooter (render-spacing) + :renderHeader (render-spacing)}]])) + +(defview edit-chat-group-contact-list [] + [chat-name [:chat :name]] + [view st/group-container + [status-bar] + [contact-list-toolbar chat-name] + [chat-contacts-list-view]]) \ No newline at end of file diff --git a/src/status_im/new_group/views/contact_toggle_list.cljs b/src/status_im/new_group/views/contact_toggle_list.cljs new file mode 100644 index 0000000000..25178f7d6e --- /dev/null +++ b/src/status_im/new_group/views/contact_toggle_list.cljs @@ -0,0 +1,117 @@ +(ns status-im.new-group.views.contact-toggle-list + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [dispatch]] + [status-im.contacts.views.contact :refer [contact-view]] + [status-im.components.react :refer [view + text + list-view + list-item]] + [status-im.components.confirm-button :refer [confirm-button]] + [status-im.components.status-bar :refer [status-bar]] + [status-im.components.toolbar-new.view :refer [toolbar-with-search]] + [status-im.utils.listview :refer [to-datasource]] + [status-im.new-group.views.toggle-contact :refer [group-toggle-contact + group-toggle-participant]] + [status-im.new-group.views.group :refer [separator]] + [status-im.new-group.styles :as st] + [status-im.contacts.styles :as cst] + [status-im.i18n :refer [label]] + [status-im.components.toolbar-new.actions :as act])) + +(defn title-with-count [title count-value] + [view st/toolbar-title-with-count + [text {:style st/toolbar-title-with-count-text + :font :toolbar-title} + title] + (when (pos? count-value) + [view st/toolbar-title-with-count-container + [text {:style st/toolbar-title-with-count-text-count + :font :toolbar-title} + count-value]])]) + +(defview toggle-list-toolbar [title contacts-count] + [show-search [:get-in [:toolbar-search :show]] + search-text [:get-in [:toolbar-search :text]]] + (toolbar-with-search + {:show-search? (= show-search :contact-group-list) + :search-text search-text + :search-key :contact-group-list + :custom-title (title-with-count title contacts-count) + :search-placeholder (label :t/search-contacts)})) + +(defn render-separator [_ row-id _] + (list-item ^{:key row-id} + [separator])) + +(defn render-spacing [] + #(list-item [view cst/contact-list-spacing])) + +(defview contact-toggle-list [] + [contacts [:all-added-group-contacts-filtered] + selected-contacts-count [:selected-contacts-count] + group-type [:get :group-type]] + [view st/group-container + [status-bar] + [toggle-list-toolbar + (label (if (= group-type :contact-group) + :t/new-group + :t/new-group-chat)) + selected-contacts-count] + [view {:flex 1} + [list-view + {:dataSource (to-datasource contacts) + :renderRow (fn [row _ _] + (list-item ^{:key row} [group-toggle-contact row])) + :renderSeparator render-separator + :renderFooter (render-spacing) + :renderHeader (render-spacing) + :style cst/contacts-list + :keyboardShouldPersistTaps true}]] + (when (pos? selected-contacts-count) + [confirm-button (label :t/next) #(dispatch [:navigate-to :new-group])])]) + +(defview add-contacts-toggle-list [] + [contacts [:all-group-not-added-contacts-filtered] + group [:get-contact-group] + selected-contacts-count [:selected-contacts-count]] + [view st/group-container + [status-bar] + [toggle-list-toolbar (:name group) selected-contacts-count] + [view {:flex 1} + [list-view + {:dataSource (to-datasource contacts) + :renderRow (fn [row _ _] + (list-item ^{:key row} [group-toggle-contact row])) + :renderSeparator render-separator + :renderFooter (render-spacing) + :renderHeader (render-spacing) + :style cst/contacts-list + :keyboardShouldPersistTaps true}]] + (when (pos? selected-contacts-count) + [confirm-button (label :t/save) #(do + (dispatch [:add-selected-contacts-to-group]) + (dispatch [:navigate-back]))])]) + +(defview add-participants-toggle-list [] + [contacts [:contacts-filtered :all-new-contacts] + chat-name [:chat :name] + selected-contacts-count [:selected-participants-count]] + [view st/group-container + [status-bar] + [toggle-list-toolbar chat-name selected-contacts-count] + [view {:flex 1} + [list-view + {:dataSource (to-datasource contacts) + :renderRow (fn [row _ _] + (list-item ^{:key row} [group-toggle-participant row])) + :renderSeparator render-separator + :renderFooter (render-spacing) + :renderHeader (render-spacing) + :style cst/contacts-list + :keyboardShouldPersistTaps true}]] + (when (pos? selected-contacts-count) + [confirm-button (label :t/save) #(do + (dispatch [:add-new-participants]) + (dispatch [:navigate-back]))])]) + + diff --git a/src/status_im/new_group/views/group.cljs b/src/status_im/new_group/views/group.cljs new file mode 100644 index 0000000000..2a2dc96fd4 --- /dev/null +++ b/src/status_im/new_group/views/group.cljs @@ -0,0 +1,111 @@ +(ns status-im.new-group.views.group + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [dispatch]] + [status-im.contacts.styles :as cst] + [status-im.components.react :refer [view + text + icon + touchable-highlight]] + [status-im.components.text-field.view :refer [text-field]] + [status-im.components.styles :refer [color-blue color-gray5 color-light-blue]] + [status-im.components.status-bar :refer [status-bar]] + [status-im.components.toolbar-new.view :refer [toolbar]] + [status-im.utils.platform :refer [platform-specific]] + [status-im.new-group.styles :as st] + [status-im.i18n :refer [label]])) + +(defn separator [] + [view cst/contact-item-separator-wrapper + [view cst/contact-item-separator]]) + +(defview group-name-input [] + [new-group-name [:get :new-chat-name]] + [view + [text-field + {:wrapper-style st/group-chat-name-wrapper + :line-color color-gray5 + :focus-line-color color-light-blue + :focus-line-height st/group-chat-focus-line-height + :label-hidden? true + :input-style st/group-chat-name-input + :auto-focus true + :on-change-text #(dispatch [:set :new-chat-name %]) + :value new-group-name}]]) + +(defn group-toolbar [group-type edit?] + [view + [status-bar] + [toolbar + {:title (label + (if (= group-type :contact-group) + (if edit? :t/edit-group :t/new-group) + (if edit? :t/chat-settings :t/new-group-chat))) + :actions [{:image :blank}]}]]) + +(defn group-name-view [] + [view st/chat-name-container + [text {:style st/group-name-text} + (label :t/name)] + [group-name-input]]) + +(defn add-btn [on-press] + [view st/add-button-container + [touchable-highlight {:on-press on-press} + [view st/add-container + [view st/settings-icon-container + [icon :add_blue st/add-icon]] + [view st/settings-group-text-container + [text {:style st/add-group-text} + (label :t/add-members)]]]]]) + +(defn delete-btn [on-press] + [view st/settings-group-container + [touchable-highlight {:on-press on-press} + [view st/settings-group-item + [view st/delete-icon-container + [icon :close_red st/add-icon]] + [view st/settings-group-text-container + [text {:style st/delete-group-text} + (label :t/delete-group)] + [text {:style st/delete-group-prompt-text} + (label :t/delete-group-prompt)]]]]]) + +(defn group-chat-settings-btns [] + [view st/settings-group-container + [view {:opacity 0.4} + [touchable-highlight {:on-press #()} + [view st/settings-group-item + [view st/settings-icon-container + [icon :speaker_blue st/add-icon]] + [view st/settings-group-text-container + [text {:style st/settings-group-text} + (label :t/mute-notifications)]]]]] + [separator] + [touchable-highlight {:on-press #(dispatch [:clear-history])} + [view st/settings-group-item + [view st/settings-icon-container + [icon :close_blue st/add-icon]] + [view st/settings-group-text-container + [text {:style st/settings-group-text} + (label :t/clear-history)]]]] + [separator] + [touchable-highlight {:on-press #(dispatch [:leave-group-chat])} + [view st/settings-group-item + [view st/delete-icon-container + [icon :arrow_right_red st/add-icon]] + [view st/settings-group-text-container + [text {:style st/delete-group-text} + (label :t/leave-chat)]]]]]) + +(defn more-btn [contacts-limit contacts-count on-press] + [view + [view cst/contact-item-separator-wrapper + [view cst/contact-item-separator]] + [view cst/show-all + [touchable-highlight {:on-press on-press} + [view + [text {:style cst/show-all-text + :uppercase? (get-in platform-specific [:uppercase?]) + :font (get-in platform-specific [:component-styles :contacts :show-all-text-font])} + (str (- contacts-count contacts-limit) " " (label :t/more))]]]]]) + diff --git a/src/status_im/new_group/views/toggle_contact.cljs b/src/status_im/new_group/views/toggle_contact.cljs new file mode 100644 index 0000000000..da751c36b9 --- /dev/null +++ b/src/status_im/new_group/views/toggle_contact.cljs @@ -0,0 +1,38 @@ +(ns status-im.new-group.views.toggle-contact + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] + [status-im.components.react :refer [view icon touchable-highlight]] + [status-im.contacts.views.contact-inner :refer [contact-inner-view]] + [status-im.new-group.styles :as st] + [status-im.contacts.styles :as cst] + [status-im.components.styles :refer [color-light-blue color-gray5]] + [status-im.utils.platform :refer [platform-specific]])) + +(defn on-toggle [checked? whisper-identity] + (let [action (if checked? :deselect-contact :select-contact)] + (dispatch [action whisper-identity]))) + +(defn on-toggle-participant [checked? whisper-identity] + (let [action (if checked? :deselect-participant :select-participant)] + (dispatch [action whisper-identity]))) + +;;TODO: maybe it's better to have only one global component contact-view (with the types: default, extended and toggle) +(defview toogle-contact-view [{:keys [whisper-identity] :as contact} selected-key on-toggle-handler] + [checked [selected-key whisper-identity]] + [touchable-highlight {:on-press #(on-toggle-handler checked whisper-identity)} + [view + [view (merge st/contact-container (when checked {:style st/selected-contact})) + [contact-inner-view (merge {:contact contact} + (when checked {:style st/selected-contact}))] + [view st/toggle-container + [view (merge st/icon-check-container + {:background-color (if checked color-light-blue color-gray5)}) + (when checked + [icon :check_on st/check-icon])]]]]]) + +(defn group-toggle-contact [{:keys [whisper-identity] :as contact}] + [toogle-contact-view contact :is-contact-selected? on-toggle]) + +(defn group-toggle-participant [{:keys [whisper-identity] :as contact}] + [toogle-contact-view contact :is-participant-selected? on-toggle-participant]) + diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 912cc2f8e8..9fe3079bc1 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -161,10 +161,12 @@ :save "Save" :change-color "Change color" :clear-history "Clear history" + :mute-notifications "Mute notifications" + :leave-chat "Leave chat" :delete-and-leave "Delete and leave" :chat-settings "Chat settings" :edit "Edit" - :add-members "Add Members" + :add-members "Add members" :blue "Blue" :purple "Purple" :green "Green" @@ -195,7 +197,7 @@ :group-name "Group name" :edit-group "Edit group" :delete-group "Delete group" - :delete-group-prompt "This will not affect group members" + :delete-group-prompt "This will not affect contacts" :group-members "Group members" :contact-s {:one "contact" :other "contacts"} From 9f2af873937496d15cf31f4d50a5b32b98e6abb2 Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Thu, 2 Mar 2017 14:35:58 -0300 Subject: [PATCH 04/48] chats list UI refresh --- .../app/src/main/assets/fonts/Roboto-Bold.ttf | Bin 0 -> 135820 bytes .../src/main/assets/fonts/Roboto-Light.ttf | Bin 0 -> 140276 bytes .../src/main/assets/fonts/Roboto-Medium.ttf | Bin 0 -> 137308 bytes .../src/main/assets/fonts/Roboto-Regular.ttf | Bin 0 -> 145348 bytes .../icon_add.imageset/icon_add.png | Bin 353 -> 522 bytes src/status_im/android/platform.cljs | 24 ++- src/status_im/chats_list/screen.cljs | 121 ++++++++----- src/status_im/chats_list/styles.cljs | 164 ++++++++++-------- src/status_im/chats_list/subs.cljs | 19 ++ .../chats_list/views/chat_list_item.cljs | 4 +- .../chats_list/views/inner_item.cljs | 88 ++++++---- .../components/chat_icon/styles.cljs | 6 +- src/status_im/components/context_menu.cljs | 19 +- src/status_im/components/styles.cljs | 5 +- src/status_im/ios/platform.cljs | 31 +++- src/status_im/subs.cljs | 1 + src/status_im/translations/en.cljs | 5 +- src/status_im/utils/datetime.cljs | 2 +- 18 files changed, 302 insertions(+), 187 deletions(-) create mode 100644 android/app/src/main/assets/fonts/Roboto-Bold.ttf create mode 100644 android/app/src/main/assets/fonts/Roboto-Light.ttf create mode 100644 android/app/src/main/assets/fonts/Roboto-Medium.ttf create mode 100644 android/app/src/main/assets/fonts/Roboto-Regular.ttf create mode 100644 src/status_im/chats_list/subs.cljs diff --git a/android/app/src/main/assets/fonts/Roboto-Bold.ttf b/android/app/src/main/assets/fonts/Roboto-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..aaf374d2cc000c058f434f43c3b53bcaf315e2a0 GIT binary patch literal 135820 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 TYqd&VnqJLHIX9iq_T+y7#;O#c literal 0 HcmV?d00001 diff --git a/android/app/src/main/assets/fonts/Roboto-Light.ttf b/android/app/src/main/assets/fonts/Roboto-Light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..664e1b2f9dbafbf6280305123d2df7fa0c66cee9 GIT binary patch literal 140276 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/assets/fonts/Roboto-Medium.ttf b/android/app/src/main/assets/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..aa00de0ef929483ea17fbe5f3fef66de45ed724b GIT binary patch literal 137308 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/assets/fonts/Roboto-Regular.ttf b/android/app/src/main/assets/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3e6e2e76134cd6040a49ccf9961d302f7d139fcd GIT binary patch literal 145348 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 Z#48=VA6zo7lmk44ofy`glX(ebOMALFhD30_ zow<>($$_UW+QX!R#xYNt;=1S4_y2$Q zc)w$6x>S0?&z$|;BN?3)s!BD28!E1SU){!4Vc3BbfG0Zp!z0wb;yk_VoBv j`-t7f`b!VC?UGOCF+8v (or (:name item) "") + (str/lower-case)) + text (str/lower-case text)] + (not= (str/index-of name text) nil))) + +(register-sub :filtered-chats + (fn [_ _] + (let [chats (subscribe [:get :chats]) + search-text (subscribe [:get-in [:toolbar-search :text]])] + (reaction + (if @search-text + (filter #(search-filter @search-text (second %)) @chats) + @chats))))) diff --git a/src/status_im/chats_list/views/chat_list_item.cljs b/src/status_im/chats_list/views/chat_list_item.cljs index 3d92393808..f084b29cb8 100644 --- a/src/status_im/chats_list/views/chat_list_item.cljs +++ b/src/status_im/chats_list/views/chat_list_item.cljs @@ -6,7 +6,7 @@ touchable-highlight]] [status-im.chats-list.views.inner-item :refer [chat-list-item-inner-view]])) -(defn chat-list-item [[chat-id chat]] +(defn chat-list-item [[chat-id chat] edit?] [touchable-highlight {:on-press #(dispatch [:navigate-to :chat chat-id])} [view - [chat-list-item-inner-view (assoc chat :chat-id chat-id)]]]) + [chat-list-item-inner-view (assoc chat :chat-id chat-id) edit?]]]) diff --git a/src/status_im/chats_list/views/inner_item.cljs b/src/status_im/chats_list/views/inner_item.cljs index ac564fdd0f..db26966e41 100644 --- a/src/status_im/chats_list/views/inner_item.cljs +++ b/src/status_im/chats_list/views/inner_item.cljs @@ -4,6 +4,7 @@ [clojure.string :as str] [status-im.components.react :refer [view image icon text]] [status-im.components.chat-icon.screen :refer [chat-icon-view-chat-list]] + [status-im.components.context-menu :refer [context-menu]] [status-im.models.commands :refer [parse-command-message-content]] [status-im.chats-list.styles :as st] [status-im.utils.utils :refer [truncate-str]] @@ -36,16 +37,16 @@ (cond (not message) - [text {:style st/last-message-text-no-messages} + [text {:style st/last-message-text} (label :t/no-messages)] (str/blank? content) - [text {:style st/last-message-text-no-messages} + [text {:style st/last-message-text} ""] (:content content) [text {:style st/last-message-text - :number-of-lines 2} + :number-of-lines 1} (:content content)] (:command content) @@ -53,7 +54,7 @@ :else [text {:style st/last-message-text - :number-of-lines 2} + :number-of-lines 1} content])]))}))) (defview message-status [{:keys [chat-id contacts]} @@ -85,40 +86,51 @@ :font :medium} unviewed-messages]])) -(defn chat-list-item-inner-view [{:keys [chat-id name color - online group-chat contacts public?] - :as chat}] - (let [last-message (subscribe [:get-last-message chat-id]) - name (or (get-contact-translated chat-id :name name) - (generate-gfy)) - private-group? (and group-chat (not public?)) - public-group? (and group-chat public?)] +(defn options-btn [chat-id] + (let [options [{:value #(dispatch [:remove-chat chat-id]) + :text (label :t/delete-chat) + :destructive? true}]] + [view st/opts-btn + [context-menu + [icon :options_gray] + options]])) + +(defn chat-list-item-name [name group-chat? public?] + (let [private-group? (and group-chat? (not public?)) + public-group? (and group-chat? public?) + chat-name (if (str/blank? name) + (generate-gfy) + (truncate-str name 30))] + [view st/name-view + (when public-group? + [view st/public-group-icon-container + [icon :public_group st/public-group-icon]]) + (when private-group? + [view st/private-group-icon-container + [icon :private_group st/private-group-icon]]) + [text {:style st/name-text} + (if public-group? + (str "#" chat-name) + chat-name)]])) + +(defn chat-list-item-inner-view [{:keys [chat-id name color online + group-chat contacts public?] :as chat} + edit?] + (let [last-message (subscribe [:get-last-message chat-id]) + name (or (get-contact-translated chat-id :name name) + (generate-gfy))] [view st/chat-container [view st/chat-icon-container [chat-icon-view-chat-list chat-id group-chat name color online]] - [view st/item-container - [view st/name-view - (when public-group? - [view st/public-group-icon-container - [icon :public_group st/public-group-icon]]) - (when private-group? - [view st/private-group-icon-container - [icon :private_group st/private-group-icon]]) - (let [chat-name (if (str/blank? name) - (generate-gfy) - (truncate-str name 30))] - [text {:style st/name-text - :font :medium} - (if public-group? - (str "#" chat-name) - chat-name)]) - #_(when private-group? - [text {:style st/memebers-text} - (label-pluralize (inc (count contacts)) :t/members)])] - [message-content-text chat-id]] - [view - (when @last-message - [view st/status-container - [message-status chat @last-message] - [message-timestamp @last-message]]) - [unviewed-indicator chat-id]]])) + [view st/chat-info-container + [view st/item-upper-container + [chat-list-item-name name group-chat public?] + (when (and (not edit?) @last-message) + [view + [message-status chat @last-message] + [message-timestamp @last-message]])] + [view st/item-lower-container + [message-content-text chat-id] + (when-not edit? [unviewed-indicator chat-id])]] + [view st/chat-options-container + (when edit? [options-btn chat-id])]])) diff --git a/src/status_im/components/chat_icon/styles.cljs b/src/status_im/components/chat_icon/styles.cljs index de0c8248ff..bde6566d6d 100644 --- a/src/status_im/components/chat_icon/styles.cljs +++ b/src/status_im/components/chat_icon/styles.cljs @@ -3,7 +3,7 @@ online-color]])) (defn default-chat-icon [color] - {:margin 4 + {:margin 0 :width 40 :height 40 :alignItems :center @@ -204,8 +204,8 @@ (def pending-wrapper {:position :absolute - :bottom 4 - :right 5 + :bottom 0 + :right 0 :width 12 :height 12 :border-radius 6 diff --git a/src/status_im/components/context_menu.cljs b/src/status_im/components/context_menu.cljs index 3719b3c88d..6d59ec78cb 100644 --- a/src/status_im/components/context_menu.cljs +++ b/src/status_im/components/context_menu.cljs @@ -27,12 +27,13 @@ (def list-selection-fn (:list-selection-fn platform-specific)) (defn open-ios-menu [options] - (list-selection-fn {:options (mapv :text options) - :callback (fn [index] - (when (< index (count options)) - (when-let [handler (:value (nth options index))] - (handler)))) - :cancel-text (label :t/cancel)}) + (let [cancel-option {:text (label :t/cancel)} + options (conj options cancel-option)] + (list-selection-fn {:options options + :callback (fn [index] + (when (< index (count options)) + (when-let [handler (:value (nth options index))] + (handler))))})) nil) (defn context-menu [trigger options] @@ -44,8 +45,8 @@ [menu {:onSelect #(when % (do (%) nil))} [menu-trigger trigger] [menu-options st/context-menu-options - (for [{:keys [style value] :as option} options] + (for [{:keys [style value destructive?] :as option} options] ^{:key option} [menu-option {:value value} - [text {:style (merge st/context-menu-text style)} - (:text option)]])]])) \ No newline at end of file + [text {:style (merge (st/context-menu-text destructive?) style)} + (:text option)]])]])) diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 9c04928129..c5a404bf45 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -24,6 +24,7 @@ (def text1-disabled-color "#555555") (def text2-color color-gray) (def text3-color color-blue) +(def text4-color color-gray4) (def online-color color-light-blue) (def new-messages-count-color color-blue-transparent) (def chat-background color-light-gray) @@ -107,7 +108,7 @@ :justify-content :center :height 48}}}) -(def context-menu-text +(defn context-menu-text [destructive?] {:font-size 15 :line-height 20 - :color text1-color}) + :color (if destructive? color-light-red text1-color)}) diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index abc6e962bd..fea6d28b2b 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -1,5 +1,6 @@ (ns status-im.ios.platform - (:require [status-im.components.styles :as styles])) + (:require [status-im.components.styles :as styles] + [status-im.utils.utils :as utils])) (def component-styles {:status-bar {:default {:height 20 @@ -27,6 +28,19 @@ :additional-height 5} :actions-list-view {:border-bottom-color styles/color-gray3 :border-bottom-width 0.5} + :chat-list {:list-container {:background-color styles/color-white} + :chat-container {:height 74} + :chat-icon-container {:height 74} + :chat-info-container {:margin-top 14} + :chat-options-container {:margin-top 14} + :item-lower-container {:margin-top 6} + :chat-name {:height 20} + :last-message {:font-size 15 + :height 24} + :last-message-timestamp {:font-size 15} + :unread-count {:top 3} + :public-group-icon-container {:margin-top 2} + :private-group-icon-container {:margin-top 2}} :chat {:new-message {:border-top-color styles/color-gray3 :border-top-width 0.5}} :discover {:subtitle {:color styles/color-steel @@ -150,10 +164,15 @@ (def react-native (js/require "react-native")) -(defn show-action-sheet [{:keys [options callback cancel-text]}] +(defn action-sheet-options [options] + (let [destructive-opt-index (utils/first-index :destructive? options)] + (clj->js (merge {:options (mapv :text options) + :cancelButtonIndex (count options)} + (when destructive-opt-index {:destructiveButtonIndex destructive-opt-index}))))) + +(defn show-action-sheet [{:keys [options callback]}] (.showActionSheetWithOptions (.-ActionSheetIOS react-native) - (clj->js {:options (conj options cancel-text) - :cancelButtonIndex (count options)}) + (action-sheet-options options) callback)) ;; Structure to be exported @@ -164,7 +183,8 @@ :list-selection-fn show-action-sheet :tabs {:tab-shadows? false} :chats {:action-button? false - :new-chat-in-toolbar? true} + :new-chat-in-toolbar? true + :render-separator? true} :uppercase? false :contacts {:action-button? false :new-contact-in-toolbar? true @@ -174,4 +194,3 @@ :private-group-icon-container {:margin-top 2} :group-chat-focus-line-height 1 :public-group-chat-hash-style {:top 6 :left 3}}) - diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index a4b068540a..62dc54226b 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -2,6 +2,7 @@ (:require-macros [reagent.ratom :refer [reaction]]) (:require [re-frame.core :refer [register-sub subscribe]] status-im.chat.subs + status-im.chats-list.subs status-im.group-settings.subs status-im.discover.subs status-im.contacts.subs diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 9fe3079bc1..6cb45ae4c0 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -122,8 +122,11 @@ ;chats :chats "Chats" :new-chat "New chat" + :delete-chat "Delete chat" :new-group-chat "New group chat" - :new-public-group-chat "Join public group chat" + :new-public-group-chat "Join public chat" + :edit-chats "Edit chats" + :search-chats "Search chats" :empty-topic "Empty topic" :topic-format "Wrong format [a-z0-9\\-]+" :public-group-topic "Topic" diff --git a/src/status_im/utils/datetime.cljs b/src/status_im/utils/datetime.cljs index 98ea60546a..5e96371d37 100644 --- a/src/status_im/utils/datetime.cljs +++ b/src/status_im/utils/datetime.cljs @@ -30,7 +30,7 @@ (t/day today-date)) yesterday (plus today (days -1))] (cond - (before? local yesterday) (unparse (formatter "dd MMM") local) + (before? local yesterday) (unparse (formatter "dd MMM hh:mm") local) (before? local today) (label :t/datetime-yesterday) :else (today-format-fn local))))) From 8c126e07792d59a5df2e14c469dced192fe06875 Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Mon, 20 Feb 2017 21:31:32 -0300 Subject: [PATCH 05/48] start-new-chat screen UI changes --- src/status_im/android/core.cljs | 2 + src/status_im/android/platform.cljs | 11 +++ src/status_im/chats_list/screen.cljs | 4 +- src/status_im/ios/core.cljs | 2 + src/status_im/ios/platform.cljs | 11 +++ src/status_im/new_chat/screen.cljs | 108 +++++++++++++++++++++++++++ src/status_im/new_chat/styles.cljs | 85 +++++++++++++++++++++ src/status_im/translations/en.cljs | 1 + 8 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 src/status_im/new_chat/screen.cljs create mode 100644 src/status_im/new_chat/styles.cljs diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 1e46ec1312..b607fa3ce1 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -24,6 +24,7 @@ [status-im.accounts.screen :refer [accounts]] [status-im.transactions.screen :refer [confirm]] [status-im.chats-list.screen :refer [chats-list]] + [status-im.new-chat.screen :refer [new-chat]] [status-im.new-group.screen-public :refer [new-public-group]] [status-im.new-group.screen-private :refer [new-group edit-group]] @@ -113,6 +114,7 @@ :add-participants new-participants :remove-participants remove-participants :chat-list main-tabs + :new-chat new-chat :new-group new-group :edit-group edit-group :chat-group-settings chat-group-settings diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 4c12d12bfe..8a2129d009 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -56,6 +56,17 @@ :item {:status-text {:color styles/color-black :line-height 22 :font-size 14}}} + :new-chat {:option-inner-container {:height 56} + :option-icon-container {:background-color styles/color-white + :margin-top 8} + :option-name-text {:font-size 16 + :color styles/text1-color} + :contact-list-title-container {:background-color styles/color-light-gray + :padding-top 28 + :padding-bottom 20 + :margin-top 0} + :contact-list-title {:color styles/text4-color + :font-size 14}} :contacts {:subtitle {:color styles/color-gray4 :font-size 14} :subtitle-count {:color styles/color-gray4 diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index b813efce7b..31ff824cd0 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -41,7 +41,7 @@ (defn ios-toolbar-actions [] [(act/opts ios-toolbar-popup-options) - (act/add #(dispatch [:navigate-to :group-contacts :people]))]) + (act/add #(dispatch [:navigate-to :new-chat]))]) (defn toolbar-view [] [toolbar {:title (label :t/chats) @@ -67,7 +67,7 @@ :offset-y 22 :hide-shadow true :spacing 13 - :on-press #(dispatch [:navigate-to :group-contacts :people])}]) + :on-press #(dispatch [:navigate-to :new-chat])}]) (defn chat-list-padding [] [view {:height (if ios? 0 8) diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 4cb9735d25..2d2c5ee656 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -22,6 +22,7 @@ [status-im.accounts.screen :refer [accounts]] [status-im.transactions.screen :refer [confirm]] [status-im.chats-list.screen :refer [chats-list]] + [status-im.new-chat.screen :refer [new-chat]] [status-im.new-group.screen-private :refer [new-group edit-group]] [status-im.new-group.views.chat-group-settings :refer [chat-group-settings]] @@ -94,6 +95,7 @@ :add-participants new-participants :remove-participants remove-participants :chat-list main-tabs + :new-chat new-chat :new-group new-group :edit-group edit-group :chat-group-settings chat-group-settings diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index fea6d28b2b..6b82603f05 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -61,6 +61,17 @@ :icon {:padding-top 0 :bottom -4 :justify-content :flex-end}}} + :new-chat {:option-inner-container {:height 64} + :option-icon-container {:background-color styles/color-blue-transparent + :margin-top 12} + :option-name-text {:font-size 17 + :color styles/color-light-blue} + :contact-list-title-container {:background-color styles/color-white + :padding-top 19 + :padding-bottom 15 + :margin-top 16} + :contact-list-title {:color styles/text1-color + :font-size 16}} :contacts {:subtitle {:color styles/text1-color :font-size 16 :letter-spacing -0.2} diff --git a/src/status_im/new_chat/screen.cljs b/src/status_im/new_chat/screen.cljs new file mode 100644 index 0000000000..90902a1889 --- /dev/null +++ b/src/status_im/new_chat/screen.cljs @@ -0,0 +1,108 @@ +(ns status-im.new-chat.screen + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch]] + [status-im.components.react :refer [view text + linear-gradient + image + touchable-highlight + list-view + list-item]] + [status-im.contacts.views.contact :refer [contact-view]] + [status-im.components.status-bar :refer [status-bar]] + [status-im.components.toolbar-new.view :refer [toolbar-with-search]] + [status-im.components.drawer.view :refer [drawer-view]] + [status-im.new-chat.styles :as st] + [status-im.utils.listview :as lw] + [status-im.i18n :refer [label]] + [status-im.utils.platform :refer [ios?]])) + +(defn list-bottom-shadow [] + [linear-gradient {:style {:height 4} + :colors st/list-bottom-shadow}]) + +(defn list-top-shadow [] + [linear-gradient {:style {:height 3} + :colors st/list-top-shadow}]) + +(defn list-separator [] + (when ios? + [view st/list-separator-wrapper + [view st/list-separator]])) + +(defn options-list-item [{:keys [on-press icon-uri label-key]}] + [touchable-highlight {:on-press on-press} + [view st/option-container + [view st/option-inner-container + [view st/option-icon-container + [image {:source {:uri icon-uri} + :style st/option-icon}]] + [view st/option-info-container + [text {:style st/option-name-text} + (label label-key)]]]]]) + +(defn options-list [] + [view + [view (st/options-list) + [options-list-item {:on-press #(dispatch [:open-contact-toggle-list :chat-group]) + :icon-uri :icon_private_group_big + :label-key :t/new-group-chat}] + [list-separator] + [options-list-item {:on-press #(dispatch [:navigate-to :new-public-group]) + :icon-uri :icon_public_group_big + :label-key :t/new-public-group-chat}] + [list-separator] + [options-list-item {:on-press #(dispatch [:navigate-to :new-contact]) + :icon-uri :icon_add_blue + :label-key :t/add-new-contact}]] + (when-not ios? [list-bottom-shadow])]) + +(defn contact-list-row [] + (fn [row _ _] + (list-item ^{:key row} [contact-view {:contact row}]))) + +(defn contact-list-title [contact-count] + [view + [view st/contact-list-title-container + [text {:style st/contact-list-title + :font :medium} + (label :t/choose-from-contacts) + (when ios? [text {:style st/contact-list-title-count + :font :medium} + " " contact-count])]] + (when-not ios? [list-top-shadow])]) + +(defn contact-list-separator [_ row-id _] + (when ios? (list-item ^{:key row-id} [list-separator]))) + +(defview new-chat-toolbar [] + [show-search [:get-in [:toolbar-search :show]]] + [view + [status-bar] + (toolbar-with-search + {:show-search? (= show-search :contact-list) + :search-key :contact-list + :title (label :t/contacts-group-new-chat) + :search-placeholder (label :t/search-for)})]) + +(defview new-chat [] + [contacts [:all-added-group-contacts-filtered] + params [:get :contacts-click-params]] + [drawer-view + [view st/contacts-list-container + [new-chat-toolbar] + (when contacts + [list-view {:dataSource (lw/to-datasource contacts) + :enableEmptySections true + :renderRow (contact-list-row) + :bounces false + :keyboardShouldPersistTaps true + :renderHeader #(list-item + [view + [options-list] + [contact-list-title (count contacts)] + (when-not ios? [view st/spacing-top])]) + :renderSeparator contact-list-separator + :renderFooter #(list-item (when-not ios? [view + [view st/spacing-bottom] + [list-bottom-shadow]])) + :style st/contacts-list}])]]) diff --git a/src/status_im/new_chat/styles.cljs b/src/status_im/new_chat/styles.cljs new file mode 100644 index 0000000000..982858336d --- /dev/null +++ b/src/status_im/new_chat/styles.cljs @@ -0,0 +1,85 @@ +(ns status-im.new-chat.styles + (:require [status-im.components.styles :as st] + [status-im.utils.platform :as p])) + +(def list-bottom-shadow + ["rgba(24, 52, 76, 0.165)" + "rgba(24, 52, 76, 0.03)" + "rgba(24, 52, 76, 0.01)"]) + +(def list-top-shadow + ["rgba(24, 52, 76, 0.01)" + "rgba(24, 52, 76, 0.03)"]) + +(def list-separator + {:border-bottom-width 1 + :border-bottom-color st/color-gray5 + :margin-left 72 + :opacity 0.5}) + +(def list-separator-wrapper + {:background-color st/color-white + :height 1}) + +(defn options-list [] + {:padding-top (if p/ios? 0 8) + :padding-bottom (if p/ios? 0 8) + :background-color st/color-white}) + +(def option-container + {:flex-direction :row + :background-color st/color-white}) + +(def option-inner-container + (merge {:flex 1 + :flex-direction :row + :background-color st/color-white} + (get-in p/platform-specific [:component-styles :new-chat :option-inner-container]))) + +(def option-icon-container + (merge {:width 40 + :height 40 + :border-radius 50 + :margin-left 16} + (get-in p/platform-specific [:component-styles :new-chat :option-icon-container]))) + +(def option-icon + {:width 24 + :height 24 + :top 8 + :left 8}) + +(def option-info-container + {:flex 1 + :flexDirection :column + :margin-left 16 + :justifyContent :center}) + +(def option-name-text + (get-in p/platform-specific [:component-styles :new-chat :option-name-text])) + +(def contact-list-title-container + (merge {:padding-left 16} + (get-in p/platform-specific [:component-styles :new-chat :contact-list-title-container]))) + +(def contact-list-title + (get-in p/platform-specific [:component-styles :new-chat :contact-list-title])) + +(def contact-list-title-count + {:color st/text4-color + :opacity 0.5}) + +(def contacts-list-container + {:flex 1 + :margin-bottom 0}) + +(def contacts-list + {:backgroundColor st/color-light-gray}) + +(def spacing-top + {:background-color st/color-white + :height 8}) + +(def spacing-bottom + {:background-color st/color-white + :height 8}) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 6cb45ae4c0..d870ead6b0 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -154,6 +154,7 @@ :contacts-group-dapps "ÐApps" :contacts-group-people "People" :contacts-group-new-chat "Start new chat" + :choose-from-contacts "Choose from contacts" :no-contacts "No contacts yet" :show-qr "Show QR" :enter-address "Enter address" From 07f1877c6349ea6015eac7f69266a4741917e1c1 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Wed, 15 Mar 2017 21:47:48 +0200 Subject: [PATCH 06/48] defstyle and defnstyle macro --- src/status_im/android/platform.cljs | 2 - .../components/toolbar_new/styles.cljs | 14 ++--- src/status_im/contacts/styles.cljs | 10 ++-- src/status_im/ios/platform.cljs | 2 - src/status_im/utils/styles.clj | 51 +++++++++++++++++++ 5 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 src/status_im/utils/styles.clj diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 8a2129d009..8e61ee2ed2 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -23,7 +23,6 @@ :padding-left 16 :padding-right 16} :toolbar-title-container {:padding-left 30} - :toolbar-title-center? false :toolbar-with-search-content {:padding-left 30} :sized-text {:margin-top 0 :additional-height 0} @@ -127,7 +126,6 @@ :bottom-gradient {:height 3} :input-label {:left 4} :input-error-text {:margin-left 4} - :main-tab-list {:margin-bottom 20} :toolbar-nav-action {:width 56 :height 56 :align-items :center diff --git a/src/status_im/components/toolbar_new/styles.cljs b/src/status_im/components/toolbar_new/styles.cljs index f56874efdb..1db1d1bec7 100644 --- a/src/status_im/components/toolbar_new/styles.cljs +++ b/src/status_im/components/toolbar_new/styles.cljs @@ -1,4 +1,5 @@ (ns status-im.components.toolbar-new.styles + (:require-macros [status-im.utils.styles :refer [defnstyles]]) (:require [status-im.components.styles :refer [text1-color color-white color-light-gray @@ -24,13 +25,12 @@ (merge {:flex-direction :row} (get-in p/platform-specific [:component-styles :toolbar-new]))) -(defn toolbar-nav-actions-container [actions] - (let [center? (get-in p/platform-specific [:component-styles :toolbar-title-center?])] - (merge {:flex-direction :row} - (when center? - {:width (when (and actions (pos? (count actions))) - (-> (+ toolbar-icon-width toolbar-icon-spacing) - (* (count actions))))})))) +(defnstyles toolbar-nav-actions-container + [actions] + {:flex-direction :row + :ios {:width (when (and actions (pos? (count actions))) + (-> (+ toolbar-icon-width toolbar-icon-spacing) + (* (count actions))))}}) (def toolbar-title-container (merge (get-in p/platform-specific [:component-styles :toolbar-title-container]) diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index 6138cc7941..7ffbfd52db 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -1,4 +1,5 @@ (ns status-im.contacts.styles + (:require-macros [status-im.utils.styles :refer [defstyles]]) (:require [status-im.components.styles :refer [text1-color text2-color text3-color @@ -21,9 +22,10 @@ {:flex 1 :background-color toolbar-background2}) -(def contacts-list-container - (merge (get-in p/platform-specific [:component-styles :main-tab-list]) - {:flex 1})) +(defstyles contacts-list-container + {:flex 1 + :android {:margin-bottom 20} + :ios {:margin-bottom 72}}) (def contacts-list {:background-color color-white}) @@ -218,4 +220,4 @@ :justify-content :center}) (def delete-contact-text - {:color color-light-red}) \ No newline at end of file + {:color color-light-red}) diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 6b82603f05..89f94dfa66 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -22,7 +22,6 @@ :padding-left 16 :padding-right 16} :toolbar-title-container {:align-items :center} - :toolbar-title-center? true :toolbar-with-search-content {:align-items :center} :sized-text {:margin-top -5 :additional-height 5} @@ -148,7 +147,6 @@ :bottom-gradient {:height 1} :input-label {:left 0} :input-error-text {:margin-left 0} - :main-tab-list {:margin-bottom 72} :toolbar-search-input {:padding-left 10} :toolbar-nav-action {:width 46 :height 56 diff --git a/src/status_im/utils/styles.clj b/src/status_im/utils/styles.clj new file mode 100644 index 0000000000..46ac5179f7 --- /dev/null +++ b/src/status_im/utils/styles.clj @@ -0,0 +1,51 @@ +(ns status-im.utils.styles) + +(defn body [styles] + `(let [styles# ~styles + common# (dissoc styles# :android :ios) + platform# (keyword status-im.utils.platform/platform) + platform-specific# (get styles# platform#)] + (if platform-specific# + (merge common# platform-specific#) + common#))) + +(defmacro defstyles + "Defines styles symbol. + Styles parameter may contain plaform specific styles: + {:width 100 + :height 125 + :ios {:height 20} + :android {:margin-top 3}} + + Reuslting styles for Android: + {:width 100 + :height 125 + :margin-top 3} + + Resulting styles for iOS: + {:width 100 + :height 20}" + [style-name styles] + `(def ~style-name + ~(body styles))) + +(defmacro defnstyles + "Defines styles function. + Styles parameter may contain plaform specific styles: + {:width 100 + :height (* a 2) + :ios {:height (/ a 2)} + :android {:margin-top 3}} + + Resulting styles for Android (with (= a 10)): + {:width 100 + :height 20 + :margin-top 3} + + Resulting styles for iOS (with (= a 10)): + {:width 100 + :height 5}" + [style-name params styles] + `(defn ~style-name + [~@params] + ~(body styles))) From 810fe76c7c1b61c70af75db18a89480c3fa1e76d Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Wed, 15 Mar 2017 20:35:33 +0300 Subject: [PATCH 07/48] fixed address line on login and refreshed discover toolbar --- src/status_im/accounts/login/screen.cljs | 1 - src/status_im/components/toolbar_new/view.cljs | 9 ++++++++- src/status_im/discover/screen.cljs | 10 ++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/status_im/accounts/login/screen.cljs b/src/status_im/accounts/login/screen.cljs index 73faf4808e..d298b924bb 100644 --- a/src/status_im/accounts/login/screen.cljs +++ b/src/status_im/accounts/login/screen.cljs @@ -34,7 +34,6 @@ :label-color "#ffffff80" :line-color :white :input-style st/input-style - :wrapper-style (merge button-input st/address-input-wrapper) :on-change-text #(dispatch [:set-in [:login :address] %])}]]) (defview password-input [error] diff --git a/src/status_im/components/toolbar_new/view.cljs b/src/status_im/components/toolbar_new/view.cljs index 885afbe5f9..5b98f13599 100644 --- a/src/status_im/components/toolbar_new/view.cljs +++ b/src/status_im/components/toolbar_new/view.cljs @@ -68,6 +68,11 @@ (def search-text-input (r/atom nil)) +(defn- toolbar-search-submit [on-search-submit] + (let [text @(subscribe [:get-in [:toolbar-search :text]])] + (on-search-submit text) + (dispatch [:set-in [:toolbar-search :text] nil]))) + (defn- toolbar-with-search-content [{:keys [show-search? search-placeholder title @@ -80,7 +85,9 @@ :ref #(reset! search-text-input %) :auto-focus true :placeholder search-placeholder - :on-change-text #(dispatch [:set-in [:toolbar-search :text] %])}] + :on-change-text #(dispatch [:set-in [:toolbar-search :text] %]) + :on-submit-editing (when on-search-submit + #(toolbar-search-submit on-search-submit))}] (or custom-title [view [text {:style st/toolbar-title-text diff --git a/src/status_im/discover/screen.cljs b/src/status_im/discover/screen.cljs index ad77c850be..50692ab82e 100644 --- a/src/status_im/discover/screen.cljs +++ b/src/status_im/discover/screen.cljs @@ -8,8 +8,8 @@ text text-input icon]] - [status-im.components.toolbar.view :refer [toolbar-with-search]] - [status-im.components.toolbar.actions :as act] + [status-im.components.toolbar-new.view :refer [toolbar-with-search]] + [status-im.components.toolbar-new.actions :as act] [status-im.components.drawer.view :refer [open-drawer]] [status-im.components.carousel.carousel :refer [carousel]] [status-im.discover.views.popular-list :refer [discover-popular-list]] @@ -23,9 +23,10 @@ (let [hashtags (map #(str/lower-case (str/replace % #"#" "")) (re-seq #"[^ !?,;:.]+" status))] (or hashtags []))) -(defn toolbar-view [show-search?] +(defn toolbar-view [show-search? search-text] [toolbar-with-search {:show-search? show-search? + :search-text search-text :search-key :discover :title (label :t/discover) :search-placeholder (label :t/search-tags) @@ -74,12 +75,13 @@ (defview discover [current-view?] [show-search [:get-in [:toolbar-search :show]] + search-text [:get-in [:toolbar-search :text]] contacts [:get :contacts] current-account [:get-current-account] discoveries [:get-recent-discoveries]] [view st/discover-container [toolbar-view (and current-view? - (= show-search :discover))] + (= show-search :discover)) search-text] (if discoveries [scroll-view {:style (get-in platform-specific [:component-styles :main-tab-list])} [discover-popular {:contacts contacts From 990f9fcbf5104103353d691f59a69ea0dadeb776 Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Tue, 7 Mar 2017 20:06:15 -0300 Subject: [PATCH 08/48] tabs bar UI refresh --- .../src/main/res/drawable-hdpi/icon_chats.png | Bin 0 -> 765 bytes .../res/drawable-hdpi/icon_chats_active.png | Bin 0 -> 776 bytes .../main/res/drawable-hdpi/icon_contacts.png | Bin 0 -> 1091 bytes .../drawable-hdpi/icon_contacts_active.png | Bin 0 -> 1087 bytes .../main/res/drawable-hdpi/icon_discover.png | Bin 0 -> 1215 bytes .../drawable-hdpi/icon_discover_active.png | Bin 0 -> 1198 bytes .../main/res/drawable-hdpi/icon_tab_chats.png | Bin 537 -> 0 bytes .../res/drawable-hdpi/icon_tab_contacts.png | Bin 792 -> 0 bytes .../res/drawable-hdpi/icon_tab_discover.png | Bin 891 -> 0 bytes .../src/main/res/drawable-mdpi/icon_chats.png | Bin 0 -> 419 bytes .../res/drawable-mdpi/icon_chats_active.png | Bin 0 -> 427 bytes .../main/res/drawable-mdpi/icon_contacts.png | Bin 0 -> 718 bytes .../drawable-mdpi/icon_contacts_active.png | Bin 0 -> 720 bytes .../main/res/drawable-mdpi/icon_discover.png | Bin 0 -> 755 bytes .../drawable-mdpi/icon_discover_active.png | Bin 0 -> 753 bytes .../main/res/drawable-mdpi/icon_tab_chats.png | Bin 295 -> 0 bytes .../res/drawable-mdpi/icon_tab_contacts.png | Bin 504 -> 0 bytes .../res/drawable-mdpi/icon_tab_discover.png | Bin 617 -> 0 bytes .../main/res/drawable-xhdpi/icon_chats.png | Bin 0 -> 737 bytes .../res/drawable-xhdpi/icon_chats_active.png | Bin 0 -> 742 bytes .../main/res/drawable-xhdpi/icon_contacts.png | Bin 0 -> 1272 bytes .../drawable-xhdpi/icon_contacts_active.png | Bin 0 -> 1272 bytes .../main/res/drawable-xhdpi/icon_discover.png | Bin 0 -> 1536 bytes .../drawable-xhdpi/icon_discover_active.png | Bin 0 -> 1555 bytes .../res/drawable-xhdpi/icon_tab_chats.png | Bin 435 -> 0 bytes .../res/drawable-xhdpi/icon_tab_contacts.png | Bin 936 -> 0 bytes .../res/drawable-xhdpi/icon_tab_discover.png | Bin 1226 -> 0 bytes .../main/res/drawable-xxhdpi/icon_chats.png | Bin 0 -> 1228 bytes .../res/drawable-xxhdpi/icon_chats_active.png | Bin 0 -> 1234 bytes .../res/drawable-xxhdpi/icon_contacts.png | Bin 0 -> 2051 bytes .../drawable-xxhdpi/icon_contacts_active.png | Bin 0 -> 2048 bytes .../res/drawable-xxhdpi/icon_discover.png | Bin 0 -> 2428 bytes .../drawable-xxhdpi/icon_discover_active.png | Bin 0 -> 2379 bytes .../res/drawable-xxhdpi/icon_tab_chats.png | Bin 651 -> 0 bytes .../res/drawable-xxhdpi/icon_tab_contacts.png | Bin 1329 -> 0 bytes .../res/drawable-xxhdpi/icon_tab_discover.png | Bin 1512 -> 0 bytes .../main/res/drawable-xxxhdpi/icon_chats.png | Bin 0 -> 1546 bytes .../drawable-xxxhdpi/icon_chats_active.png | Bin 0 -> 1532 bytes .../res/drawable-xxxhdpi/icon_contacts.png | Bin 0 -> 2723 bytes .../drawable-xxxhdpi/icon_contacts_active.png | Bin 0 -> 2645 bytes .../res/drawable-xxxhdpi/icon_discover.png | Bin 0 -> 3257 bytes .../drawable-xxxhdpi/icon_discover_active.png | Bin 0 -> 3296 bytes .../res/drawable-xxxhdpi/icon_tab_chats.png | Bin 777 -> 0 bytes .../drawable-xxxhdpi/icon_tab_contacts.png | Bin 1775 -> 0 bytes .../drawable-xxxhdpi/icon_tab_discover.png | Bin 2016 -> 0 bytes .../Contents.json | 4 +- .../icon_chats.imageset/icon_chats.png | Bin 0 -> 1546 bytes .../icon_chats_active.imageset/Contents.json | 21 +++++ .../icon_chats_active.png | Bin 0 -> 1532 bytes .../Contents.json | 4 +- .../icon_contacts.imageset/icon_contacts.png | Bin 0 -> 2723 bytes .../Contents.json | 21 +++++ .../icon_contacts_active.png | Bin 0 -> 2645 bytes .../Contents.json | 4 +- .../icon_discover.imageset/icon_discover.png | Bin 0 -> 3257 bytes .../Contents.json | 21 +++++ .../icon_discover_active.png | Bin 0 -> 3296 bytes .../icon_tab_chats.png | Bin 651 -> 0 bytes .../icon_tab_contacts.png | Bin 1329 -> 0 bytes .../icon_tab_discover.png | Bin 1512 -> 0 bytes src/status_im/chats_list/screen.cljs | 9 +- src/status_im/chats_list/styles.cljs | 16 ++-- src/status_im/components/main_tabs.cljs | 82 +++++++----------- .../components/tabs/bottom_shadow.cljs | 6 +- src/status_im/components/tabs/styles.cljs | 31 +++---- src/status_im/components/tabs/tab.cljs | 67 ++++---------- src/status_im/components/tabs/tabs.cljs | 37 ++------ .../components/toolbar_new/styles.cljs | 4 +- src/status_im/contacts/screen.cljs | 5 +- src/status_im/contacts/styles.cljs | 31 +++---- src/status_im/db.cljs | 2 +- src/status_im/discover/screen.cljs | 5 +- src/status_im/discover/styles.cljs | 13 ++- src/status_im/subs.cljs | 10 +++ src/status_im/utils/styles.clj | 36 ++++---- 75 files changed, 219 insertions(+), 210 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_chats.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_chats_active.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_contacts.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_contacts_active.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_discover.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_discover_active.png delete mode 100644 android/app/src/main/res/drawable-hdpi/icon_tab_chats.png delete mode 100644 android/app/src/main/res/drawable-hdpi/icon_tab_contacts.png delete mode 100644 android/app/src/main/res/drawable-hdpi/icon_tab_discover.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_chats.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_chats_active.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_contacts.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_contacts_active.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_discover.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_discover_active.png delete mode 100644 android/app/src/main/res/drawable-mdpi/icon_tab_chats.png delete mode 100644 android/app/src/main/res/drawable-mdpi/icon_tab_contacts.png delete mode 100644 android/app/src/main/res/drawable-mdpi/icon_tab_discover.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_chats.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_chats_active.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_contacts.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_contacts_active.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_discover.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_discover_active.png delete mode 100644 android/app/src/main/res/drawable-xhdpi/icon_tab_chats.png delete mode 100644 android/app/src/main/res/drawable-xhdpi/icon_tab_contacts.png delete mode 100644 android/app/src/main/res/drawable-xhdpi/icon_tab_discover.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_chats.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_chats_active.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_contacts.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_contacts_active.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_discover.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_discover_active.png delete mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_tab_chats.png delete mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_tab_contacts.png delete mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_tab_discover.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_chats.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_chats_active.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_contacts.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_contacts_active.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_discover.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_discover_active.png delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_tab_chats.png delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_tab_contacts.png delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_tab_discover.png rename ios/StatusIm/Images.xcassets/{icon_tab_chats.imageset => icon_chats.imageset}/Contents.json (86%) create mode 100644 ios/StatusIm/Images.xcassets/icon_chats.imageset/icon_chats.png create mode 100644 ios/StatusIm/Images.xcassets/icon_chats_active.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_chats_active.imageset/icon_chats_active.png rename ios/StatusIm/Images.xcassets/{icon_tab_contacts.imageset => icon_contacts.imageset}/Contents.json (85%) create mode 100644 ios/StatusIm/Images.xcassets/icon_contacts.imageset/icon_contacts.png create mode 100644 ios/StatusIm/Images.xcassets/icon_contacts_active.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_contacts_active.imageset/icon_contacts_active.png rename ios/StatusIm/Images.xcassets/{icon_tab_discover.imageset => icon_discover.imageset}/Contents.json (85%) create mode 100644 ios/StatusIm/Images.xcassets/icon_discover.imageset/icon_discover.png create mode 100644 ios/StatusIm/Images.xcassets/icon_discover_active.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_discover_active.imageset/icon_discover_active.png delete mode 100644 ios/StatusIm/Images.xcassets/icon_tab_chats.imageset/icon_tab_chats.png delete mode 100644 ios/StatusIm/Images.xcassets/icon_tab_contacts.imageset/icon_tab_contacts.png delete mode 100644 ios/StatusIm/Images.xcassets/icon_tab_discover.imageset/icon_tab_discover.png diff --git a/android/app/src/main/res/drawable-hdpi/icon_chats.png b/android/app/src/main/res/drawable-hdpi/icon_chats.png new file mode 100644 index 0000000000000000000000000000000000000000..24acc606e41cbca2c3891901f1b2fd3319661657 GIT binary patch literal 765 zcmVPx%w@E}nR9Fe^mrZXHK^VvXvn-1g3Yau%lcGYaF|~U1;6>v>6Y*%&_!6t1z>i?R ziALkWt2Opu^k6h;N{q&)TCfO|R;q0=#@dvZ9cLGp?!Yn|w}6+O!_GYOyv%Q(eP(wS zaGRTfon?TC+$p8x{-bACsY(xt?40Td!4_olc>K!w1tW%R46OP(jQY?@*NHhw0aBs2 zS**qlOQOKt%8YqU#x!DLB&RK+j$vYeg! z@|3+K6QW?k42c~7MMsFFWw|_lJ#m4Zq9;VYJps}I2xheY){Vqn5mZlr*zZnBmdG6) z>@O6nNd~4h^1a^IueLQr2w{gv`hpTE38?%B%N)sKEJ30w!LrxmdlHN7DVj}gUQ0~e zdoY<~u-tCpg!xpCKhqK9h%8+`9E(nygLQMPx%!bwCyR9Fe^m(6PvK^VrL+0A!stO0HO#8~U09<=xYil9fK9u$fNkM^$CtCtr1 z3+hc&5CowhC?fQr9;_6lmC!0y)LO|waN$Jw;I*-bXHb(_S??qz1)cjlSj zzVpt^F5o_H1lAS-!W&L0C0*CPofBlah1buikAg^|=m8{1qUW5;^cT_C$io09rA(-NMH z{sCnfZ1vps?q*b9tPlM5nM!#mWDjfky`SRFjb48n#Uo!ZuKs1{ppyBr! zOit%D4P+!m-2i&~*Sw5pZx-~n!jk9yi#ff`tCZvruWQklmw~Hyf8fxb5d2<(L~;?o z7t9yT?Z-1nd|X6~E#JG(64Fz}7bq%~*Bk+QqgF_tnIR#A1dWUJ71 z+{Fd53mrE?;Q-fdr|rnkopC2SX?<)L)$`#3h1u0``bea3@(SFZ)kC)3_Dzi*bR1j1 zrWs{+MEsmx!oBBnk0@w6PpmHQEsDUFs5f`Bd)p~CVefwjS^*eV%NyO>dw5WFi4Y-} z5xwFiEix(;1fi$UCS*#ptEFuY5keGpk3S_8Bdq+V&quZqC>#9MO9Bt~?jYZd6W_YH zwYRHpazs#I+Qz0vBAF?EL#U$(nGlHBxi9W}X%wqvy>f&Y3}ZjRU{bXNDAg{>A+r39 zumaN-57re%g)>Ent=}M9vk3d;=xB`xCratvwi^M92>b=ejJ*k&(Q=jm0000Px&{YgYYR9Fe^R!eLXR}{T(YzU!{@D~(9B(QO%RsylWVh0IBQn!I=KIq%++`+f$PYjYKttHA75fK@a6_3Np+67b(J<_`QK_@(i?9|Y-4A`yFw zW8YRaLCG7vn@c6_PY|M^A}eD`Fc{d|dZ6iP1!i+dHv6;8R4P@Yl}eqCVkjbtB%FAD z392G!bb=>@fbYGM5k58!EnXbLsv-zDZ1YP*xDY(*#|!!qWckH*0KQ*R70P4=&kEoVxDY>K$@l0z+T=HfWfD9w+iv6k!*dlR%Y*x{ zDkp^y77p3uC%l|kVt+6OTG@6O=s5BmAdAbA%#7dy95>tcu^DeW7<&xBF4#F%n_ZaZ zS-p14RS@opEq1ciw&HCqv6D<*Mf- zv0vI-n=j7Hn;tm|N-N6R1)RTcY;2scPawOa^Ulv$nTlXeTrZ!*;AmT7&t)^GLQrNv zi9(6f1vU>)(s>EyUkim+j~bJ1-oCeMa{=}pJrj8=L>6^x5VR2zv;{WB|Ql!rn6EE zB@ip{xrmOu%0;RvMvn~eLqY9nGyaXTplnt-f?~EBfW1e-Ff^RAyQ^Yz;J;EqD471I zuW!5_D{#&$dVc&ZsA|!R^7)v64au(FCJLYn(zJJnotJ7RM=tMp;ARM4IMM{ye@#v= z8G}P!@i?CG*RLnNC|``>l^g5s76D07lx1FfhcdmNoB|Rxn+;!pC92vJkyI6y`z4xf zF-CqZ05#IajSVthfWI3~r@n6SH?XvRu@h7^A6}BT=?9#C!O_Fn-#-+_x9MB23?n1? zhQgG(%+BGQL$O#I%Ze%Q`V0=hkun7_zzABnZtj8cR&CD002ov JPDHLkV1fsQ`|$t( literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_contacts_active.png b/android/app/src/main/res/drawable-hdpi/icon_contacts_active.png new file mode 100644 index 0000000000000000000000000000000000000000..6df51881172b77ca088a85627e6f28eed6929eef GIT binary patch literal 1087 zcmV-F1i<@=P)Px&`AI}UR9Fe^R!K}#K^UHS4`gvcL5Wftj1e&|NIckh^Q6YO989=q+#?62;(C!N z(da=BN=ZzJsRyGTOpI|!)EE*EM&m(c(L+UwhPEK6M5G(^&G`S%zVcq*Qjj+Bz$ER= z|9{_n|JRv$^Ge86n_7XX70B!g&~(bzx_-kHGKY>{kfc9yp3F>OZBhW{4Tx_C}Z;peDB?j=WSA(qbsg z0y|-AmRl7=JR}8nSaA?biy_AOnpA}l=Y%^_@v>48+P{R>GA3*%gux*dJc7XPRW8hb zt)53IFXpfWsT%T9aV%G;)f+y~7=6h(I}QamV~;WB)xw+#t?JlpJRY8@q4w_RHqLoH zd^8-4F^{-Xm{RhPP%0_0VGp>>GX%$ynqp&V*dWg8)N%4yjk}$;_fYIoGDjUFjy!eF zXl!Z-j$oD1gt43!w>xe1l+t5>hsQYbD2#c;lk$e4>BR`=!~j@>jhKi7vaR3jve5D5({rCWwt~P2QzVE7k>%r!M1%{gOq@_rQKV*+ZXfqthjVK5W zI`T9tm)ESc<@bP*y_~TtussE^iSMXL8|*Vno;U2J5v3@;E`ltu0UVtLTdP59kWlfk z`$)+hg`@5*4JpLVAADALc(gokMs{a;5tZNC`x^ac31bZkN9mzp6t3jYVE-4`FMw5E z3_l`A!4o|dPTi=pT~5UDfuW(+9&QsD300QS!Q=@T?{D;bQQiG;z~w z48iTYlyT`5Eb*KqvG1@IT@n{&-)i}}|mwuLotG;GTJzq-O|@rA;862l&TQR zw3)bp7-2cWGJ9?(T!Ig*OwBLMB4x$dR+PzOl-!s9=%Et6INQ9@a`Sjo1f= zS)raIk>L;>=Px(c}YY;R9Fe^SIuu5MHGKCn>Ha$oWwSyg?^}6he$1@AP#MOtKb0Q04F3Qiqup8 z1BAps0Q?20J)~+wkvO1KqJjg^n`sYK0hJ14J5@hWf!2=gI4w!DGrZs0yG(Xxjhp0{ zC$0C*oA+ja`##r1TeRhYjd?&s&1WuM8jyD%zNe*lq_^qsPrUQypHZFlthLs%Qn_&rsW1*x35XB&Lfoc9OmhW}IMD@e9 z6i#(`sJ}8ko>kdQ$|Vv{hnqbzLek0SbNf!2>M=mrLf1Q^S-_57XFa ziu(GTZtCHlBgLUyZtwL_z)UP;*hJ1e2_Vl?R9$HJ7l)Bj!#gNF#sJ4s)Zf3|d|t@2 zTElhs+z167hLb%`NZ`1%HwlND8qF5nymgPR{#2x5={7xH^(@8$IT%YYDIKqzgS!Fpx2 zg=T1qPzf<~B@`G;A|Uh`DV?gJyCJr=uo&8Nnq8lq%>0Ki+)1c1?4#*@HTOfMvG_1! z=&xa=6!h}pDRTEe=gTXcE7yK5lIk>8Q@OdgM5~lYHR+$t}CEydc;N3OQOIt=Dtl9?AL1TusI~391u_D zNp4F+_`V89W(~09V&e!`Ucy$ zqW$}J(MW0t<0Y!r^IA#I>ZMqf&ClOG$iz$PEUNf_Ykt6k2eo>I`;2HVJ<4gN)7@-P_If)#8~xuG z^ANX)7rDK6I}4$LD{gR~DsU|p`h+a-_i-sOLZ3lt`_+U5=9~%kg1g^~9?MsG{dpk6 zJqC!AsvdPbrwWg0afScz6(k8Bj5{tTeb3;~PSe9D2Cfg0z{r_)m;_pi9~q(aQ_wdl z7P3mEHlkGP0|qt9Uj4=4x1X5U{cFc7rtP};nJ+Kylq>o*(qcgE9-KXK?ASl+I%vyi d%L54>_!l^5w9nM5!PNi&002ovPDHLkV1gfXP;dYM literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_discover_active.png b/android/app/src/main/res/drawable-hdpi/icon_discover_active.png new file mode 100644 index 0000000000000000000000000000000000000000..bab95befde205bacf26dd7c8a0577f44549d1d18 GIT binary patch literal 1198 zcmV;f1X25mP)Px(Xh}ptR9Fe^S5IghRT%%??9T4Akxgn^n@t9Hl#k8~k-skttIGdMwZ^E$I zV?G$>eShaS-}~P8-UB$GgAD9110w8x<6Csr%Efn3z%wV2{N;-eURV#?w8A5zwXjwl z!Uj$t%25FEPX?V&b2(8`<0Vyw#~v8j_?pMAlz3(O!8`!YB3LuuOr7|P<#A|b6Ekk9 za#0Ef0OPk;-EoSO+3`gv3zylCcVqw>AkIwF08t#43Lf{CHn4!O&y*YJaUI zjEugRUQ`v@l=(`WrFU#VwK~F`V#Rwb!qVGqLw}DAXR>L?9J18!DPvJO-^7bjLS=^nFmj5@Y~{3`0nQ|`00;-!L3ToT?pVB)D%WQyqd_E3V8p-nfvw6r&=Ha zG^YtkUOJuG%Nh9WYSw#r%rX-_+N?pP z=66Yf!dO4-7vb)QJa^jJv(HYBXW*?18R+Urcn^>HJU-Xw+=+@A35dGy z1UvC|5JmarZB1p81xDP_R~}XOtjmb4gANJ^9w6SEcst-42-D1*zfgi{VlaU$Y#Z=P z_ua@OuuUW&IyQKKc%$UKiMN9=QTpM>-^<<;)kV3hK-$+1#ez>4&Hs^2)r_U7)~Cw zz10`Ci^~g;#w=-Vc%e`kX+UEkPGH`fcst+@%uSE`OkAQmn!7o5Qkw}4(CxeKHI(wp zxPb#ZY5`AHiq*o>Jy&dO)dw09pAU4#H!XX|PW6WGeOe!)OWb*507XcDC#g>@Q?2EB zqon;VKh)=}1ST}?f|s_xnsAb9CeStCWaBpKuMz)4Q$_;~5Z@@NPpdXGrn8HHTO=j` zBHz)Oo{u`uup`-U06t>y^AQ)YUo+woDaL{;7Fiu4{Vvj`tWdyCx>0^ept^*x7Az_9 zBmJo*FDtuTTVt+&{&!EcR(Tyo!s*LozrS(WzrMB>?ZE3G19}Gj1COPjin7BwBx^=ZaKp&vY z_6;?w7lR5I8~z zqD1W20&bWP4c-~tx8@lT^A;Q@gzPbFs#1plgx|exK7&IM2!EqjTeBOeQro>`#n4S` z)(Q~8J;a1)Fd-UDh(_duczOyTo%1Lw0_0Qz{m~L#ZMoBbT{y+n&m|!Waa2lY$fgr^UpAdUr6fQU;>hQcC@X^R+Q33`YWF6x$a|i9<{qdG zEYu%ur+Hzlp-l`s)+PoP#@aJ?6MyZk^}^R4>S{}j^%Z21hc+>=vbJ9XD~sUa=@o^G zB&P2c^ttJ(U0|&Lc-96M0swt({u|6GHF)_BRO=>kk3AEj!Gvfqq5Z@L0PQ`*aXk?9 zLa-S&RjJcBEJW&!yG$(v82~`z@3?2lNWG!Tp~*P$5IUaBW_UvER(;fK&iELOV?V4Y bL{8`z=Wh4nYWPAp00000NkvXXu0mjf3f$k# diff --git a/android/app/src/main/res/drawable-hdpi/icon_tab_contacts.png b/android/app/src/main/res/drawable-hdpi/icon_tab_contacts.png deleted file mode 100644 index b7f48eff4cfdebfc2f44e2f6fd304fe2d0577cd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 792 zcmV+z1LypSP)klX% zGdy9+q2e*)^?=+n6LgH1e7mex@&$ByQ8|)S#(2pWP%>qaILSWSpE$|-4u9V+Tid?% zgmS~)uRNb0D$3<0-!^a9{FA9lVhjxADwzrnQLcuIvKLz@+M@9xX3+6YCldDlo{U-K z^2X*YWs%MnYXcN%*7(vN<#W#)^pM)UXBQ+phyVDINR!E_fhoBxYzQVt+ZgGMD8m5g zA;Cy*gvrr1!iL&BC7`jPR^N9MlF$!Vc14*=ff!f4$w#d<$$1BCpEP)y&9LdK$vW)%pHuhO1`<(`M|ZK(8}gzuZHpgfRVPy zJaDYSH)fZTtPit0@Mv7#>VOOYjA&fmn%#ltNulsnG10bRY6M|2d{s=;y}BE+rBq>@ z2){ZeV}TiO?q;8*hj^_UGWND5z+CiRy3V`=A{vdS3e)#OkkHz-rWtAuw6Kv0s2-&R z_uIkKF$oCuDToeuF&tFj@A2UC_Y1extJ6xl$MO`eY!4ndIh^UOJkfRI$oSs)iLr0`q zJ|o0Xzt>Sl(;0;e!5$(COL$1GToVm?9m`}&6&PZ<9{>zW&Sf4m98?_3oEC+L3xK%} z<%KGcIb==<|Ij9Rsg?t~Ce)|YP3=Y)Yz~<)%sB}_R-{gJ;Q8J$82FPdL(|27AOKkz z677NU-fa#0|D)-QOsRsiqK?yI1({N%Ss6g0Jz1;jyQ)X2!sXWC@A2U1@ub^^)y?zb>#fPI2h@U$uQD6e=u%+RVTDPgIkq+a{!Jz zpmVH}Z_a+Cezdu+&Ihhl_{Q4WQ;c+@Q!DVlTsBzwXRc%H{4*C;cG`WV_ZO`gO91aL RA^rdW002ovPDHLkV1n=?iQ)hN diff --git a/android/app/src/main/res/drawable-mdpi/icon_chats.png b/android/app/src/main/res/drawable-mdpi/icon_chats.png new file mode 100644 index 0000000000000000000000000000000000000000..accffce44accdb33ce9bfd18529922185534b64b GIT binary patch literal 419 zcmV;U0bKrxP)Px$T}ebiR7eeDU>F4iLVyvQ{DLK0xBUPA-y548kz(5tV|~E-nXqY~&~T8EUNCd9 zS^$%z22DQ;Zrysg<>sx2|3MhtfTrS%R2N4R z1~E|~u+p7-PBJ`y@dj*}yNfwkOi^BvVcX8*Fr!dtqJoH@pBJu4K!69#hS4AnvOHWN zltGjQXU|<{`1$KM!>iZt81CMC3f6iLNQ3wwagaPN01qNu3P9qw?mPx#WHlgzaRm#q zI--1ltbtVaz*vAU*-^y@%8Jr>(>5uVV2xx!0bT|ZLk*(M`2|Wz7jDh~mSGv_ny3;7 z?Cflh6JoqG85kHFscr!yBjaNxM#eOd!HKcn4M2VsBLm}Im__jV0J#ieWMZ7b#K7F9 zq9XkmrjT43GY%LT8r4+f8pt&eT_4;6px5sHXZSx?T~)pvUD3$q0{~AAV5>8|5QG2# N002ovPDHLkV1nK#sLlWY literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_chats_active.png b/android/app/src/main/res/drawable-mdpi/icon_chats_active.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fb8a4f8cd0430138b249eca2e56a1b2b9e923c GIT binary patch literal 427 zcmV;c0aX5pP)Px$Wl2OqR7eeDU>F4iLVyvQd~*MjE&mz*dt;L$MvRe>aogMi8L)mPY#Jyr9Aw`A z|Np&U=3=z~CP@vNeimG~`+dv#yWjqUFuKdR*%=vJ40sr{NM4qfls~f=Eh;6|M=!hS4AiWHwwO zltGjQtB-tS`1a!;!<}b88IE873f6l3#y2n@Bo30t1>ix1O94py(3P)XjI8D>&|qA_ zf~<}xA0TTWl|3*P@NhDd>QJ2OvHHMCkBfm?mSBx!d2u#|L{~PPu0ogi^8Fvf!aW~m z{QLhu16>ZQ56~46;`4GcKb}({lL<7e5nV0C7BDg}K4xTMOamD_r%<*5$gg5#WVj2n z2wsRFmq9>9GnhI4x9LiAJ%%YHm&OtYjEx4$oDJj}h*RJByWj6zy!*Wpr-BhH0RVR} VW-?A~RZ0K=002ovPDHLkV1huCuz3Ig literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_contacts.png b/android/app/src/main/res/drawable-mdpi/icon_contacts.png new file mode 100644 index 0000000000000000000000000000000000000000..c428fa16b06d9eff9e6415c688be6f4d228ec493 GIT binary patch literal 718 zcmV;<0x|uGP)Px%h)G02R7ef&RL^S@Q4pSaSrbU2#)Eq?aB_gPsa%BSAr0A=sv|X%mf-YLYgIZL<5G^EPg}KVnHvBDnDO&3rT8 zH}A*n0{nme_6cCO3m6@r3Sgyr4-hZuTp=ce-*@}w<+G)BT3rI~&5HN_+mYDRtp26p| z)Pxb+oH5aiZ6b!{C;$SF8o}258`Ce*?+sIDJVwO4KF9{b+Fh{ZJGy8twKNR^PPfFH zS@GV3!H@;(&~X;{ls$zSe_|syKY12A0IC>qGtYzJ z;q%|jF-HLzw0F_e>$gD!9;2eW=vY)rc|{{BbLlxkyp;}vqnGY#5)V0mFVXsmu z)%uBP5tmBk)k@cbb^=%791{ZDUZADD?92{*Cg{IF{p(7lvQe^vW*+B&x$M_t>-EM? zGp=g9R4!L$i6_js*=CIX1%hRw*TPTD_`hlY0)>GJR6J*`c>n+a07*qoM6N<$g1A{r At^fc4 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_contacts_active.png b/android/app/src/main/res/drawable-mdpi/icon_contacts_active.png new file mode 100644 index 0000000000000000000000000000000000000000..568786dd1abf0ad305365b193654666b65dc5aad GIT binary patch literal 720 zcmV;>0x$iEP)Px%ib+I4R7ef&RZmD1VHAIFX16eFTQ8X_VdSCkU_I)hC|Mj;!fR!Gg>(*j43oG3SbWU;!a3BKJ*LtqjWP-G`AaFCRzn}Cht_-nk zI|0w8Wu;1AOYh zB^(pay`=93pC-(srZSSG)Lr?+7EBUJgK@8b<8Q|K3gp4=A%bWzk!``mKeM}j2oT>o zTybZtz!iZF!&iXEs(FK6w;Zgk4ebb3w{o-k7)#41wqU|}^Tg+v(v_GnhPfFhN>Lm+ z+*s98ik0X23cQ~*j{#V5r%i~E2~p^D?~A1wJGXXO$MD0xj@k*ge0%R~qpk9n5W=_b zch%0iIbQ)Gy;F4aS*n2)4RX;M1hn|xuZburv545juk9oOh1gjDU2A=CB{nLYtdasB zr_Cc|+1r};RlQoL0pxUw@?%O-wS)a>=Nm8Ts2}R{i@f{?7thQKrdyxAdNlY4V zcuydq{$x0NA-zzZxCqKEEl_vZEWD$_4HDleipu!Hk7$s5{su`?~lzK1Vxp+1yY5k+!=7=Cc+&e!1j^Dz^17?hoab zjkA3E5^+(Qna@`&=uNO~IHmDu1x`oFczH9+^pV?wJkR>rRPG`vXmIDTk0YOrgUdN< zryF0(QzkWMe&A{0iw7^IX~cg>Q+qn<9|cGJOXzRA_!OaQv~y(u0000Px%tw}^dR7ef&RZDMDK@>i7c_>m^ApzuZOAN43qKPX53mev5=)z@xgKK||iQSpT zN5WR33mR8Ve8dG1LvNr~A_xd1g?qLSXOs z<@kapg2y=o0r&x!aB$jc^WJd8Le~Qj3T}hPqnb)KpM`VcDOv=JY4Sw?VMM!SnXKFG z1FibECIq&wK`68h(Qpvl?xh=qkWCU@#E_%-;o1U z$a_5=yUqz)L4^5>mv6<@u~W_(XXkq;IFf}5MD@Cn741(=v@u!mXw^muFy$7_7@Md= zFB=C!$GP+Ua=EOaq6A?Hhv&WlxUo>JfM~!3X+J0 z?L~D?rT7zPQNKTO^og*sEdCJBi)1ZcKtBsCewybFq7KC-dJ~I=p5}5l_jcpq2y?N= z$Uk(Px%t4TybR7ef&Rn1RRK@gv*eeh@m6h$#mWBEAHa??cGgCFt8K@OY@i3jh-qeuP( z{{j;e<4F=V;pk^f@nAwsS~!T5Sco771tOGwymfxB?91*e7&z-Bo86uL&CJ{1&dekF zF9rj}qH4)2)nurM&CQ($OEW~ORZ(Ora!ft%8R~vFahI2O9aw6}p)=99Fq8*q0_{YMgTHSKEx67eKR};mWBN}GS@-aE>90yha(Bf4o z2w+;)YKj+E%Y;Fne$%;*C?(D|QSy8P#Qg&{ep1j$h zon0>giG4QM$ifOxe^3^h4lmo{eD>>ZU=Vfq-~d43K?C$57X{E(m$g*fo!1-8)*C>9 zY{7$qbL_PYU2y64jT8R%(aT?yTP*1#0$sRC%#B$517J}EMLOjqj{uJQ}vK0#vFBP0JTl z=t1p3V;W~QGVxkjnP~;s>x#Y|%Kz52cFGLK{I<~OtWksBwUk@FVxCyhq{`4C13{3B z11fzh9;(p-EsIgN+$1lcEJtYCiE=g>cR!m(duwFNBsd2x`0~1Q-rNUU jSK)W(-{e5Vzj*KmT|xR*uI&HO00000NkvXXu0mjf4UA;y literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_tab_chats.png b/android/app/src/main/res/drawable-mdpi/icon_tab_chats.png deleted file mode 100644 index 6bb1a35f9219f474c85b3fce4c2aefa0f9cd4902..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4Z)cX>Ojj)B|5GtaFhBqZ;wO#4*dHuvw#Npc+W0hbF@KDX7$^h7!A zW96&5!^3Ns!~>*Nx&?C??Zu7T5|4BUrXFncj+eBn`+d6L!KLs?M<*~Uui2nI=j)tT zOXKQisXR9Db6qTE@F)Go$pZ}`@(L$SzAg7O4LB`lA|G(Qpkw0y|HeS4%wL%B>@u6g h>{&AkPi)s>5PI93v}k3`JD__RJYD@<);T3K0RV4gZUg`T diff --git a/android/app/src/main/res/drawable-mdpi/icon_tab_contacts.png b/android/app/src/main/res/drawable-mdpi/icon_tab_contacts.png deleted file mode 100644 index 277368a9b873bf85ce1acea18e14ce124dad01b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 504 zcmVNkm^$WvkQFO#mUKs=ft$V)8DC^XmuH1Y@m<#b-*<5L@R?X7 zZf#@-!^w=-H#f7AEkgdNrtM|WK~zYIy_UaD8$l3p_49sdULy zk2cZP1K!oH-(b{NpkNWcPZROWha1_ms8K~9_G;b^M%AYf2Pj}veXr*2M2({eLeJ~i zQ({9S{@Yo%<<`4CvLktP-e{`D53|+=U%X$Pm)U|n0IAlKfSoMy;^dB zqHWiDKFRCs{Fwd98>_4P6xF}-pNta7r4kd@E?a$zz9}io4wjePJ82ox(}tUlH3C%F zxMEpNPxk&-yN@5=Cqty62)be{E1A0&tfvh>uX}ty@7mM>P8{ID2o@LSIK8;#%F|r7 z`rLH%BRn6`c=ke5!LTsZ8H)o_IoM9O6+oAl6`(mo^=6k$6~bnBw24OiGK^28DbR>t z9!|GW9UN|C&qQSRiHB$r*^N%MXCImWf9OY<#c#`BAo|FT_xb#{00000NkvXXu0mjf DFQpAT diff --git a/android/app/src/main/res/drawable-xhdpi/icon_chats.png b/android/app/src/main/res/drawable-xhdpi/icon_chats.png new file mode 100644 index 0000000000000000000000000000000000000000..55ca434d476ff46f6c8140b9c926ed2d44e66e0c GIT binary patch literal 737 zcmV<70v`Q|P)Px%n@L1LRA>e5SvzY~K@|RGUq+B5kVS-KSHav^scF)QAXtRtFRVlx$uF={NQ(Rf zo3*gg##(FwX`&!$L@UiUc@{B(X2l{aJI;w-+{`^Ud+suO_ZD-Sx#zp*ocX>p5B33g z^BwRV@EsUr2b6U3=PzH+qK!JVu1IrS#wn$C71YCp+T5GYy17p0tY_86vq6z3URvu3 z4PCc6iUm*sJ2`Ei;~*B0Hd*O>UVyYy{fhG|(67!)>lW<5Mq_8Tt##d;_*3`&yZ4{$ z&`kId0UUWL(~0qmn7$EUWcUJp9R0+HkDJ)tJ7Ck3#Igncfsr#{cmAy8&UZxU?wuKw z$3{^s7EVU;3AZgttetE75dn69)ThpK#^D@Bxp6pGH^iI?pl!n$hjSR^#^GGu5OXGg z_B>}C&S8`rhjVp9%$Wc>u$*x?hf!`E&eaVuX9DQ9SzX(};kWN-wSJ$B0irE&>{LcYgo`j;jaP%0HMeLX=g^zD2TF02GWtm<>)Ry{U3o%yQ?6yf@zg-vQtcq=UgR ToGAle00000NkvXXu0mjfm0wu> literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_chats_active.png b/android/app/src/main/res/drawable-xhdpi/icon_chats_active.png new file mode 100644 index 0000000000000000000000000000000000000000..9a2f4860a30acd56525cfeb392f9d90c7dec0da2 GIT binary patch literal 742 zcmVPx%ph-kQRA>e5STSoAK@grfU(UN26(Jz{-V>uJT9^W6SAi-kfYQw$%ysUlD4GXQO=(P#eu((lQ|jTuWb;Kbua`9T{8rIIRpg16QmPRl z#s%Cx!~!V6?$Girj)Pc0`E+GFIsvje9h{dtfrG29EOX6td$-n&`@Nc1M!$c&{LOT= z!cGa`$V-`yo(D;apyg6()f0 zJU2L;!zeZj=kjW-Fah*nxxwKaMzL8qmsewj37~E>_k07^zHC8vE9%W;b6qHpuO^x` z^A|VEyAMvpIKo_59$zkAV}+f7PFVKr1e9HIb3bz4;17!dzPDvV&iL}CF$;UTzx>o{C&_;BQ~IIQ3P`(Dp=FG$4gt4H^}DVJdL z&o-=o--efOHdo@mST{Hy4zs3|RGbTS9~N8no9N*zN0!5^5zr%t(24(ns>N1gIwscU z2%DHy0ub<(Cirx+IU^BalYot&7EEaYG^a!$eod~^cl82xuFbP>ARN1N20JD}5)ogk ziTHGW#Z7$4Tu(Ljw;z5h(@EQLk`?sS6VHd$EA_!o8n1E|w^0vqc620oM31aW!sgz> zD}?Q_bK$gY#B7{XfB*mh07*qoM6N<$f+n$Ang9R* literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_contacts.png b/android/app/src/main/res/drawable-xhdpi/icon_contacts.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f1ab41f2eaf56f48794c9a4a05158cec0e0f48 GIT binary patch literal 1272 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 Q4GdrgPgg&ebxsLQ0H(CFsQ>@~ diff --git a/android/app/src/main/res/drawable-xhdpi/icon_tab_contacts.png b/android/app/src/main/res/drawable-xhdpi/icon_tab_contacts.png deleted file mode 100644 index 9192c55522d6ac78452e3611ebe9ff96306e5dd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 936 zcmV;Z16TZsP)#M&?PK^C=nNsLXc1iGyya;#b^@#cklQo=dG=L`rCqtpI*A?eGu!kZukA0|iK{bm#A z#=zK=e>7jk0|-f9B05a>5^o?L^Trza6E;^7GDPfga!jP&Kup@6lmFrY95E>dk{?nA zgp57SjUIJ`q&<0^GLV=m3j(uNa~{w#&kLZd)rqIU&i%W^0PG!~vc4N;*&9St-cM=0 zGLc!q<+L%>Q%+M&$+`QUx>7uKr95eJFtcz%AQ;uwr?yf;z@_5NG}V+a)KiYo)hQYc zbhSFK6`!Q3ri89mr><`G8SpgNGtxF4+6*KItnRkyDEM+(n}NOK(~PuDhc*N2yWxzq zO@}rE%ibW{2a&YxwhtmKdxN^V)n`BgGYcozn%F*wFtc!?D;oovGjSjoJf;n^^J&S<)CL*YSTE%{2vY;8tTm0FNHnd01zs%4MUS^VblOGifQ2UF5cj%yRGRzAziUa9))XeiZjdC9t*=W^G5` z8uy0ylNYA#b-9{t6;?58HEpjOpK>Ed9Vz(RfFYvqh@S@LJ0U~Jx#WkGfy9~9L{22B zF=0M4{3kK~!jg-I~u&8%Gq!zi+&2Ao!5T753Uh6svzilM_-8s8{eM z97=LYf)t6il0m3P)UyRh4V5CHBvR8{!Ueci9FRDLO8o~~C<^x4s8%=_Fy3We54(1- zW93G454%Y_Ey~_6+ zC7vbbIRGIqlQy8pL}|5`7SazQ$8K(PY{0}S0)y}MM-up%fT$;#Enpxgfcb-4+VeN} zaPH(DM+W@x;$2KJl{El&{EBqQj;WZ*rw?yuTXk${z|6DUT^76sKx>yehv+0Jx%edd zwpl09>|$y~pOk{PaP{H=K$C*EQY-povrd-vRVvj!$s5wLfgPfa`kXo{(< zO{^kt@y8ki2H)$CaCKXy7w*^^t5id1?p40uIF)~Q>LJxG7|5x8;;YINyXpa>#Iv8e zcmN?464*;Q{LSq1+SZ%A(X#@dU zSVbZd#Bfx_&Hey>+3=J_g9VKPcuA?ncYWL+_z&*$`IhvkgrNaTY$6)O&_ED9Dpjxl z_0K7O+dT3*{0SYOf1${bI!Y|tBK~G5fMNUJO+qE)Ni86bafU@K0XHXtjMxwqkxaU&da}z+S$LqoSjiZY`0ZZABD~ zP3{kzz+*C3AOB|tWBoo@%t)>1Yha9f8Rf^ZFpiGTEy4LR z^n&603F`>L`qGq^w9f;)0gxvHyyo+MA<652eI_=_ybhq)6(!y%mQCIOYy+03;{_&4 zcUO~hm?&K-h*VPvwU-tc$aPPaGZ@IJy|hqiR}Dx%h#U)GzB{sAK7%6P=U-;6aIFj7 o7rC~d8q{-bKlW%uH$S)eA5^*kJhc&9-2eap07*qoM6N<$f;qM*;{X5v diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_chats.png b/android/app/src/main/res/drawable-xxhdpi/icon_chats.png new file mode 100644 index 0000000000000000000000000000000000000000..bf795c4c7f72ab6944144b5c2505d5397428cfe2 GIT binary patch literal 1228 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_contacts_active.png b/android/app/src/main/res/drawable-xxhdpi/icon_contacts_active.png new file mode 100644 index 0000000000000000000000000000000000000000..e4f0b065d8e25713fb5e26f49e064ea6945e75ec GIT binary patch literal 2048 zcmV+b2>Px+x=BPqRCodHT5D_-MHHTy-ac-{0tJ!w76~+wKT07XiaY|Epg)We6GUPn2HJq~ zXd&PaV}PP2Bx;26rnV5lL`_W4kVv8=l;8_7X|GrV5_#7{J7-Oa?tFtpL35v{`zR(FE<`rH3V05yuF#8QNXH(h{wB`uQ z4tqO)1Y#EHBImB~Ia_|olG?R6bhpX)6)~=QZ#03N-GFSA9B$O2VGL6YOsg5Rc5i1{ zh@wUW@khuzh(p-~%|23D;uOLG<+PeXA?0~-5lQO{o8Dcmv_d;OK zliP&O82KS!PZSNHQHr~f&xGdL+ zm67imBJJ|ES!Xja4HM*a`M-c!vO%jeT$bx3lOI2xoQL`6Pu8!y9k3#px)q}p3=ssg zVGGQL*P@|P-*FwTn@DnaIX<1J&tThW(IuXbtDB%J9ySr)ob3jU=6ks993zo_Ho-d~ zx(jFHklE7+R-!?4w&^Cw=ku+EO-6yvaTMaLUwjdKaKv^McK=#J zgFx4;QU@PDZfQ5y4rd_FOd?zD3B$ieh7n*8_P@k(zTU`!MR7 zJw1P@wwyvZ<7(1PExxnxbQh=aOSK#7#tpNk+n-exN|R3AF$mV_Q^K~Jfgx;!HUQlO z+3oh@5V{7n!6%Z!gF_gJ`qHmWH$gLsaWCxU-Z$zBMrjYQ{*%-p-AX$(IvMw$yEM@Gly|N5vlZ5?F0Ng0jn@x~h^|qkx79 z0&;9lmv6V$gcS_kUpCFY8AuAt#;)0Wy;PEd#~`;@D7SGEZ3OKyx)bJw|1d@GDjyy= z`9p3FsW`aa(IJnc^=z0Rd4Q365JvOCs3<&e79Ju>SPv@S<6Z|T%g3OTFJmds0CXM` za?D1_*~6QQT9tjV*X8>?Q?bOJW0bB^lC6{jya7b;#`>y~6Uz2f*HI3o5?1TiQ&C)9 z*0MAVV>|l0*~NHcnVXM@~YQ_R35Ez>{FFdbecwx z0#o&}qNZ~jrN)E2D!9f@jLG`?O%6>-@u(71vAgpI<* zMG#a3E3+v1^@-A)i>ZKP`^#(GDPw4wd{JP(I!7bOq<~B|n+N&CM()7t>SeM$V8csMsH7b;)e!?W!|~ zJKp5-e-ETAQ3t`dVU_s}WIQmtZU7ksbc+DI=)ynVXD(d!n)5kX%?N=$*q~Ox1{L0r z_(PQ-sQny;C3IE1nzj~ifTGXO^rNr@l%@57Z{+3Vlpb6^>EBp0lfGiGOMX*?96r$R zS9}>j4!4v|@`pnSzqTYK=yE$NhF4?{S2cR{-;q#rn|YtPjM|}94>Pv)twY_DV&xMO zbdtp?77+%(4&$T zvM?#itBh#>}bU=}@9v9EiYtUf|evx`ke3=72` z4tgyEV~*SdnKL^7bCjZBmgf*575idsH!hoV7m z=DuDE|DRr6-}5lPj}Y`{8ygR~)Leytp-WGnDS!VP8rxJQNXW_UV1$ndK~gv{k7wzk zgY*t$;M$(VX;{tY@U93!@U!ETByzf%gYY@wfjKaa)UJkN5M_Uv;aG8Dwiz&KfdTuW zzquh1g5Xz_pWqYCWl_r>FUdvuxkH?bV%=ALj9ZDFe8X)R@doGQ@uJutB8FuF+Oh>> z(S!owa3*4gm@dY@*zCFUYS$KfIZ#x=3<8twQhTV3QaT5geZ&6%g(O5;dqR(TdV|G~ zxQ@|du@q(jZ;)Q^=?}L;@;EB>07?jh(!*_t#m*Os91Y8t;|FK8(L=r^YcXIkU@>4Z eU@`FjV&FgR9Rqy?`{+0T0000Px;Hc3Q5RCodHTl;TZ#T7ntukFRJ_)({R#B0a)u2T@GPYQP1NNtfwVnHhv1%U`6 z;*X#|_c#6qgpv{~s8NyPwoZbS3MmMiv_%bS)GB^ruj4q*!|@wG?j6o|!;;IIcJtADiHz^0ucfc0ucfc0uch=P6WiaW!b~SlN~~cB#~I_ z=-Br$KX0n6T?wEQ@1Nf<9QSRK)FTDmwumlCi~7on%04`L^p{I213gTd@p1W>>rVc} zajb4BWS1b>EhT+7JqHG7glu}Vv%Td~x-Q?h5kzbAdHW#od5P1%tg5ifWap+aeOHl)gZR3@rIQ&ePAO*Mm6TS?V>D#^B$1V4!NdP#9hRa=|* zGKdImT8ll|`?mqMAzfiice9-hI#pL!P;GT3)v$Dx6bJf)zEj~{^>Sxt%d@_XIhD#P zhJGyNeUBO-DP5YITkt+KPAplK)Do|!@-lVTh;=|oy|892S+!jIEIJiZnY*`0|G7Fw zcka$BPs<`Xs7kB_kav85hg@LAWvLn-nWE(t)!onD9e_Ms`1nv@_;}L+NRz4Xvoi07 zlgVWBll+)v!%B7g14h~ac?VBETLsVJ(Y4OaEd~#631#&H zBW-|iD#yVycovVY^$zcFLB$qQc?Sa@ZGg}Tr*eE3Vws;`CdYAor^YXLwY@$5xo=~h zN+W;}vS6R6;6klfBmAU$^Lf?m9}H56k;+EO2%xXyIe~$u>|q}6e|PiPAwExP*&obW z%ahJrCZAFI5VFXuGkxw%#EIj>R9#i+v48{&kECdbKPF}F-U3S!!;y2qwaC@7KN#B> zpytM=kEdp4BtjM@i$I^!(ik25*$=3(p)QNX-ntsXr)_@|UHaq-t*-h8AhY^p{bIBNfAtEiHB5tE?z91_wO+z(IYw065T?lr3r|#86XH(`{W| z#sDF1j986nfm-ECjvp`3fL6EM&DribWuPrR7}FRaG?ltK1Ki``@oT;pCX1_UalTyNDqqdv_a0S%lE89o5>?n&3MAv1{%DK02&{kdXhH@ zPkgqcW|@oGjpw_(o1yS#Hs8?^|F6jyMgVPYB1Ln*)N&})qy#u~TiEH)W_Ct=8>+?- zUFI#{-@VT4;PY$*5MK!R1|X=INxBApj%v}N&E*MW%^_AJ^#U&=fOx=f00I*eV+|+p z#!UFG3mQ|05p#nb;^W7|188{o#$Gnk9T+@aOzjYyz#x#&2Ab`Z#ibQFF>%W{3Tog< zZ)8aiCXc)oQZw*ibqYM>4=-N!{G6RUYGlp~BowrUj7Y zxW4L@9vJE1LM`kizQ`|EJNlpn5ZmTJfRHOM*dnR^z4tFD<>NEgpal@S?12{-aFGDH z@={^n9Up>jm!c zj!GvbfP}-pmQmrRL4yM>@>ck?wKjSIb`LC;tlho_%)kDDnkfOKq+&zElYBQ(zNoSO zZIMEnAXNYi@to}>C;cZP*2-gLbt*sQQr*P@9Yp_0nANgiEj$)0x!BlP_lKvRXg}24 z(9mWHI>u4V54dfIE=L!?XFG3bLmE+)vvlVZup})1rHzyteYW6|C_H=!yij9n<4mqxSKHXtE-@Ncu zUev$Hl7oB=i{r$_1Ic9LEfb!s@)n=1p7D+k@Q~RF)Z!z=#PQd9_J{Qel^{NUt%Whk z*Uo@UvF|jwZoEZ%EnT*Pq|RLxvN0-_H@xdb?G=&Rox#;p`g| zd1yl=hzBa-w9EhaJCTP+x|$a*uJ8^qXjzaBdmxe6r=HtMbJ>CK6KDDxXkENO(q*q% z{F+}-Z~&zX%&x2_P_mB#n+<{{`L#KMyC9Eu&$~ uqxJ}a2!RNJ2!RNJ2!RNJ2!a1!1ik{HraPx;1xZ9fRCodHTU~5iM-`sA>-}wrp>^u~*f_Qm+#feiY11TD;|D;rRYh7sfv3JC zAR!Pac>x|P-VjK!Kp>=&KA^tv6Di?GEvN`7QP*h$YTTwRp@|)5?Ko+iB3G%sKi)fh z-`Z=h*LUxonf2O>x<^{=-I=*(&U|~$nKS3yD@21D2s99AAkaXdfj|R+1_B>X1mwqM z*>7Dxi9^QqJkDT??RZ9h=;q75N{7;gh&w3g4$O(WzKC`qy86=kD7& z6RqW#(NPtfcGC|lNA*ir?8n^wN{G9cWRRCaQXJmZ6+gYy=6$6F(4k}FzZF7#t(=9F zA|sT1g98@4g1e6FYWG%-5aDyx&T2- z)E&MPN~yr?tdR1gQsUGLN48z`9dFsGlnP%+<@(&b+pk;&?NE{)8j1?V>b=-H*)46mfPE`{?aDczHC+4lFJe@|w-H~<9a%~bY2 zl?NCA1i}%R&v=bpjkZve)4i)BHsZ%i3!p=TsjtAc|KP_+w-1_h8z%U&1HZNB{+84I z-Ll7(1cbgr?1jlR>+-5*92Wlm?(Rfu5Rayy0qo~)mC0o?SU^-~yx$mT#0K;~<0|pY zxp!`GHA&Q{UNcs8uX39 z8?CO$O=1UGZBYYP6b(zUy)`1bwuD8;richPRVRWJGTZFLnmapXI%smEnGO$*C*ea7 zd#oRYLPE5+04(|~m}4Sp?za$7zP7t7u}^0e+9o#73}%L{SBG(}#^m!tT)B}ge8lia zq63<>|DL$mWa6`=o_TQ%M(``)oUGNtZTXG?tlyuR7MCVHLn}|V*o}ugJ3JbV0OIjs zK0@~3w2n=ASBSs;>$bQF2d_g;BwibU<|mhRr$v;DAPxO{Rs$b-wXaQ%YYZ$5G14I3 z0VhpARF_0^o5=tvAHuGrwY?Wv7z4zEr@+~&$e`Z7N3UmnMUsxxHZL+V28gF}9z1=e zSjWzh>p9=qosd&o4dU!PmHSGuj-9EgtjNt($gD^?+uI%SuC~K zUk&u$Ar9Q1C>%=3<=U;BIP><5IDO$GE2fOJA=`=rF0{wU|8R0^fcEWdIdk^XE#o#Nj1*fJoxc#6m8k)F7C{-qDZ^o;-3z3gWE$mCQ3_0H;!)n4F~E|$P?j186VX3(Dh^lX(ZSs9TvK+xfSo~Uh!W>u~^Uc5Ml zV@+wa>}&>$Gu9r?X$=r73`}U*5`B&?nT##+{BYJSB;Sg^ZTt`KwE_so4F}o9N0{}q zO^q^3s7oeeOL>lzMAfK)89Qk5vI6MBXto!pvW;ZG9CE$V<;AF4PVZ`uykjG$6+n5E zX^N9E!EQs`%5}+PY$;FXw`pq3Ai~7Vw!#HQRsi8hzX%Xb%%)t!I7gRE#+LJ>vj#v` z=0#ps03nKA1c*#*oHc{McT<5m^THV0fRVCsyLXhG|Ka_{0KGSXVckb+QVtN%dj-V2-bucA^-HmR3Xk;&7(%C42<;8 zy*)L6wiip=b+3&9!h|aTVo{HEtBd3MiStqcX+qVQQ7JF4YbE5%$SCyRRZNRWHOjF|X>jci5$4Ugs?tn}~_%fYO8 z)-Ad6DI3|008-NRG_T^sw!2yJ{@Q-4gU}?SQaj}_0!S!-fLJT9R{}V#hX*IL>hYy( zFaiiEOW(RYA0%L{yj}^%4P!IY2I#GcnRY}uflrh2L4uGr*R_UHal1Dn?WN?i%a0e8 zX5mv7UwmjoU4jHN>p3(y(NjrwuXb&KkpJ;@(51|GAd&Xf1I=}5Zc?~LTBIFG!@PX` zPbomWrY0TS`-wuWoaJC18d=n1-D-WQ;D`8Hg%)XTd#RL)Pi527h@z_sms#;-QIB;i zmS#-PZdxk}8idk$EF9U2cTBXNFVNDU|K`$rss)E~Gnl0L@x!_m6JgXW=4_bQS`$Jn zl+IIFfy%s=PCice2 z3?BhLSWBTxc~hIHRn#u#bE+v$mhvrLBg2@9hNCSyuX5?_VgUhSapKkamLG0RgkHf@ zs6YDhqn~_y-;TRFp>5A1$UA}0syr~kHwIv4kLk!8XkvU*Z!YH|i&!g?m+?T>t62O{ z2&vKD&d3E^mph~}%>E)%7KKxJ;ow;~TLr#rQAz3rGdoeKzt|pVV#A~9$6eQbsdz(G z-*`R;6aEt~;SD*COvYo8MP@B6tII$OC!k?(883dZ}!NcTZ$B(vc54tB% zgZPeT5R*#%0An2I=OH1Tq*P9_uQU7x7NlSAsl*uV&&_Mu5H9)oAtU7ZAW%Mq4RRmS zGQNL4#ic@C{{httDE2osdd*Nu?*H^YLZwUm5!`~d49mp$jybPq90Ah$WCzMr&J{69g zYj2mc%h|90FMzdy4tc@n3@m8QUy%R&!LN>Pxe_Fy7C>Y|O&T6cAHYOWCnVl`;M1|o xLChQd4FnnpG!SSY&_JMpKm&mW0{_1V{13>*AeyU+)$;%V002ovPDHLkV1gUun7{x4 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_tab_chats.png b/android/app/src/main/res/drawable-xxhdpi/icon_tab_chats.png deleted file mode 100644 index 382bcaaaf6a062ccef0103f8ed7b9defba0a384b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!EX7WqAsj$Z!;#Vf4nJ zXtsecqtcuEJwQRp64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq!<{OI6Pe( zLn`LHy=CafmJsxp;){IwYU4_qYZl356JZJU(o6&l=HXn;wd#jq^ z>g$^aPk872I`whg`scFW<(?c){Tf{Se64vV)I_+^*cd@i@-KOEF)awxUbt^>Q|~9C zw#DKl@8vGO>;3p^*7?Y=EC)vhnfL1xmk0f^*tRq7z_TjG-O;Br?%KKJnXQgo{@KgU zDt>X;tlKF&=6VVCMroFB)?3OJazD;<&%CQ^yjL>jPI?7wWcgxGq~Ye{E1CXI zKjiRhm7|b=r-KUPL>3q9jQg)!=5xI8K6WeY$Ib@3*Am(M>dUHx?S6DuD}8&jC(`!s z(`7~Rhr%bwTR12w)E6|gHvT!pD8}@OpS^(XlQ4S$(bP0l+XkKe>@P& diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_tab_contacts.png b/android/app/src/main/res/drawable-xxhdpi/icon_tab_contacts.png deleted file mode 100644 index 19f17a094278dce6050f899d72d668a15272e085..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1329 zcmV-11%W`Sz!VsjN4;CsDHIw44H zbLP3&nWM)d5Y@IxdY9NRl_v+3IuC2#EXp9YD}T?$>8;F?1zHPl0kjzurE=wfQuk=# z8(Kkk?2E;{@yS>T{S2ER(B)7*Ed4^)D3e>NhW6!q|(mJTR9@A#Jz2tD-h!?%W)tWVZIRZ0%*)+RL%Ao8k5QBV^g4z*Q_0RBHU^V3NKrzptipRSwuuk*a(=xPOJ3pt$octfZSQ5|>Q&Ojd9yS_^x{ht+)u?Q2?=^{ZQV{!hPa5=&REw3MmD(c*bj76BBB^L=28H+GMZ`RX% zOj$fIDua(HnKuI0&V&g{9?3j@_JMTPxo2S0**uS*eIR)x?nDV~q*u2xOg!I3cEFLG zhl%IAtZs>2nik%Ry;?nDd}^1Sg!#q6v$B)OF+R1+t5xyspe3XEmn$j$T}=s{?$G12 zo$dgTWtdw&WZ~`Mg_s)HFXDq7?mL@1H?|-zr)+y5*ydbcb}ouZ}WKpFc7 n9pi1VP)sFTo&mX-(}ioxcTTv}RC z4AP6_)Sl)LXz4CZ4c?G7Ly(d2FkkFfU^q9Ql!D%==AX3 znsMEKv-{@l?7ANqSl6BRe(%fg_vZckO~`Q^bP`Y4qrfm=$m>eMXMku+{1eibwG6`H#UWs5I_z@x2 zW6Lyhsw+?`P&{FWfN9_x;2mWJS4R?<1r{ySP}V4A0>u;dhrqYMbtMJX&N?t-nZ_?F z3aeY7c*1@km;*jhVUR*rf%}$e{8>*SH479^*kRxya1RL8V}y@5z&!B4GL7R}3aCk- zc*1@YSOCUrsk8yC0Cz0Y_}A-=o&}00?011>;F{OU8q9Oxwq+WBd$}p><;U@a{V}jc z^N9n(<~7-ds;OF_c)~Ujt{U@bSdfSTE3z$BQB{aZ)mMOy+HDIIN5Hsc8b4L~VMT#t zpR-1DdrmPjzz3E3q_QCdd zgm9VRYAUUK8_dlVjTERbTn781#JasLH*M}@eXig|c!~jVPBLi=6bL7IA zaPi7v&f&qMG{^q#oL}!m93;@j&5;YdceShTa<+D}ev1Pz97dd~&_Xx_1HDltW%=Cy z*4^QGoKp%-9W=-g(}F7R0Z8fdAi{`4lD?y=|H&L2kvTY0QdSjg zhY_boeMi+3OsDq%wibc9A|Z?(H6Em~{{bnG?;$qO8!bC4_kzYJ80ZSIp?)>tb(nLo z_w;*^?*ggnpfycU-PoOooebYlF+n}dIc)7_`R%X&6j@a@8~HWqf2co2peR=_NBH{F z%bxDZ92}9_$&yOv*xbot@8xuR4!{e`G~UjyC@ukC_)$xx$NRA(=2n|hkkn3A=QyVv zO8~wLRM`LI!zGo@v6;@YwVTy7@$||mfu10?I+X8h#4dL5Ecvq0;o_BjgeIr9o*x09 zHO{6$@q=X=pTp^$)uqPR5=c(8a0~Ppv2lOiNg}iWTms3{46}`}C}7OG6Y~n!gBH=a zM;1WV5gMFuN+5Z%YDT9;0b`~xTk*__qCBIws?DU}uv#ojvDA|5eZsh8|F4DXS zb{T}{R3#3y)50s_d2e1;aD(O=0<0jOR-VLx8U%uqr`sgrWhOx$aXSbbCu@1@0<>Rl zQjzxSaVntfe2_F~47fvMRwk3O?lD#3K>HP46=}cZtpdIaR7kVECh&iY%M+;K@21)S O0000_ diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_chats.png b/android/app/src/main/res/drawable-xxxhdpi/icon_chats.png new file mode 100644 index 0000000000000000000000000000000000000000..4092c54b1c333afe0cc84046da98a96cff906a54 GIT binary patch literal 1546 zcmV+l2KD)gP)Px)#7RU!RCodHoX>9?MHI*1*qcO2Qwj~#jma;!cKH>ROC$v1(5gsCZKR%y5=8!h z9zX)rTPrwJt%Q*1jT4t1`X3afhywyuDu+Ua2&#e_iXeqnO%sTn#9iiD*jev5`(~V( z&Dwq|S>B!Z=DnHEcRag0*$n`1On?b60Vco%m;e)C0!)AjFaajO1egF5U;>>&K)C4W z7gw%5`*^K*K?XnS`~IMd97&BSg!n_Y?Q0Lj2UAnW?^5lwE&#&!ORG11fB`CbTibx2}V#mWrsJ_2<1N;jVU+V(Mgh!~P9b_k2SQntv=KQF^q{G6x08tHM zn@WHMP?^M9!UDvKTTR9Ss7zulVF6;rttMjuR3@>OumG{*R+F&+Dw9}CSb$h@tI1dZ zl}W56EI_Qd)nuMpq?Rl!EM$u%xaj+EL@x7XRgcY*Z?FHjdBA%l0a5^jzgmQw68zI- zGJm~z4^u~3jAP96b60JS9fz2S2uqnKMesIRdZK{(*urt`NwTC3HqQf z)}c06ajCqNJ#hlyoFATcqB?=TSclqN#ijC6_QVM=GQ6K^vtq}SG_|>kOXa2Pi4$OV z=%h<^0PWQ)q$pokaienT*b*mzPNUn&CvgJcb-wAQQ%A=qoVS@e;TY6$;sn5(EYnS= zj*d?_Z!>kmF{tCj34nLFD=Ys}?XKC;7wb@)tGHBN%APm@aCrgmaOFcyRNE^)=&Q3N z;VLfKNWvj;0$_V_dEx5p^~hfWj(qenS&DEKmtY)eCT}qQIiPy!@!3Tk2A#!Y7djFH)`zyjFi zX&j9OFh*v#0t;Z5r*SkEz!;g`3M_zKp2pEw0Apl!E3g1|c^XG!0gRE^t-u1<wNn3gysg#+cydqwj(4h+8em<3ef#tu6>KF?uG(r{fWF=y z7&LfZ(^bb>C9ZV=u;Zg6gTPaf-VksiKq@8R`9ov;OVH4Od_O=VMne}AAvczVjGT_{ z-MbGDmsX&(whra;`@xcYGGoo?&jlYn2O+G$yiEwSo z%mQd&o0ynbe`k8~G=Mm#;cn!@0z~6l4w`4CPn@+a0t*l%9NL%fpxp@-fo&03fH2{} zv3w@;%fMl6*QN+8Kn-jCjvW2vZqNI?zI5}*mIy4sCe!fVXSrPV=Wt>0m=Zz0MN8g9 zumC}#|L@Duf3=Vwe!qc9DT)-qhu@V7p#l~l00gHU`T11BpOoJl0aN5|MFb(v$U1e8 z^7}$GJck5>u>b(e65K8MYW^o(o;QA|F!HVm{3^_usT1er`qxQ$!*;t;Cd3?c!$(#7 zR^QS;dNX}LK#3;A4cVb9!cWb5Uf-{|+*1z~pEfJFe0er=>eR8nWWULkM`r@a6VUhR zRQkh%2Zye;8DFd2ak3hk65>)mKm48?0qa&<+lImHp92J(D-=dfGkm?#VpjkO|GC2G zS-sTkg#_#g!0?+IQFa7i_)WpL^9x}3O~cm`K%PvuUe93o+k&qpfOKlSp26_94PQ%u z@S3>%MfmcGlQVp^V}(C`71Yz!`>{+lhv_8z+XDQPg~I50JLx%!76JLMV^Z_;i}ZiS w(~8DUOn?b60Vco%m;e)C0!)Aj>@b1<06uGkN9VVn(*OVf07*qoM6N<$f>XuZL;wH) literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_chats_active.png b/android/app/src/main/res/drawable-xxxhdpi/icon_chats_active.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e52f2405c494b554e0fd557d880a128e0a95e2 GIT binary patch literal 1532 zcmZXUdpOez7{`B`SxYXPMKQI_*(170i9{HNupG8&XEvd;rk$r<@QegCxhz356UO=Zg}k|pdgbC z5~Lgz9QG2}xM<=OEg43)Ph7b_uGoJ6GOEIvKtKdrPrayA!b!k0_I(x^=BRZ%Pto_Z zZ(yfiY7~hqJnzH5X;d>d6hz=Q=?0DGug6CCL=;D$0WEVP0s+C}V96j73H{g8Vh&sj znE6(`-<0z7G%YbvN@fC&J@jGDNow5!zlMaZe1CySu^lxi+(s0gy*yCE;3ZK+RO(01 zjn^jo!_;9cJd?M#GkTZFp#f_Nt4{A~&h$45;H>jbT6iZMt=uC$Q+Ldi>T~#yNeak@ z*tq3@2;{{q-&=?b&F{WCC|nnzPZfo8813^^C+65Z&{HQqU_WdpftuMQe-cOvu}(?@ z95m7fuLEgQG&q;^XRY1pc13ewX|S4<5Sh8@z8a|d()O(8djk?u^YeapSpXb6!)B+{CqE-;W{61TO{}x z@Wi$99Ax`rsmk+NE-}oEl(R)KKx%lcd=|%E;iDk=v=pQMi4~ zw2W5IAf3<7)d(y{w|V!Dd1o6!W(@iDxr>LYw{{9kP7Q5&UbHD`aQ`RCN35o)gb=$b0K$ajXb}GUY>EQMoo1})`+g55-#Pgp zN9{8^d|7#+(<4aS2Wz(tweEjI zxS}9ERM(>Ldba?Za~SIt;bv$GMSSE9>1%%fK2Hs$)%T&)PTv?4tiG;5GwB{Kl}sQTlz>+U?FQV*Wt-LZfM{y#esxP+KUnJNc;IETj#QC zYgs~UB&V-+_<8;9gZ1-UYQ^EMWhBlE+>c7fb&lO#Q8Xr>RS~_ka>qEuq9eWs&kDhO zu>*uFvX?|H3%{+-v&|Mmo9F?W0=ur#HMd_n%%6uT*?~WU<=a-%GTT)Wf)cS5Q>BC- z*$-Eb)%1E;u4i=H7aHd0-IxFNhYz(Jrn-|BzDoh literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_contacts.png b/android/app/src/main/res/drawable-xxxhdpi/icon_contacts.png new file mode 100644 index 0000000000000000000000000000000000000000..64ccdc77576108891db766f3bd52f6e2412ae10a GIT binary patch literal 2723 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 dCo@=a002ovPDHLkV1oaAF-rgd literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_contacts_active.png b/android/app/src/main/res/drawable-xxxhdpi/icon_contacts_active.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed7402549789e38a6ee40d9e3b9604b7aa0d218 GIT binary patch literal 2645 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_discover_active.png b/android/app/src/main/res/drawable-xxxhdpi/icon_discover_active.png new file mode 100644 index 0000000000000000000000000000000000000000..601c213982ae354d74d89388ee4b3a1983e1c699 GIT binary patch literal 3296 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 ecoLXg3H%STK2TH$Vd=~O00004nJ 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 literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_chats_active.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_chats_active.imageset/Contents.json new file mode 100644 index 0000000000..933c163d2b --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_chats_active.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_chats_active.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/StatusIm/Images.xcassets/icon_chats_active.imageset/icon_chats_active.png b/ios/StatusIm/Images.xcassets/icon_chats_active.imageset/icon_chats_active.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e52f2405c494b554e0fd557d880a128e0a95e2 GIT binary patch literal 1532 zcmZXUdpOez7{`B`SxYXPMKQI_*(170i9{HNupG8&XEvd;rk$r<@QegCxhz356UO=Zg}k|pdgbC z5~Lgz9QG2}xM<=OEg43)Ph7b_uGoJ6GOEIvKtKdrPrayA!b!k0_I(x^=BRZ%Pto_Z zZ(yfiY7~hqJnzH5X;d>d6hz=Q=?0DGug6CCL=;D$0WEVP0s+C}V96j73H{g8Vh&sj znE6(`-<0z7G%YbvN@fC&J@jGDNow5!zlMaZe1CySu^lxi+(s0gy*yCE;3ZK+RO(01 zjn^jo!_;9cJd?M#GkTZFp#f_Nt4{A~&h$45;H>jbT6iZMt=uC$Q+Ldi>T~#yNeak@ z*tq3@2;{{q-&=?b&F{WCC|nnzPZfo8813^^C+65Z&{HQqU_WdpftuMQe-cOvu}(?@ z95m7fuLEgQG&q;^XRY1pc13ewX|S4<5Sh8@z8a|d()O(8djk?u^YeapSpXb6!)B+{CqE-;W{61TO{}x z@Wi$99Ax`rsmk+NE-}oEl(R)KKx%lcd=|%E;iDk=v=pQMi4~ zw2W5IAf3<7)d(y{w|V!Dd1o6!W(@iDxr>LYw{{9kP7Q5&UbHD`aQ`RCN35o)gb=$b0K$ajXb}GUY>EQMoo1})`+g55-#Pgp zN9{8^d|7#+(<4aS2Wz(tweEjI zxS}9ERM(>Ldba?Za~SIt;bv$GMSSE9>1%%fK2Hs$)%T&)PTv?4tiG;5GwB{Kl}sQTlz>+U?FQV*Wt-LZfM{y#esxP+KUnJNc;IETj#QC zYgs~UB&V-+_<8;9gZ1-UYQ^EMWhBlE+>c7fb&lO#Q8Xr>RS~_ka>qEuq9eWs&kDhO zu>*uFvX?|H3%{+-v&|Mmo9F?W0=ur#HMd_n%%6uT*?~WU<=a-%GTT)Wf)cS5Q>BC- z*$-Eb)%1E;u4i=H7aHd0-IxFNhYz(Jrn-|BzDoh literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_tab_contacts.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_contacts.imageset/Contents.json similarity index 85% rename from ios/StatusIm/Images.xcassets/icon_tab_contacts.imageset/Contents.json rename to ios/StatusIm/Images.xcassets/icon_contacts.imageset/Contents.json index 1bd385d0a8..b1445eaf8e 100644 --- a/ios/StatusIm/Images.xcassets/icon_tab_contacts.imageset/Contents.json +++ b/ios/StatusIm/Images.xcassets/icon_contacts.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon_tab_contacts.png", + "filename" : "icon_contacts.png", "scale" : "1x" }, { @@ -18,4 +18,4 @@ "version" : 1, "author" : "xcode" } -} \ No newline at end of file +} diff --git a/ios/StatusIm/Images.xcassets/icon_contacts.imageset/icon_contacts.png b/ios/StatusIm/Images.xcassets/icon_contacts.imageset/icon_contacts.png new file mode 100644 index 0000000000000000000000000000000000000000..64ccdc77576108891db766f3bd52f6e2412ae10a GIT binary patch literal 2723 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 dCo@=a002ovPDHLkV1oaAF-rgd literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_contacts_active.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_contacts_active.imageset/Contents.json new file mode 100644 index 0000000000..d88743a2e2 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_contacts_active.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_contacts_active.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/StatusIm/Images.xcassets/icon_contacts_active.imageset/icon_contacts_active.png b/ios/StatusIm/Images.xcassets/icon_contacts_active.imageset/icon_contacts_active.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed7402549789e38a6ee40d9e3b9604b7aa0d218 GIT binary patch literal 2645 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 literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_discover_active.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_discover_active.imageset/Contents.json new file mode 100644 index 0000000000..43e44f838b --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_discover_active.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_discover_active.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/StatusIm/Images.xcassets/icon_discover_active.imageset/icon_discover_active.png b/ios/StatusIm/Images.xcassets/icon_discover_active.imageset/icon_discover_active.png new file mode 100644 index 0000000000000000000000000000000000000000..601c213982ae354d74d89388ee4b3a1983e1c699 GIT binary patch literal 3296 zcmV<63?K7}P)Px>nn^@KRCodHUF&aD*AYKw--~%U7{bHG#)R^Uu_0}PO-0j?R+UK9M*Y%CO{79v zwP_T{r+h5`0S~2VB|;+gA@KnzK;T2vw6vsI9&LhgVn{;$>Y7Ku1PmDO!+THXx8|nn z_1)cj9$v4lJJRazo_o&B+?jjk%$b>cmoX1K33w9lB;ZNFlYl1yPXe9|O{0Z#&DlK?LprD;Uyvn!%zIFZ~Sn5ZWKCW3z7himJ@7gR1$S^+``{=&Zgm+A0J zF4z*m*-b)nnlo`c7@BqbcQ4MprNT(1j=}YI#8Ye8h_z7&*2Xy7L~UQo=a+MK%;%3j zzpkE3UB9#fw(pJa5Ek2$&j5aN#zzEWCz+2Q=6-(kz)Oq!ocdLA+ow0gtn}UF#tai1 ziO)6?dMjgMjvJn#gqFq`&$#Jp_mNh>wmtn9nGmaN1jUY=^LD}cVZSAg?0==Uy;$GL zI@cLbJd#d}2Y0t7;$>;~h<0OP$fNTp}M3wz=}wFGlL z#blUaoRd?pB;H-W=DPvKPH9Q<*;h@reBqJwReQB|ex$2nHNl5|N zWYK19Uk;wKeofPM?>|?Q*$AJJ2RFo3bWZ!Wfxxi8UlWwv;vfGo$Y)2&ygK& z(dODPf|@x2Qbvd^CsT#*xf~HHb0=R z#RYAkdJ&Q}d?6E#4jvRdDa?%Ji$W|C(qA`x0sd5TeU!XIInbh8OaFtQCET;`sW}UB3D-h z$O?SCYCgZKGFD3gh-%W}Bb9(qVX_=!uHPPE$IjfPyo&-g!IkVkC}}BRG^EUrE3jOV zL!g8+7l)*IQ`vyoM6?tDBsBe|ycx2Efn!H+k|k1d)4(6#r*d(~eAiY0;`ww3BxQ(J za$l?oT~|}CStK{|dehQKm+Jv}9kmsZO{NI`ULM{l{j>X8T84jR`wt@83IGx$Q*fLv z5Fbb}#GBjz^UO61?%sb4Gc-8rwnbyS*1=!|C ztJvE52zzMOXkz%wyP0gN^5iE&?8=ws>b-idrP$`Cs)CIBLea`n0IC;gA2T5e@Y7uV z@wex)C)QO_Vr6U;eepbBHsP{m{Y>`vjv;pNAGfulo3_M}Pe5|VIkU$9+g!{0?Y^o< zV(S{FP&rcLpOF$G+@ zD&~_1v>f?XB)v@myd7208JkPfAvkxIT<#K^gj@`TzZ+A)y+mr0O$L<*roeVJRq*MI z&83G888&7%P}ED?{j_lzQve?=3D4q1`Nu@o;MmNU>xhs<4}~Udpu69Q2Lyb^6hP*u z&1MiaI4FcN0oY`zg3j1{nmswexkw~jSu=o26oV8Oe=L`2Q{E5?a#cZRY(7ndrxB*6 zyZ>{U`u}`9`M-_KfR5huhWv*kP!ebY5MHqU|A>oglo*4trT__=_{|jMz|Glz@Mc5- z7PDIOFBEl|&Rh8Wp2dG7wuA73EMSbuxDevP&T;x?Exw!yjRp5!R(+9`s$P#7UCHX ziM;mq!0bZjRob=p>YZJ~OUW|UIuVBnf+=#^$~*Nh)&_z8`NVB@f&^TyaI_OYmSz2b z+KtTuZ3U!#^hoIVP{~)kV=+dFxG8{LKX`JG(BU%)z&R9PEaa|lf<~V>FDMC9?r1>* zWj;YJ_sVU1F0V92R$BpNb{!XBn?Y>ID&-+MnU{e1k#|C0!kp!8s#Wt%-y-V;f)m?e&G4XtKk#6hJ|$qUOhD z5aH=ce6ZT)Px?r2{Ya#fQtt&SL_>>pkfV0Q&>OTKHIB9ztC7dlEGpu{T@AO1&|4n_Wuhpt=o=7 z&#KyR_Jg7+)a_sqhq*!my_{f)tUD^L0BI9M9?<7x{}BhOFyLKOksiZ?(|+!Y?S1D) zRW^Z6Ib5U>Cz@G`j*f)FGZ)DIe}dEuKneQ2`@@qje5%iGw-p}`hu-+|! z)A(s(@^bc_40LC6;fpmd3!Wp-L#aL=nJgqzM&tQn3!<8)7$%+$k~j1d8GKSRfV5mM zgIujI36_g?68b3$cf|Z57He8EBd&&P{3v?6%Qb4R{wwb#>faAyE--AN+5@A?k7nQB4Ha5Zgg` zLFHy6vpBB^Imc5{Cg|hd^Hk+Vr|{Q2(w z7VL28&5&5cTU@cj`KNF0tX=J@?}JWK3c#55?)&f1RDIeV5q^h+eTIZi0_U-+IpNbQ z=26=egYB|O{0Z#&+1Uw0N67VG8Nx+kUCjn0ao&-Dz ecoLXg3H%STK2TH$Vd=~O00004nJ zXtsecqtcuEJwQRp64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq!<{OI6Pe( zLn`LHy=CafmJsxp;){IwYU4_qYZl356JZJU(o6&l=HXn;wd#jq^ z>g$^aPk872I`whg`scFW<(?c){Tf{Se64vV)I_+^*cd@i@-KOEF)awxUbt^>Q|~9C zw#DKl@8vGO>;3p^*7?Y=EC)vhnfL1xmk0f^*tRq7z_TjG-O;Br?%KKJnXQgo{@KgU zDt>X;tlKF&=6VVCMroFB)?3OJazD;<&%CQ^yjL>jPI?7wWcgxGq~Ye{E1CXI zKjiRhm7|b=r-KUPL>3q9jQg)!=5xI8K6WeY$Ib@3*Am(M>dUHx?S6DuD}8&jC(`!s z(`7~Rhr%bwTR12w)E6|gHvT!pD8}@OpS^(XlQ4S$(bP0l+XkKe>@P& diff --git a/ios/StatusIm/Images.xcassets/icon_tab_contacts.imageset/icon_tab_contacts.png b/ios/StatusIm/Images.xcassets/icon_tab_contacts.imageset/icon_tab_contacts.png deleted file mode 100644 index 19f17a094278dce6050f899d72d668a15272e085..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1329 zcmV-11%W`Sz!VsjN4;CsDHIw44H zbLP3&nWM)d5Y@IxdY9NRl_v+3IuC2#EXp9YD}T?$>8;F?1zHPl0kjzurE=wfQuk=# z8(Kkk?2E;{@yS>T{S2ER(B)7*Ed4^)D3e>NhW6!q|(mJTR9@A#Jz2tD-h!?%W)tWVZIRZ0%*)+RL%Ao8k5QBV^g4z*Q_0RBHU^V3NKrzptipRSwuuk*a(=xPOJ3pt$octfZSQ5|>Q&Ojd9yS_^x{ht+)u?Q2?=^{ZQV{!hPa5=&REw3MmD(c*bj76BBB^L=28H+GMZ`RX% zOj$fIDua(HnKuI0&V&g{9?3j@_JMTPxo2S0**uS*eIR)x?nDV~q*u2xOg!I3cEFLG zhl%IAtZs>2nik%Ry;?nDd}^1Sg!#q6v$B)OF+R1+t5xyspe3XEmn$j$T}=s{?$G12 zo$dgTWtdw&WZ~`Mg_s)HFXDq7?mL@1H?|-zr)+y5*ydbcb}ouZ}WKpFc7 n9pi1VP)sFTo&mX-(}ioxcTTv}RC z4AP6_)Sl)LXz4CZ4c?G7Ly(d2FkkFfU^q9Ql!D%==AX3 znsMEKv-{@l?7ANqSl6BRe(%fg_vZckO~`Q^bP`Y4qrfm=$m>eMXMku+{1eibwG6`H#UWs5I_z@x2 zW6Lyhsw+?`P&{FWfN9_x;2mWJS4R?<1r{ySP}V4A0>u;dhrqYMbtMJX&N?t-nZ_?F z3aeY7c*1@km;*jhVUR*rf%}$e{8>*SH479^*kRxya1RL8V}y@5z&!B4GL7R}3aCk- zc*1@YSOCUrsk8yC0Cz0Y_}A-=o&}00?011>;F{OU8q9Oxwq+WBd$}p><;U@a{V}jc z^N9n(<~7-ds;OF_c)~Ujt{U@bSdfSTE3z$BQB{aZ)mMOy+HDIIN5Hsc8b4L~VMT#t zpR-1DdrmPjzz3E3q_QCdd zgm9VRYAUUK8_dlVjTERbTn781#JasLH*M}@eXig|c!~jVPBLi=6bL7IA zaPi7v&f&qMG{^q#oL}!m93;@j&5;YdceShTa<+D}ev1Pz97dd~&_Xx_1HDltW%=Cy z*4^QGoKp%-9W=-g(}F7R0Z8fdAi{`4lD?y=|H&L2kvTY0QdSjg zhY_boeMi+3OsDq%wibc9A|Z?(H6Em~{{bnG?;$qO8!bC4_kzYJ80ZSIp?)>tb(nLo z_w;*^?*ggnpfycU-PoOooebYlF+n}dIc)7_`R%X&6j@a@8~HWqf2co2peR=_NBH{F z%bxDZ92}9_$&yOv*xbot@8xuR4!{e`G~UjyC@ukC_)$xx$NRA(=2n|hkkn3A=QyVv zO8~wLRM`LI!zGo@v6;@YwVTy7@$||mfu10?I+X8h#4dL5Ecvq0;o_BjgeIr9o*x09 zHO{6$@q=X=pTp^$)uqPR5=c(8a0~Ppv2lOiNg}iWTms3{46}`}C}7OG6Y~n!gBH=a zM;1WV5gMFuN+5Z%YDT9;0b`~xTk*__qCBIws?DU}uv#ojvDA|5eZsh8|F4DXS zb{T}{R3#3y)50s_d2e1;aD(O=0<0jOR-VLx8U%uqr`sgrWhOx$aXSbbCu@1@0<>Rl zQjzxSaVntfe2_F~47fvMRwk3O?lD#3K>HP46=}cZtpdIaR7kVECh&iY%M+;K@21)S O0000_ diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index 31ff824cd0..ad5bf38185 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -89,9 +89,10 @@ [view st/chat-separator-item]])))) (defview chats-list [] - [chats [:filtered-chats] - edit? [:get-in [:chat-list-ui-props :edit?]] - search? [:get-in [:toolbar-search :show]]] + [chats [:filtered-chats] + edit? [:get-in [:chat-list-ui-props :edit?]] + search? [:get-in [:toolbar-search :show]] + tabs-hidden? [:tabs-hidden?]] [view st/chats-container (cond edit? [toolbar-edit] @@ -104,7 +105,7 @@ :renderFooter #(when (seq chats) (list-item [chat-shadow-item])) :renderSeparator (when (get-in platform-specific [:chats :render-separator?]) (render-separator-fn chats)) - :style st/list-container}] + :style (st/list-container tabs-hidden?)}] (when (and (not edit?) (not search?) (get-in platform-specific [:chats :action-button?])) diff --git a/src/status_im/chats_list/styles.cljs b/src/status_im/chats_list/styles.cljs index b0c3eb0598..f449465d4a 100644 --- a/src/status_im/chats_list/styles.cljs +++ b/src/status_im/chats_list/styles.cljs @@ -1,4 +1,5 @@ (ns status-im.chats-list.styles + (:require-macros [status-im.utils.styles :refer [defnstyle]]) (:require [status-im.components.styles :refer [color-white color-light-gray color-blue @@ -8,7 +9,7 @@ text4-color separator-color new-messages-count-color]] - [status-im.components.tabs.styles :refer [tabs-height]] + [status-im.components.tabs.styles :as tabs-st] [status-im.components.toolbar.styles :refer [toolbar-background1 toolbar-background2]] [status-im.utils.platform :as p])) @@ -99,10 +100,10 @@ :height 16}) (def last-message-container - {:flex-shrink 1}) + {:flex-shrink 1}) (def last-message-text - (merge {:color text4-color} + (merge {:color text4-color} (get-in p/platform-specific [:component-styles :chat-list :last-message]))) (def status-container @@ -136,9 +137,12 @@ (def chats-container {:flex 1}) -(def list-container - (merge (get-in p/platform-specific [:component-styles :main-tab-list]) - (get-in p/platform-specific [:component-styles :chat-list :list-container]))) +(defnstyle list-container [tabs-hidden?] + {:android {:background-color color-light-gray + :margin-bottom 20} + + :ios {:background-color color-white + :margin-bottom (if tabs-hidden? 20 (+ 16 tabs-st/tabs-height))}}) (def toolbar-actions {:flex-direction :row diff --git a/src/status_im/components/main_tabs.cljs b/src/status_im/components/main_tabs.cljs index bb5564e0d4..7a3734dbb9 100644 --- a/src/status_im/components/main_tabs.cljs +++ b/src/status_im/components/main_tabs.cljs @@ -4,16 +4,9 @@ [cljs.core.async.macros :as am]) (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] [reagent.core :as r] - [status-im.components.react :refer [view - animated-view - text - image - touchable-highlight - get-dimensions - swiper]] + [status-im.components.react :refer [view swiper]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.drawer.view :refer [drawer-view]] - [status-im.components.animation :as anim] [status-im.components.tabs.bottom-shadow :refer [bottom-shadow-view]] [status-im.chats-list.screen :refer [chats-list]] [status-im.discover.screen :refer [discover]] @@ -25,37 +18,24 @@ [cljs.core.async :as a])) (def tab-list - [{:view-id :chat-list - :title (label :t/chats) - :screen chats-list - :icon :icon_tab_chats - :index 0} - {:view-id :discover - :title (label :t/discover) - :screen discover - :icon :icon_tab_discover - :index 1} - {:view-id :contact-list - :title (label :t/contacts) - :screen contact-list - :icon :icon_tab_contacts - :index 2}]) - -(defn animation-logic [{:keys [offsets val tab-id to-tab-id]}] - (fn [_] - (when-let [offsets @offsets] - (let [from-value (:from offsets) - to-value (:to offsets) - to-tab-id @to-tab-id] - (anim/set-value val from-value) - (when to-value - (anim/start - (anim/timing val {:toValue to-value - :duration 300}) - (when (= tab-id to-tab-id) - (fn [arg] - (when (.-finished arg) - (dispatch [:on-navigated-to-tab])))))))))) + [{:view-id :chat-list + :title (label :t/chats) + :screen chats-list + :icon-inactive :icon_chats + :icon-active :icon_chats_active + :index 0} + {:view-id :discover + :title (label :t/discover) + :screen discover + :icon-inactive :icon_discover + :icon-active :icon_discover_active + :index 1} + {:view-id :contact-list + :title (label :t/contacts) + :screen contact-list + :icon-inactive :icon_contacts + :icon-active :icon_contacts_active + :index 2}]) (def tab->index {:chat-list 0 :discover 1 @@ -96,12 +76,14 @@ (recur (a/ Date: Fri, 17 Mar 2017 17:37:54 +0300 Subject: [PATCH 09/48] first iteration, implemented profile screens and my profile screen android styles, moved styles to platform files implemented edit profile, refactored components refactored common components, moved platform specific styles small fix fixes for code review use defstyle macro --- .../drawable-hdpi/icon_arrow_right_blue.png | Bin 0 -> 463 bytes .../res/drawable-hdpi/icon_chats_blue.png | Bin 0 -> 792 bytes .../main/res/drawable-hdpi/icon_ok_blue.png | Bin 647 -> 788 bytes .../main/res/drawable-hdpi/icon_q_r_blue.png | Bin 0 -> 704 bytes .../drawable-mdpi/icon_arrow_right_blue.png | Bin 0 -> 356 bytes .../res/drawable-mdpi/icon_chats_blue.png | Bin 0 -> 474 bytes .../main/res/drawable-mdpi/icon_ok_blue.png | Bin 501 -> 490 bytes .../main/res/drawable-mdpi/icon_q_r_blue.png | Bin 0 -> 388 bytes .../drawable-xhdpi/icon_arrow_right_blue.png | Bin 0 -> 554 bytes .../res/drawable-xhdpi/icon_chats_blue.png | Bin 0 -> 810 bytes .../main/res/drawable-xhdpi/icon_ok_blue.png | Bin 930 -> 1091 bytes .../main/res/drawable-xhdpi/icon_q_r_blue.png | Bin 0 -> 691 bytes .../drawable-xxhdpi/icon_arrow_right_blue.png | Bin 0 -> 721 bytes .../res/drawable-xxhdpi/icon_chats_blue.png | Bin 0 -> 1217 bytes .../main/res/drawable-xxhdpi/icon_ok_blue.png | Bin 1464 -> 1546 bytes .../res/drawable-xxhdpi/icon_q_r_blue.png | Bin 0 -> 1007 bytes .../icon_arrow_right_blue.png | Bin 0 -> 916 bytes .../res/drawable-xxxhdpi/icon_chats_blue.png | Bin 0 -> 1634 bytes .../res/drawable-xxxhdpi/icon_ok_blue.png | Bin 2050 -> 2130 bytes .../res/drawable-xxxhdpi/icon_q_r_blue.png | Bin 0 -> 1356 bytes .../Contents.json | 21 + .../icon_arrow_right_blue.png | Bin 0 -> 554 bytes .../icon_chats_blue.imageset/Contents.json | 21 + .../icon_chats_blue.png | Bin 0 -> 810 bytes .../icon_ok_blue.imageset/icon_ok_blue.png | Bin 1464 -> 1091 bytes .../icon_q_r_blue.imageset/Contents.json | 21 + .../icon_q_r_blue.imageset/icon_q_r_blue.png | Bin 0 -> 691 bytes src/status_im/android/core.cljs | 7 +- src/status_im/android/platform.cljs | 34 +- src/status_im/chats_list/screen.cljs | 15 +- src/status_im/components/action_button.cljs | 7 - .../action_button/action_button.cljs | 19 + .../components/action_button/styles.cljs | 30 ++ .../components/chat_icon/screen.cljs | 23 +- .../components/chat_icon/styles.cljs | 26 +- src/status_im/components/common/common.cljs | 17 + src/status_im/components/common/styles.cljs | 28 ++ src/status_im/components/list_selection.cljs | 4 + .../components/native_action_button.cljs | 7 + src/status_im/components/styles.cljs | 1 + src/status_im/components/text_field/view.cljs | 8 +- .../components/toolbar_new/view.cljs | 6 +- src/status_im/contacts/screen.cljs | 39 +- src/status_im/contacts/styles.cljs | 31 +- .../contacts/views/contact_list.cljs | 4 +- src/status_im/ios/core.cljs | 7 +- src/status_im/ios/platform.cljs | 45 +- src/status_im/new_group/styles.cljs | 2 +- .../new_group/views/chat_group_settings.cljs | 2 +- .../new_group/views/contact_toggle_list.cljs | 4 +- src/status_im/new_group/views/group.cljs | 7 +- .../new_group/views/reorder_groups.cljs | 13 +- src/status_im/profile/edit/screen.cljs | 90 ++++ src/status_im/profile/handlers.cljs | 22 +- src/status_im/profile/screen.cljs | 394 ++++++++---------- src/status_im/profile/styles.cljs | 292 +++++++------ src/status_im/translations/en.cljs | 5 + src/status_im/utils/datetime.cljs | 5 +- 58 files changed, 782 insertions(+), 475 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_arrow_right_blue.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_chats_blue.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_q_r_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_arrow_right_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_chats_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_q_r_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_arrow_right_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_chats_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_q_r_blue.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_arrow_right_blue.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_chats_blue.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_q_r_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_arrow_right_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_chats_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_q_r_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_right_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_right_blue.imageset/icon_arrow_right_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_chats_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_chats_blue.imageset/icon_chats_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_q_r_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_q_r_blue.imageset/icon_q_r_blue.png delete mode 100644 src/status_im/components/action_button.cljs create mode 100644 src/status_im/components/action_button/action_button.cljs create mode 100644 src/status_im/components/action_button/styles.cljs create mode 100644 src/status_im/components/common/common.cljs create mode 100644 src/status_im/components/common/styles.cljs create mode 100644 src/status_im/components/native_action_button.cljs create mode 100644 src/status_im/profile/edit/screen.cljs diff --git a/android/app/src/main/res/drawable-hdpi/icon_arrow_right_blue.png b/android/app/src/main/res/drawable-hdpi/icon_arrow_right_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..a5629972e14dbc4315bf653ea17e2740aa681f03 GIT binary patch literal 463 zcmV;=0WkiFP)Px$iAh93R9Fe^mAy*DKoG}gHsLI<6))D-SLhoE7B+TP3M!H-&P%{nu+UnK)p^lI z3kmoD`V_u_#eI~Dg=b?j?gkPA0NuJ!%7E4uT8D^u zKP!~7J0w7YfQ-k<_>Q-3GXdijU;6IiL1I^Zl>&*wW`&Xh+V#e52x%J_G^#3${e&h! zv_%AS>3(G1jnnF-cELmr=zKKfZLkV*NG}_J?SX4Omjy^&Y7X;OmPE#ffDxJId(~bp zZS`Q-SOxf62O_zaF>3O59j7frBt+==-T9ZQ)1+Efl_cxm@4q&~>BkcRtiPx%(n&-?R9Fe^SG|ik0Rz0VxxtiRu)#`fx>ZUW0OKb#Q0H&hTvIP z8NpLHPok$5N+M!m5s_;|u@DshgtHL5$}^V`@Ti{sz01BhS(OZcG{Pyy5 z1(clra)@z!j>tk@j(+t7?CoeYcF+ryVGn%f!M6>JvwT0mh+K#`^18He(Vkbz0m(>; zON;x+X^W7ld~+-q8q1#x&q=!dPe3k`Vow_rr9 zOakg#qp>L&mmavCLn>R;0SFjceFGfpw)MV60ZMTWDtrg)0Mudq2g0fYVf@qeBaSb$*RXUd8fRK;jhbP3|M<3pNf1~E}olBt3oCi&TrCbIgCVwEQ5|e zDGwoUyrFS%)cg}Kbkg1})dD0cqXt&xAK&>7nlj4l&|mPw|LN2*{14gj#H=AU?>llE?@R#UecSPVFG z$mMNWT1|Y+rq&X*Dx?+J=i=252pQDm!=VA5BVMlQHFZ?T05)qSp|^7Ker3BQuK?p{ zYFM}aJzJ`l>82Q=0k@6SYoAVL=e3~FQ(n!b;~6cd)?!D69-iI&ld6=Yqib!QZeY&X zl~dXI-T)HGbE)`CBM{g_H?$eLq?L35iS>R#x!$S$01!Usr!iFJ#Tk0njma45_R-eU z_d@gcC>?jr?btHu;D_G50JR|_c7!JRE9tLWDOZ#-m|yBuDFIH#T#*XNWL}k$cBWP)Px%&PhZ;R9Fe^mCsKTQ4q&x_N^QQe}IY>NKEvo@mJKS(P*LeO zdprd^1v~{dR{`AU^r6&Z8y1U~TWD)~u)lSoG`~`6XykWfICqE&g%2i~4+>a(p+b#9mIC89RX|`Q*7c^E zD$aRVg}52<4w37ebFuv%PG-)KsZTgz5UFRaFfv}5LZRX8e)?lfaU&Af{;C%3d}b$h z8+!*bX94L6dvCYq5%Y*@w-(>`*3G|~txN^djUX>Nz)g7&bQ-ftQ6WksF>{XpD7_2= zIM2Juzg`%brVOZAQ6F-WoSfv-bsLu=EzcDB?R@$Y+4Ck*TKY&kBF=3Q!hipk@14_c zt?y+(Lor`o6>5MpLk z6&OOrKYF|KQ!NnAwW|VIP`rzH$Bi$S=ih3!Wfc{`UsWL+B9zGV@KJCV3Fe`x>6&)4{fj;4jh+IY0-gdjDDW59^Zf9w S-!%~c0000Px%K}keGR7efAluK{ZKoG}wwjgn$=2V+AMSO)GIU*sH3lUPPs#WEfG)Q1qh^x6F zgp!I!i)~7HKY}3Q#E~O>2H;#fTu81!Jj@tx+&rK(#B=a$W_SO;%Pdr(QTf_O~=a}lNO?bvPu52=lR^9*u=&=VM2Y8?pqWZ{Uh^d}IngJu(FK6b)~ zF^Uou`<;EEU;}dy6=Kz1>yd+r@RZdAIT+6@%( zq7tLGE+CM#9}w>yfN|iGAKe}3GJr3X@iCrD45U{#=PLUJ@!k;_cbgqV_o-ydiTJ<= zw(4cQIthqnMlLlA@uAb-c)puMO>}3&GS(&qjfHWLn?jp6s2Si*vIyW-%`z_VI5+b= hJV+(YF7JPmegOhJ??J0h8Y}<+002ovPDHLkV1n#;5{Uo+ diff --git a/android/app/src/main/res/drawable-hdpi/icon_q_r_blue.png b/android/app/src/main/res/drawable-hdpi/icon_q_r_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..ae26f3c5eead3947716780a6099da9a354979e2f GIT binary patch literal 704 zcmV;x0zdtUP)Px%dPzh3?zOOpn)PbPk^HIb_!@nB0&KK z??6KWj}VfUgg2lF$?Y(+ci(C6#xYoXLN0D4YkqeAJUcVH=UlhC45Vd%E>eHCb+VGP zTg}*CZOVAcemUm7-O=D%b5H3M-KhbsO^(Ona5&9b%p;=l&T#ND=B4PW9TQOaci!*E zPG;k@f=s38!p9{bfO<^8CE73Y`wSY8ox3N$yMZRUBQP9YiY{!MfV5_OxvRl!kCtCS z81U)%heJSdjiuDHePGaFQWQw{NdPP}lH)#Pkm-4|2@+Fa?3wtJ@9=UyK z->|fk^atUoP$o9`DY~#>j_mDv|EnXKKwuWsNsXbXaw)p-Vke&sT~d-I}SYh%-8Dy&b4-23qS zz`dsYYH`68xykNuFarPgIX`CRjj~C_tIuVx3W(Xim%Uz)XLhG&0o#PWLephhkpJ=) z3P$A3v^GAzT^aOTI0J)c)5s*m6`BmS@q~yS%!`|VQl1c6GvS!Z%*dQNs0BpyU9x{8 z@Q8Az?5MUcgbAoAFb`c8a8)x+U8%R5Op&*Px$9!W$&R7eeDU>F6XAwc&K$e8{{I%U!m8DcGFB32Ob4#r%%`Y zXZY{U$iVo9nT5q^R<6Wlm^?B~vIV3V4zdVm5Fxt)nf>V5lLbINL6^hyke&}17!83T z`wCyMzzhe`B>RAclgSvQaaOv-HxNAvMni!1ApijB{9$~~{4m`B0000Px$lu1NER7ef&RJ~5aKn%98heO?RJ5dBeNSxH1@3Z}VwwoNl|N89-pj|-tsOO{6=nQnStpOHnpU)yq6uQS-$TewF=g7TP1 z${f4`DR~^v&ci0owgf6=nb00O+)yy zLR1%~lc^_fB>*S2Rutwv5)rqlbh%Hp%i&rAx(8a9OefSazYx%E1cFl>+?07wR)jk$ z5)glKp2m%|4;CL3;0C?7u_32d_$8b1WdSB)5mdNBV|Yb`H$d3U3jF=^2mLIH9{LG} Q6951J07*qoM6N<$f@kg3DF6Tf literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_ok_blue.png b/android/app/src/main/res/drawable-mdpi/icon_ok_blue.png index 8b6c5482cf652f6bbc2bb0534c9e8b6213d38972..dfc5073656d02c8fd3e4e879565c32f77a197970 100644 GIT binary patch literal 490 zcmVPx$q)9|UR7ef&l1okkK@f(kx;3m_xNvwJz=g+ff%xPA8U}>!UN%~3*Nx!fQr#6qqLXf1`dYnmTQ9o9TA%-Vb#uupSrt)e|v6#N^Mhni%-eV zkEKUS3EiqyJUHDg;p8Jj!CBvDMXFq1#!mZ|UPwqFoG8F~8n{EP4JqY{U08Tw;jqy+ zfQ1>;O^{VLG-S35!Um#j2(Nnbjnn`kESAC`8;TXm6hA&vLf>vAAp1 gV}Aymg8s#UAMOaC@w{Q9MgRZ+07*qoM6N<$f;=|csQ>@~ literal 501 zcmVPx$uSrBfR45gtlS?lHQ546|xieE0Qtwtjf_Np^8){`GHg<%d3!6S9UYl;PKv=LC z6+&3}3`oC$h(|oaQl?d}HcE+^;|^)lHf^HJ=H7em`Tz1i=iCAK$2X=tmU#R@mw~{) za(o+4rIC;L9s#v5WRrgajqf~{y~kenh@hE!xiK-5oHxk57AXfU#+^VDB3?s*Bro<= z-m-j3o7jw2kRChufxwj{h^+=BuO4}oXr&G>`yA59g_i(Q+mf?NO&Ixh6HHw}RIACj>y2qqghutDVN> zq(5ZS-Y7sswS2^PGIOmR^<3C#2|hF&B&Zy&!5-400000NkvXXu0mjfqu|`R diff --git a/android/app/src/main/res/drawable-mdpi/icon_q_r_blue.png b/android/app/src/main/res/drawable-mdpi/icon_q_r_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..0492d497be6528fd8df45eb0fc36506601a7e501 GIT binary patch literal 388 zcmV-~0ek+5P)Px$K1oDDR7ef<E6zKnz7QQBP1-NOVQ-!Ci>hqV^=M*rFV!_b96%v4Rtz40$cT zvLj2K02`!wF}A+H?TkH6RbAvv2a@$aJiXoZ{b!qVb!+jIs+YQ+HP4UNJMdB-+?qoY zCC5iWd{cSwX9_~=%iGmWol?q2ET?As+RHbE2iM&I08#R>eQ=tigclYtIeu-11#-@( z;ahuL&HAiud8b5x&9>XyUOVFOlG@c`IfVz;-GHaaleCGk^-P7A^2Gn&+RdPJLz_+a zJ}k+62>xi-iz`|XVc>2CrJGE0f~Bo(G4LO4GGDG6kOYY^a902T8E@$QraL;mPqoE@ z5r*Hj$OinC9o~Sg)Ge@wpPj204K%_Cas^l@HkrSt+M?uk0X0Zz63LbZLtKkWHPx$e5md{H9K@`VlBvZ&k9xBM})}bz)N;=xPYjg;@fje!lZV8KXiDkOSlZIY17O z1LOcX@NXU9rj@6&_2EXKxh>|2*hBf;ZuCXxoB^GKxsCP8n?>7(J@H_Coyyh5+}e4~ z83#aN3ywGdmx3{401VC@08#6PFb*&|KC#I-zcK}3{16M_nIa6{Rqsn^|B?*C zIltvBm@K5nYI0sB_60x)G6mrqfGG%10GSgAKfYB*RF>Ll+h)NKbgVPnP6;O`YOmW# z86cIbtl`aa48TIN04*_RH{oC?akw?w=yg2hTgYZ?--vjj7}!j^W3BcoUbIsN;K1rC z6L@I*tkOq$3#}hK%!B=rMYrNA6Ul8khX}4>RL+SQ&q1lM6I;d_zQ61CT^XR;K)vQS zj-FyxyH&p)tEQ+UZ s0%&4#fE*wP$N_SI93ThCfxqd%CptXPKp1R6egFUf07*qoM6N<$f^eSrQ~&?~ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_chats_blue.png b/android/app/src/main/res/drawable-xhdpi/icon_chats_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..31c25b335cbb5fe39cf46077606cce495e37e68e GIT binary patch literal 810 zcmV+_1J(SAP)Px%e5SiNo&K@i@(#Gyf=Ln86L0CY4FEeHWGK!qq0$4CSbQh_MI;ROPb zh=gNPpj04QB#KD1c>o&Pb0Q>!1PCEHA-BvpUf+1{_HO09^BGt-H#44}@0;1(ViP;o57fTYJv`V(3_5($t|frS zX55{Zpzw<%7N2!$)RrVqCmGQuLa|8ygR#Ej9=p}LTkTMLUh?hddw%yYYzo1yMmafR z*oySHq@4ic{48}Z50d{n>|A zmrFZIK{mFKvB$Obpkb4P#%c-RW(=20xMZRMdB}N^&=NqPxEX7$%w1-j)nQAqt6ppy zGI^0mxdX@Wa1tQlZYFg^&qqC4KuOn9ZF?oq#Nq$G3UU-<{&@3ha8m z(|op*7#jfuT?C2DapNMLD`kUqUH=U<2P1f>)L zh(kw$VuaRzpn8&A8UX|&Nx(DxEd~y{?@hCZF}q?Yl>lNv65dqhJUrKLfyfUe1M-^+ o7ZPx&{YgYYRA>e5mrHLGR}{zZnTPEVMO165NEH%Yb%S_Ryq}r54upqzh#OTrKDh!2zHNt-P(rj3GzfSOV9x2=+;D%QBD9IbYH0-D8gqWm!4roPst&Ytvlo-$ zb)eFER4J`BCi{^1N1hu11~avRf4RovPvQ;`yd9JMLa97>kv_6sSk;Gk%=rQA{WY8l+r|-Q!0PXuaf9m<#Z@aHnN<2I z=?r9rSnUP_+t5ub5ox&T)+ZiSrG*Io&y;fjkyddmdSC+q)7rhU;TG2?iz{9L!T*(# z2XVFefrH_Ce;0Iv;BRyNeQ`xwD0*5MgXiQgxVo=&fdSkJDBaq#rSXnSFJMry0>ajt0|alMm%rx2Bjha|^p;}bsmQY5f%d)1Ouuw~!=7Kx zT}9__22IV{)j8Yd`iI74Er8%NFP$XrD!=1knDhqdVD&|s9Ih7=d#*xbOWkPVFE%wD zivr-1UHC7WQ~^6Bk0AUq*Hr-5&0xsdvthb)=|v7a@4&hp&cOKV9pH~zZT9kb1YQ-A zhu{ZO@^`%cTYf$+mDiLJwDxt^r?~zxvFAgKm3==xu~LgiGV%zu#JJ`WboZ#BE#=X7 z-~q1cQ-Up}geL^g0&q|M4`;-E`O@@=JVdRy3`=Pu#80Jst~11*V;`XQHI zf`MlNMvb->*QiVG9BKvaUuYBN)`f`fSD}%ta~z#t%#Y#r;IbynmR+4Q?s2_T@jD>7 zi4z^O9)`?dnEE!S(LZgz>>m7T!mp>CPVn{<=L9~mi*nlNKNMj@^XD(B0Ggzu zXK3!5Y-TGiv%^!g(6)GF+Oz!0{ju+W?||=s?||=s@4$N;cnfE*U1gg&nk4`L002ov JPDHLkV1fqC5gPyi literal 930 zcmV;T16}-yP)|00001b5ch_0Itp) z=>Px&TuDShR7efQm(6PvQ4ql2yi_f{)C!uU=&=`19=sGqsftn*QEOZJVXd~=pok=! z7CcD~dJs#tA|ksnja6Dys9L`&DE!-9vkR{hArTKW(g=F0*Y21CkVC-{QmiCb|{fa?dvbqjUlcjD#Asm~vWRlU0y4DEK`T403#+>t3#<2A5mfDiI_hVrIY3Hm0BttmxkACoW+tEmyngNSP(ux~ZM_l*R6 zvzA_tr~1%jNwT#c3IfSetL{-GKh>YLi|tUjpadMEvhMCL$hK!q{2-5g-yv*dE!AHP zhW=UidSQfr*A58Af`uaFM}!=b&LFd}|YAaSFk1C076 zUk}x!X)$*S>Hctl)6@^#hiGXMYp07*qoM6N<$ Ef+umOV*mgE diff --git a/android/app/src/main/res/drawable-xhdpi/icon_q_r_blue.png b/android/app/src/main/res/drawable-xhdpi/icon_q_r_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..47c6572daca596a0ec1dd636c158201045cc56d8 GIT binary patch literal 691 zcmV;k0!;mhP)Px%ZAnByRA>e5SI;hkK@i{3lC+4#xeme$@DTnz28kwIoH=vlLQ)B@QM^Q7fH-iL zIJ6RfvUb?{YkQsm?cu`0%*|s#>iZjtK)m8_36hvS!q19!3OYYtliRD&E`47?E$FUQe}L>4?-G`?2pjG zra{93hsZOIqOC*G#&+zXv)BU&p=_@+cm>tkI%Kqc!|H6i8qe!nr2#C=}I_2 z^L(ea=I+JHkq-M6`kG<&*2e?HIgdz&XCJBUx2JXsb;$tH!1+(TRpJwkl_PmJ0O^^S z3`$cr0P&ev+H;G?_CoeZWM=!Fi8CPK1z!QrP`@**d8scvNYnK})8C7gBR#ePBp^l4 zc4mSLn};1MN4n7!AcbM0DS$y&VCwdCaSW+o ze0#$%Tf|X>{eyXRw~&Y`$D&TbKP*kXy<2;4boS0^Q_(1LyW*sCIdazCmJqIk4XqJ3 zIIo%2FhqOs0u)!Ys~U+fz)%Q`BBEpMKW2|Fp}Ws#gzpE@e&5`5O47Y8CS=?`!iTz0dPc z&p5Hh*LKz%zD5yQKbOOnn_oWtobc$~uSdsL)$jUr-Rpk``@TWVdj_6-G(t z{O*RDXbzQ92lvOy{wHUgj{=IW{o{N9i=Xc(ZL^wa2NgBeRHi@L8bo2(g}wvA5JQ^ z;Np9B+xYLxnYklX)+7S3YVvCV0}Fr(;n@;0lAz#BV2# zoEBp4JeRcD^Hyo}yLG>J_NIyb4*#fP+&f+L{XI6G4r}vx+j$l7*OvS3)(Dt;;Q!_C zd7CO#lYbxd{d~Op-SlH04WpPvn3kJ5EG&p(6cKW_4aktW>L68cg(>r3AZN+?`Eh@8 zUj|PO-r25UeWdJjD&wnd{6>CvY?$gepNzj<)hN?cF%(XuLtTdbw7G?`wHX6 zhx$KNoFD$Mxx#pK+2)+7X{m{F^YHqpy^Yb-p m!}zKku_gd$vbd%FfxUXReYGavms`Lz%HZkh=d#Wzp$PzTzC!N+ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_chats_blue.png b/android/app/src/main/res/drawable-xxhdpi/icon_chats_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..7f13becbd36f45b8f6b0dade489d403103f27fe4 GIT binary patch literal 1217 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 literal 1464 zcmV;p1xNacP)Px)a!Eu%RA>d=m}^WNRTO~lS@y-l&d{c2R{dd2B;kjDjDKttOA9F>)Jh|(Ev*$> zSmP^DjgKED^TT&Qs-~I+YsK1NDIx(&oBF^A?wxywvH!u-*2Xie7!IposkLjHw1&O`tvwjzF0=1T8mu;W zrjc>J6M^nH#q{^oUhXvDmMmCZ@XRX+QEPxO#y5t4orZ&H#nP$OHEFML&L6V#7#JLs z@|4Z97M-1Oy2ua)2Cu$jKkUMDLwpa?9jBQ^=u%sJam z&e}czKViQ(qTL`sH z=nJs#yq=t*=eI38Z)cNs5sN}K>u+NkZnblmWa#usmXTfDxI?-S$3~=Dd^sIvzY1wB z5zZ<_vjebiJ=s~sFI36{A{&yY&8|pLeIadMTqp+LNUqGHL{J2l7AFsaIv&#BWt?py zr|cd8_}a}p#n0|o9=6k4Whq}{bRx&Y>wa8QeyelSZ8+g!o^>w<<_1OmQo1WnLbW2) zozoE38XT9i-6iUl<%3pDymrbWMi)c6L(z3ZFUC!LGnc%`Bg9oznaCpLz#Em5Tb}C9zjxN|_pfe?>O)k;7zq9K-au$+jcFDSV5o z&37GJJAqK$%e~=I{R14oL|}q%7d~OR%KAn>42f*!D|e`V80EllhY~!T=T8jrkDqE8 zTp_R!iU}$-rgg@HLaL9F4Mh$`cg0;bzIxn=o)&qCj@>Xk{LfKJS&@xZUf0Gm5vmK1 zN$adSqmAp}sO<9Hp3F!YV^3}OjWt(2gA+YxD6A!C?8Z?TIr8|P{wu6HYn!0hfZmNz z#a5ls#`HTPxqTbdDi}6o$t6wZsqWtzo8j(fYCKV&6giP&_D%)S=4_ zMSjf!BVj|0@-Rkb57q4+TytwfV|oYesD}Qrcl2zGR1ZdbwIQ>X2-Pj+DjP3nq>MRd zrJ|vTUeTM*ws02NV#sXDPC3t4!TS5X;m~*wMbpM6CIaY^Wu=04VWCYD6+$qYBYFWG z&|5J=6{0yY3I|c|L;Wox8YfU!6>Nma!KqnToNCXEiQ8x}S*bmTMT?!|;6 zKW*2T89*(BaY^?1X?r%y=TgTbS-YI4+_l(Haz(@n@!7tyHB8R8n3lMUGA>Nf|7OgZu{rZVPx&sYygZRCodHo6T+$F%ZY?r3FzqQ4WaG*WeA{F*r~}drS}#yaEzxa&1I7@DLo} z4S0Nt4 zAVI(;>atZ&#-ATJ;|9i=`_7tePK-65tg+)agPo5Ox6r0mTv_LQmQRnq zZ2kQ`KXlIRhonpP*4m>h*PCaP{ky+%I*Ia^^^e+l*1QNbnx1Q%q1)@n_1 z+Bw^5(ayYt+M;XF;%;@O9ZI*hH*davbmwO{&h4MS`+DR1$)6u_n^rrnJUy-z7pEf} zLFrq$6b=L=+vXk<2pg$|dv;nT+Y;KbgbYyZb%~A@5c6d#AO*w_V9Yv#6c9szG3y9Y zKnwxKtRtusKz_0-r30@IsrpnM*_P05H3%E2l?Y6>CA4D+(YqMT1bRZZV`q4`dOSLg ztCPpRZL+?dWlUO(sTCKeBRj?XG%0rKw4Bq<*-DcTYKs8D9CB$slz&b;XQT9_^-^sS zpv8=zok)XA+rhjvHJb<;wc_IZMS#FzW2+fLhp=;5*-l{6p3|rmH{>OnlManxU+dp5 zwc_HwYgq{>0VSXWl)(Q*px3wgz0vV2{|*TM0lgYywbuBTyXJ5@*m)V-;JCyW>xlu? zSY@#{KAt&eHgUpHdG>a=do8MK4@-Qpp6G2J9BQnxVBkPnOCt*^VJq=nC@eljuNv)B zY)9*YaBx@x1KPN*Z)Fi6=}L%II=4>kRq}~_M1ZQT?ufIka4fn8^cc7vVShSrCISReyIy4xev--bh?|ng*>g4s%h}u1#DL(p zrPIN^1NeoY@7#NTYJ4-9JJ3?ceOvGWU(f(8?)R!CQx+w@OSx->5>Nt4KnW-TC7=Y9 dfD(ua`~&l!z8q3CaF_r9002ovPDHLkV1iq*&w2m= literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_arrow_right_blue.png b/android/app/src/main/res/drawable-xxxhdpi/icon_arrow_right_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..d840b0b5de0f88c6f9c30c392db70f084d97fb45 GIT binary patch literal 916 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 literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_chats_blue.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_chats_blue.imageset/Contents.json new file mode 100644 index 0000000000..93f4992915 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_chats_blue.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_chats_blue.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_chats_blue.imageset/icon_chats_blue.png b/ios/StatusIm/Images.xcassets/icon_chats_blue.imageset/icon_chats_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..31c25b335cbb5fe39cf46077606cce495e37e68e GIT binary patch literal 810 zcmV+_1J(SAP)Px%e5SiNo&K@i@(#Gyf=Ln86L0CY4FEeHWGK!qq0$4CSbQh_MI;ROPb zh=gNPpj04QB#KD1c>o&Pb0Q>!1PCEHA-BvpUf+1{_HO09^BGt-H#44}@0;1(ViP;o57fTYJv`V(3_5($t|frS zX55{Zpzw<%7N2!$)RrVqCmGQuLa|8ygR#Ej9=p}LTkTMLUh?hddw%yYYzo1yMmafR z*oySHq@4ic{48}Z50d{n>|A zmrFZIK{mFKvB$Obpkb4P#%c-RW(=20xMZRMdB}N^&=NqPxEX7$%w1-j)nQAqt6ppy zGI^0mxdX@Wa1tQlZYFg^&qqC4KuOn9ZF?oq#Nq$G3UU-<{&@3ha8m z(|op*7#jfuT?C2DapNMLD`kUqUH=U<2P1f>)L zh(kw$VuaRzpn8&A8UX|&Nx(DxEd~y{?@hCZF}q?Yl>lNv65dqhJUrKLfyfUe1M-^+ o7ZPx&{YgYYRA>e5mrHLGR}{zZnTPEVMO165NEH%Yb%S_Ryq}r54upqzh#OTrKDh!2zHNt-P(rj3GzfSOV9x2=+;D%QBD9IbYH0-D8gqWm!4roPst&Ytvlo-$ zb)eFER4J`BCi{^1N1hu11~avRf4RovPvQ;`yd9JMLa97>kv_6sSk;Gk%=rQA{WY8l+r|-Q!0PXuaf9m<#Z@aHnN<2I z=?r9rSnUP_+t5ub5ox&T)+ZiSrG*Io&y;fjkyddmdSC+q)7rhU;TG2?iz{9L!T*(# z2XVFefrH_Ce;0Iv;BRyNeQ`xwD0*5MgXiQgxVo=&fdSkJDBaq#rSXnSFJMry0>ajt0|alMm%rx2Bjha|^p;}bsmQY5f%d)1Ouuw~!=7Kx zT}9__22IV{)j8Yd`iI74Er8%NFP$XrD!=1knDhqdVD&|s9Ih7=d#*xbOWkPVFE%wD zivr-1UHC7WQ~^6Bk0AUq*Hr-5&0xsdvthb)=|v7a@4&hp&cOKV9pH~zZT9kb1YQ-A zhu{ZO@^`%cTYf$+mDiLJwDxt^r?~zxvFAgKm3==xu~LgiGV%zu#JJ`WboZ#BE#=X7 z-~q1cQ-Up}geL^g0&q|M4`;-E`O@@=JVdRy3`=Pu#80Jst~11*V;`XQHI zf`MlNMvb->*QiVG9BKvaUuYBN)`f`fSD}%ta~z#t%#Y#r;IbynmR+4Q?s2_T@jD>7 zi4z^O9)`?dnEE!S(LZgz>>m7T!mp>CPVn{<=L9~mi*nlNKNMj@^XD(B0Ggzu zXK3!5Y-TGiv%^!g(6)GF+Oz!0{ju+W?||=s?||=s@4$N;cnfE*U1gg&nk4`L002ov JPDHLkV1fqC5gPyi literal 1464 zcmV;p1xNacP)Px)a!Eu%RA>d=m}^WNRTO~lS@y-l&d{c2R{dd2B;kjDjDKttOA9F>)Jh|(Ev*$> zSmP^DjgKED^TT&Qs-~I+YsK1NDIx(&oBF^A?wxywvH!u-*2Xie7!IposkLjHw1&O`tvwjzF0=1T8mu;W zrjc>J6M^nH#q{^oUhXvDmMmCZ@XRX+QEPxO#y5t4orZ&H#nP$OHEFML&L6V#7#JLs z@|4Z97M-1Oy2ua)2Cu$jKkUMDLwpa?9jBQ^=u%sJam z&e}czKViQ(qTL`sH z=nJs#yq=t*=eI38Z)cNs5sN}K>u+NkZnblmWa#usmXTfDxI?-S$3~=Dd^sIvzY1wB z5zZ<_vjebiJ=s~sFI36{A{&yY&8|pLeIadMTqp+LNUqGHL{J2l7AFsaIv&#BWt?py zr|cd8_}a}p#n0|o9=6k4Whq}{bRx&Y>wa8QeyelSZ8+g!o^>w<<_1OmQo1WnLbW2) zozoE38XT9i-6iUl<%3pDymrbWMi)c6L(z3ZFUC!LGnc%`Bg9oznaCpLz#Em5Tb}C9zjxN|_pfe?>O)k;7zq9K-au$+jcFDSV5o z&37GJJAqK$%e~=I{R14oL|}q%7d~OR%KAn>42f*!D|e`V80EllhY~!T=T8jrkDqE8 zTp_R!iU}$-rgg@HLaL9F4Mh$`cg0;bzIxn=o)&qCj@>Xk{LfKJS&@xZUf0Gm5vmK1 zN$adSqmAp}sO<9Hp3F!YV^3}OjWt(2gA+YxD6A!C?8Z?TIr8|P{wu6HYn!0hfZmNz z#a5ls#`HTPxqTbdDi}6o$t6wZsqWtzo8j(fYCKV&6giP&_D%)S=4_ zMSjf!BVj|0@-Rkb57q4+TytwfV|oYesD}Qrcl2zGR1ZdbwIQ>X2-Pj+DjP3nq>MRd zrJ|vTUeTM*ws02NV#sXDPC3t4!TS5X;m~*wMbpM6CIaY^Wu=04VWCYD6+$qYBYFWG z&|5J=6{0yY3I|c|L;Wox8YfU!6>Nma!KqnToNCXEiQ8x}S*bmTMT?!|;6 zKW*2T89*(BaY^?1X?r%y=TgTbS-YI4+_l(Haz(@n@!7tyHB8R8n3lMUGA>Nf|7OgZu{rZVPx%ZAnByRA>e5SI;hkK@i{3lC+4#xeme$@DTnz28kwIoH=vlLQ)B@QM^Q7fH-iL zIJ6RfvUb?{YkQsm?cu`0%*|s#>iZjtK)m8_36hvS!q19!3OYYtliRD&E`47?E$FUQe}L>4?-G`?2pjG zra{93hsZOIqOC*G#&+zXv)BU&p=_@+cm>tkI%Kqc!|H6i8qe!nr2#C=}I_2 z^L(ea=I+JHkq-M6`kG<&*2e?HIgdz&XCJBUx2JXsb;$tH!1+(TRpJwkl_PmJ0O^^S z3`$cr0P&ev+H;G?_CoeZWM=!Fi8CPK1z!QrP`@**d8scvNYnK})8C7gBR#ePBp^l4 zc4mSLn};1MN4n7!AcbM0DS$y&js opts))) +(defn share-options [text] + [{:text (label :t/sharing-copy-to-clipboard) :value #(copy-to-clipboard text)} + {:text (label :t/sharing-share) :value #(open {:message text})}]) + (defn share [text dialog-title] (let [list-selection-fn (:list-selection-fn platform-specific)] (list-selection-fn {:title dialog-title diff --git a/src/status_im/components/native_action_button.cljs b/src/status_im/components/native_action_button.cljs new file mode 100644 index 0000000000..8ff80c068f --- /dev/null +++ b/src/status_im/components/native_action_button.cljs @@ -0,0 +1,7 @@ +(ns status-im.components.native-action-button + (:require [reagent.core :as r])) + +(def class (js/require "react-native-action-button")) + +(def native-action-button (r/adapt-react-class (.-default class))) +(def native-action-button-item (r/adapt-react-class (.. class -default -Item))) diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index c5a404bf45..861a304d78 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -13,6 +13,7 @@ (def color-steel "#838b91") (def color-white "white") (def color-light-blue "#628fe3") +(def color-light-blue-transparent "#628fe333") (def color-light-blue2 "#eff3fc") (def color-light-gray "#EEF2F5") (def color-red "red") diff --git a/src/status_im/components/text_field/view.cljs b/src/status_im/components/text_field/view.cljs index b1ba7ae6a7..c051d8a934 100644 --- a/src/status_im/components/text_field/view.cljs +++ b/src/status_im/components/text_field/view.cljs @@ -92,8 +92,7 @@ (log/debug "Input blurred") (r/set-state component {:has-focus false :float-label? (if (s/blank? value) false true)}) - (when (s/blank? value) - (field-animation animation)) + (field-animation animation) (when onBlur (onBlur))) (defn get-width [event] @@ -113,7 +112,8 @@ max-length]} (r/state component) {:keys [wrapper-style input-style label-hidden? line-color focus-line-color focus-line-height secure-text-entry label-color error-color error label value on-focus on-blur validator - auto-focus on-change-text on-change on-end-editing editable placeholder auto-capitalize]} + auto-focus on-change-text on-change on-end-editing editable placeholder auto-capitalize + multiline number-of-lines]} (merge default-props (r/props component)) line-color (if error error-color line-color) focus-line-color (if error error-color focus-line-color) @@ -127,6 +127,8 @@ :style (merge st/text-input input-style) :placeholder (or placeholder "") :editable editable + :multiline multiline + :number-of-lines number-of-lines :secure-text-entry secure-text-entry :auto-capitalize auto-capitalize :on-focus #(on-input-focus {:component component diff --git a/src/status_im/components/toolbar_new/view.cljs b/src/status_im/components/toolbar_new/view.cljs index 5b98f13599..7e63af229c 100644 --- a/src/status_im/components/toolbar_new/view.cljs +++ b/src/status_im/components/toolbar_new/view.cljs @@ -23,6 +23,7 @@ custom-action :custom-action background-color :background-color custom-content :custom-content + hide-border? :hide-border? style :style}] (let [style (merge (st/toolbar-wrapper background-color) style)] [view {:style style} @@ -63,8 +64,9 @@ {:key (str "action-" action-image)})) custom-action)]] [sync-state-gradient-view] - [view st/toolbar-border-container - [view st/toolbar-border]]])) + (when-not hide-border? + [view st/toolbar-border-container + [view st/toolbar-border]])])) (def search-text-input (r/atom nil)) diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index fde74ed231..3b5e94de03 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -3,17 +3,18 @@ (:require [reagent.core :as r] [clojure.string :as str] [re-frame.core :refer [subscribe dispatch dispatch-sync]] + [status-im.components.common.common :refer [separator]] [status-im.components.react :refer [view text image icon touchable-highlight - linear-gradient scroll-view list-view list-item] :as react] - [status-im.components.action-button :refer [action-button - action-button-item]] + [status-im.components.common.common :refer [top-shaddow bottom-shaddow]] + [status-im.components.native-action-button :refer [native-action-button + native-action-button-item]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar]] [status-im.components.toolbar-new.actions :as act] @@ -73,22 +74,14 @@ (when extended? [options-btn group])]) -(defn group-top-view [] - [linear-gradient {:style st/contact-group-header-gradient-bottom - :colors st/contact-group-header-gradient-bottom-colors}]) - -(defn group-bottom-view [] - [linear-gradient {:style st/contact-group-header-gradient-top - :colors st/contact-group-header-gradient-top-colors}]) - (defn contact-group-form [{:keys [contacts contacts-count group edit? click-handler]}] - (let [shadows? (get-in platform-specific [:contacts :group-block-shadows?]) + (let [shadows? (get-in platform-specific [:group-block-shadows?]) subtitle (:name group)] [view st/contact-group (when subtitle [subtitle-view subtitle contacts-count group edit?]) (when (and subtitle shadows?) - [group-top-view]) + [top-shaddow]) [view st/contacts-list [view st/contact-list-spacing] (doall @@ -108,13 +101,11 @@ (:group-id group)]) :text (label :t/remove-from-group)}])}] (when-not (= contact (last contacts)) - [view st/contact-item-separator-wrapper - [view st/contact-item-separator]])]) + [separator st/contact-item-separator])]) contacts))] (when (< contacts-limit contacts-count) [view - [view st/contact-item-separator-wrapper - [view st/contact-item-separator]] + [separator st/contact-item-separator] [view st/show-all [touchable-highlight {:on-press #(do (when edit? @@ -126,7 +117,7 @@ :font (get-in platform-specific [:component-styles :contacts :show-all-text-font])} (str (- contacts-count contacts-limit) " " (label :t/more))]]]]]) (when shadows? - [group-bottom-view])])) + [bottom-shaddow])])) (defview contact-group-view [{:keys [group] :as params}] [contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit] @@ -135,12 +126,12 @@ :contacts-count contacts-count})]) (defn contacts-action-button [] - [action-button {:button-color color-blue - :offset-x 16 - :offset-y 22 - :hide-shadow true - :spacing 13} - [action-button-item + [native-action-button {:button-color color-blue + :offset-x 16 + :offset-y 22 + :hide-shadow true + :spacing 13} + [native-action-button-item {:title (label :t/new-contact) :buttonColor :#9b59b6 :onPress #(dispatch [:navigate-to :new-contact])} diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index 3d88cf27c4..6c07c0af4c 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -52,25 +52,6 @@ {:margin-left 8 :opacity 0.6}) -(def contact-group-header-gradient-top - {:flexDirection :row - :height 3 - :backgroundColor toolbar-background2}) - -(def contact-group-header-gradient-top-colors - ["rgba(24, 52, 76, 0.165)" - "rgba(24, 52, 76, 0.03)" - "rgba(24, 52, 76, 0.01)"]) - -(def contact-group-header-gradient-bottom - {:flexDirection :row - :height 2 - :backgroundColor toolbar-background2}) - -(def contact-group-header-gradient-bottom-colors - ["rgba(24, 52, 76, 0.01)" - "rgba(24, 52, 76, 0.05)"]) - (def show-all (merge (get-in p/platform-specific [:component-styles :contacts :show-all]) {:flexDirection :row @@ -80,11 +61,8 @@ (def show-all-text (get-in p/platform-specific [:component-styles :contacts :show-all-text])) -(def contact-item-separator-wrapper - {:background-color color-white}) - (def contact-item-separator - (get-in p/platform-specific [:component-styles :contacts :separator])) + {:margin-left 72}) (def contact-container (merge (get-in p/platform-specific [:component-styles :contacts :contact-container]) @@ -155,13 +133,6 @@ :alignItems :center :justifyContent :center}) -(def search-btn - {:width 24 - :height 56 - :margin-right 24 - :alignItems :center - :justifyContent :center}) - ; New contact (def contact-form-container diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index aed9ece9c3..61d5424f83 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -1,6 +1,7 @@ (ns status-im.contacts.views.contact-list (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] + [status-im.components.common.common :refer [separator]] [status-im.components.react :refer [view text image icon @@ -114,8 +115,7 @@ (defn render-separator [_ row-id _] (list-item ^{:key row-id} - [view st/contact-item-separator-wrapper - [view st/contact-item-separator]])) + [separator st/contact-item-separator])) (defview contacts-list-view [group modal click-handler action edit?] [contacts [:all-added-group-contacts-filtered (:group-id group)] diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 2d2c5ee656..d6544f1f89 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -37,6 +37,7 @@ [status-im.participants.views.remove :refer [remove-participants]] [status-im.group-settings.screen :refer [group-settings]] [status-im.profile.screen :refer [profile my-profile]] + [status-im.profile.edit.screen :refer [edit-my-profile]] [status-im.profile.photo-capture.screen :refer [profile-photo-capture]] status-im.data-store.core [taoensso.timbre :as log] @@ -114,11 +115,13 @@ :qr-scanner qr-scanner :chat chat :profile profile + :my-profile my-profile + :edit-my-profile edit-my-profile :profile-photo-capture profile-photo-capture :accounts accounts :login login - :recover recover - :my-profile my-profile)] + :recover recover)] + [view {:flex 1} [component] diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 89f94dfa66..d3b43370a2 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -77,10 +77,6 @@ :subtitle-count {:color styles/color-gray4 :font-size 16 :letter-spacing -0.2} - :separator {:margin-left 72 - :height 1 - :background-color styles/color-gray5 - :opacity 0.5} :info-container {:margin-left 16} :contact-inner-container {:height 63} :icon-check {:border-radius 50 @@ -104,6 +100,29 @@ :line-height 20 :letter-spacing -0.2 :color styles/text1-color}} + :profile {:profile-bage {:padding-top 24} + :profile-name-text {:font-size 17 + :line-height 20 + :letter-spacing -0.2} + :profile-status-text {:font-size 14 + :line-height 20 + :letter-spacing -0.2} + :profile-setting-item {:padding-left 16 + :padding-right 16 + :height 73} + :profile-setting-title {:font-size 14 + :letter-spacing -0.2} + :profile-setting-text {:font-size 17 + :letter-spacing -0.2} + :profile-setting-spacing {:height 10} + :add-to-contacts-text {:font-size 17 + :line-height 20 + :letter-spacing -0.2} + :edit-name-title {:font-size 13 + :letter-spacing -0.1} + :profile-icon-edit-text {:font-size 15 + :line-height 20 + :letter-spacing -0.2}} :new-group {:group-name-text {:font-size 13} :members-text {:letter-spacing -0.2 :font-size 16} @@ -144,6 +163,15 @@ :font-size 17 :line-height 20 :letter-spacing -0.2} + :action-button-label {:color styles/color-light-blue + :letter-spacing -0.2 + :font-size 17 + :line-height 20} + :action-button-icon-container {:background-color styles/color-light-blue-transparent} + :action-button {:height 64} + :separator {:height 1 + :background-color styles/color-gray5 + :opacity 0.5} :bottom-gradient {:height 1} :input-label {:left 0} :input-error-text {:margin-left 0} @@ -159,7 +187,8 @@ :toolbar-last-activity {:color styles/text2-color :background-color :transparent :top 0 - :font-size 14}}) + :font-size 14} + :text-field-focus-line-height 1}) (def fonts {:light {:font-family "SFUIText-Light"} @@ -196,10 +225,10 @@ :render-separator? true} :uppercase? false :contacts {:action-button? false - :new-contact-in-toolbar? true - :group-block-shadows? false} + :new-contact-in-toolbar? true} + :group-block-shadows? false :discover {:uppercase-subtitles? true} :public-group-icon-container {:margin-top 2} :private-group-icon-container {:margin-top 2} - :group-chat-focus-line-height 1 :public-group-chat-hash-style {:top 6 :left 3}}) + diff --git a/src/status_im/new_group/styles.cljs b/src/status_im/new_group/styles.cljs index 2a46c058b3..ede18b385a 100644 --- a/src/status_im/new_group/styles.cljs +++ b/src/status_im/new_group/styles.cljs @@ -62,7 +62,7 @@ (get-in platform-specific [:public-group-chat-hash-style]))) (def group-chat-focus-line-height - (get-in platform-specific [:group-chat-focus-line-height])) + (get-in platform-specific [:component-styles :text-field-focus-line-height])) (def group-chat-name-wrapper {:padding-top 0 diff --git a/src/status_im/new_group/views/chat_group_settings.cljs b/src/status_im/new_group/views/chat_group_settings.cljs index f89a27032d..f801fd1a2f 100644 --- a/src/status_im/new_group/views/chat_group_settings.cljs +++ b/src/status_im/new_group/views/chat_group_settings.cljs @@ -68,7 +68,7 @@ [view st/group-container [view {:flex 1} [group-toolbar type true] - [scroll-view {:keyboardShouldPersistTaps true} + [scroll-view [group-name-view] [chat-group-members] [view st/separator] diff --git a/src/status_im/new_group/views/contact_toggle_list.cljs b/src/status_im/new_group/views/contact_toggle_list.cljs index 25178f7d6e..5e549fb404 100644 --- a/src/status_im/new_group/views/contact_toggle_list.cljs +++ b/src/status_im/new_group/views/contact_toggle_list.cljs @@ -12,7 +12,7 @@ [status-im.utils.listview :refer [to-datasource]] [status-im.new-group.views.toggle-contact :refer [group-toggle-contact group-toggle-participant]] - [status-im.new-group.views.group :refer [separator]] + [status-im.components.common.common :refer [separator]] [status-im.new-group.styles :as st] [status-im.contacts.styles :as cst] [status-im.i18n :refer [label]] @@ -41,7 +41,7 @@ (defn render-separator [_ row-id _] (list-item ^{:key row-id} - [separator])) + [separator cst/contact-item-separator])) (defn render-spacing [] #(list-item [view cst/contact-list-spacing])) diff --git a/src/status_im/new_group/views/group.cljs b/src/status_im/new_group/views/group.cljs index 2a2dc96fd4..b8a8f8cd80 100644 --- a/src/status_im/new_group/views/group.cljs +++ b/src/status_im/new_group/views/group.cljs @@ -2,6 +2,7 @@ (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [dispatch]] [status-im.contacts.styles :as cst] + [status-im.components.common.common :as cmn] [status-im.components.react :refer [view text icon @@ -15,8 +16,7 @@ [status-im.i18n :refer [label]])) (defn separator [] - [view cst/contact-item-separator-wrapper - [view cst/contact-item-separator]]) + [cmn/separator cst/contact-item-separator]) (defview group-name-input [] [new-group-name [:get :new-chat-name]] @@ -99,8 +99,7 @@ (defn more-btn [contacts-limit contacts-count on-press] [view - [view cst/contact-item-separator-wrapper - [view cst/contact-item-separator]] + [separator] [view cst/show-all [touchable-highlight {:on-press on-press} [view diff --git a/src/status_im/new_group/views/reorder_groups.cljs b/src/status_im/new_group/views/reorder_groups.cljs index 803fce4683..28fa96cd43 100644 --- a/src/status_im/new_group/views/reorder_groups.cljs +++ b/src/status_im/new_group/views/reorder_groups.cljs @@ -4,17 +4,16 @@ [status-im.components.react :refer [view text icon - linear-gradient touchable-highlight list-item]] [status-im.components.confirm-button :refer [confirm-button]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar]] [status-im.components.sortable-list-view :refer [sortable-list-view sortable-item]] + [status-im.components.common.common :refer [top-shaddow bottom-shaddow]] [status-im.utils.listview :refer [to-datasource]] [status-im.utils.platform :refer [android?]] [status-im.new-group.styles :as st] - [status-im.contacts.styles :as cst] [status-im.i18n :refer [label label-pluralize]] [status-im.utils.platform :refer [platform-specific]] [reagent.core :as r])) @@ -35,14 +34,6 @@ [view st/order-item-icon [icon :grab_gray]]]])) -(defn top-shaddow [] - [linear-gradient {:style cst/contact-group-header-gradient-bottom - :colors cst/contact-group-header-gradient-bottom-colors}]) - -(defn bottom-shaddow [] - [linear-gradient {:style cst/contact-group-header-gradient-top - :colors cst/contact-group-header-gradient-top-colors}]) - (defn render-separator [last shadows?] (fn [_ row-id _] (list-item @@ -57,7 +48,7 @@ (defview reorder-groups [] [groups [:get :contact-groups] order [:get :groups-order] - shadows? (get-in platform-specific [:contacts :group-block-shadows?])] + shadows? (get-in platform-specific [:group-block-shadows?])] (let [this (r/current-component)] [view st/reorder-groups-container [status-bar] diff --git a/src/status_im/profile/edit/screen.cljs b/src/status_im/profile/edit/screen.cljs new file mode 100644 index 0000000000..c5aa2a2f13 --- /dev/null +++ b/src/status_im/profile/edit/screen.cljs @@ -0,0 +1,90 @@ +(ns status-im.profile.edit.screen + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [status-im.profile.styles :as st] + [status-im.components.styles :refer [color-blue color-gray5]] + [re-frame.core :refer [dispatch]] + [status-im.components.status-bar :refer [status-bar]] + [status-im.components.toolbar-new.view :refer [toolbar]] + [status-im.components.toolbar-new.actions :as act] + [status-im.components.text-field.view :refer [text-field]] + [status-im.i18n :refer [label]] + [status-im.components.confirm-button :refer [confirm-button]] + [status-im.components.chat-icon.screen :refer [my-profile-icon]] + [status-im.components.context-menu :refer [context-menu]] + [status-im.profile.validations :as v] + [status-im.components.react :refer [view + scroll-view + text + touchable-highlight + text-input]] + [cljs.spec :as s])) + +(defn edit-my-profile-toolbartoolbar [] + [toolbar {:title (label :t/edit-profile) + :actions [{:image :blank}]}]) + +(defview profile-name-input [] + [new-profile-name [:get-in [:profile-edit :name]]] + [view + [text-field + {:wrapper-style st/profile-name-wrapper + :line-color st/edit-line-color + :focus-line-color st/profile-focus-line-color + :focus-line-height st/profile-focus-line-height + :label-hidden? true + :input-style st/profile-name-input + :on-change-text #(dispatch [:set-in [:profile-edit :name] %]) + :value new-profile-name}]]) + +(def profile-icon-options + [{:text (label :t/image-source-gallery) :value #(dispatch [:open-image-picker])} + {:text (label :t/image-source-make-photo) :value #(dispatch [:navigate-to :profile-photo-capture])}]) + +(defn edit-profile-bage [contact] + [view st/edit-profile-bage + [view + [context-menu + [my-profile-icon {:account contact + :edit? true}] + profile-icon-options]] + [view st/edit-profile-name-container + [text {:style st/edit-name-title} + (label :t/name)] + [profile-name-input]]]) + +(defn edit-profile-status [{:keys [status]}] + [view st/edit-profile-status + [view + [text {:style st/edit-status-title} "Status"] + [view + [text-field + {:wrapper-style st/profile-status-wrapper + :line-color st/edit-line-color + :focus-line-color st/profile-focus-line-color + :focus-line-height st/profile-focus-line-height + :multiline true + :max-length 140 + :placeholder (label :t/profile-no-status) + :label-hidden? true + :input-style st/profile-status-input + :on-change-text #(dispatch [:set-in [:profile-edit :status] %]) + :value status}]]]]) + +(defview edit-my-profile [] + [current-account [:get-current-account] + changed-account [:get :profile-edit]] + (let [profile-edit-data-valid? (s/valid? ::v/profile changed-account) + profile-edit-data-changed? (or (not= (:name current-account) (:name changed-account)) + (not= (:status current-account) (:status changed-account)) + (not= (:photo-path current-account) (:photo-path changed-account)))] + [view st/profile + [status-bar] + [edit-my-profile-toolbartoolbar] + [view {:flex 1} + [scroll-view st/edit-my-profile-form + [edit-profile-bage changed-account] + [edit-profile-status changed-account]]] + (when (and profile-edit-data-changed? profile-edit-data-valid?) + [confirm-button (label :t/save) #(do + (dispatch [:check-status-change (:status changed-account)]) + (dispatch [:account-update changed-account]))])])) diff --git a/src/status_im/profile/handlers.cljs b/src/status_im/profile/handlers.cljs index 3b7b2b9a51..0d248257b7 100644 --- a/src/status_im/profile/handlers.cljs +++ b/src/status_im/profile/handlers.cljs @@ -1,5 +1,5 @@ (ns status-im.profile.handlers - (:require [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [subscribe dispatch after]] [status-im.utils.handlers :refer [register-handler]] [status-im.components.react :refer [show-image-picker]] [status-im.utils.image-processing :refer [img->base64]] @@ -44,3 +44,23 @@ (fn [db _] (dispatch [:navigate-to :chat console-chat-id]) (dispatch [:set-chat-command :phone])))) + +(register-handler :open-chat-with-the-send-transaction + (u/side-effect! + (fn [db [_ chat-id]] + (dispatch [:navigate-to :chat chat-id]) + (dispatch [:set-chat-command :send])))) + +(defn prepare-edit-profile + [{:keys [current-account-id] :as db} _] + (let [current-account (select-keys (get-in db [:accounts current-account-id]) + [:name :photo-path :status])] + (update-in db [:profile-edit] merge current-account))) + +(defn open-edit-profile [_ _] + (dispatch [:navigate-to :edit-my-profile])) + +(register-handler + :open-edit-my-profile + (-> prepare-edit-profile + ((after open-edit-profile)))) diff --git a/src/status_im/profile/screen.cljs b/src/status_im/profile/screen.cljs index 7e3ffb68b5..dec7b8a251 100644 --- a/src/status_im/profile/screen.cljs +++ b/src/status_im/profile/screen.cljs @@ -1,241 +1,211 @@ (ns status-im.profile.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [dispatch]] [clojure.string :as str] - [cljs.spec :as s] [reagent.core :as r] + [status-im.contacts.styles :as cst] + [status-im.components.common.common :refer [separator]] + [status-im.components.styles :refer [color-blue color-gray5]] + [status-im.components.context-menu :refer [context-menu]] + [status-im.components.action-button.action-button :refer [action-button + action-separator]] + [status-im.components.common.common :refer [top-shaddow bottom-shaddow]] [status-im.components.react :refer [view text text-input image icon - modal scroll-view - touchable-highlight - touchable-opacity - touchable-without-feedback - show-image-picker - dismiss-keyboard!]] - [status-im.components.icons.custom-icons :refer [oct-icon]] + touchable-highlight]] [status-im.components.chat-icon.screen :refer [my-profile-icon]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.text-field.view :refer [text-field]] - [status-im.components.selectable-field.view :refer [selectable-field]] - [status-im.components.status-view.view :refer [status-view]] - [status-im.components.list-selection :refer [share]] - [status-im.utils.phone-number :refer [format-phone-number]] - [status-im.utils.image-processing :refer [img->base64]] - [status-im.utils.platform :refer [platform-specific]] + [status-im.components.toolbar-new.view :refer [toolbar]] + [status-im.components.toolbar-new.actions :as act] + [status-im.components.list-selection :refer [share-options]] + [status-im.utils.platform :refer [platform-specific android?]] [status-im.profile.handlers :refer [message-user]] - [status-im.profile.validations :as v] [status-im.profile.styles :as st] - [status-im.utils.random :refer [id]] - [status-im.utils.utils :refer [clean-text]] - [status-im.components.image-button.view :refer [show-qr-button]] - [status-im.i18n :refer [label - get-contact-translated]] - [status-im.constants :refer [console-chat-id wallet-chat-id]])) + [status-im.i18n :refer [label]] + [status-im.utils.datetime :as time])) -(defn toolbar [{:keys [account edit?]}] - (let [profile-edit-data-valid? (s/valid? ::v/profile account)] - [view - [touchable-highlight {:style st/back-btn-touchable - :on-press (fn [] - (dispatch [:set-in [:profile-edit :edit?] false]) - (dispatch [:set-in [:profile-edit :name] nil]) - (dispatch [:navigate-back]))} - [view st/back-btn-container - [icon :back st/back-btn-icon]]] - [touchable-highlight {:style st/actions-btn-touchable - :on-press (fn [] - (if edit? - (when profile-edit-data-valid? - (dismiss-keyboard!) - (dispatch [:check-status-change (:status account)]) - (dispatch [:account-update account]) - (dispatch [:set-in [:profile-edit :edit?] false])) - (dispatch [:set :profile-edit (merge account {:edit? true})])))} - [view st/actions-btn-container - (if edit? - [oct-icon {:name :check - :style (st/ok-btn-icon profile-edit-data-valid?)}] - [icon :dots st/edit-btn-icon])]]])) -(defn status-image-view [_] - (let [component (r/current-component) - just-opened? (r/atom true) - input-ref (r/atom nil) - set-status-height #(let [height (-> (.-nativeEvent %) - (.-contentSize) - (.-height))] - (r/set-state component {:height height}))] - (r/create-class - {:reagent-render - (fn [{{:keys [whisper-identity - name - status - photo-path]} :account - edit? :edit?}] - [view st/status-block - [view st/user-photo-container +(defn my-profile-toolbar [] + [toolbar {:actions [(act/opts [{:value #(dispatch [:open-edit-my-profile]) + :text (label :t/edit)}])]}]) - (if edit? - [touchable-highlight {:on-press (fn [] - (let [list-selection-fn (:list-selection-fn platform-specific)] - (dispatch [:open-image-source-selector list-selection-fn])))} - [view - [my-profile-icon {:account {:photo-path photo-path - :name name} - :edit? edit?}]]] - [my-profile-icon {:account {:photo-path photo-path - :name name} - :edit? edit?}])] - [text-field - {:line-color :white - :focus-line-color :white - :editable edit? - :input-style (st/username-input edit? (s/valid? ::v/name name)) - :wrapper-style st/username-wrapper - :value (get-contact-translated whisper-identity :name name) - :on-change-text #(dispatch [:set-in [:profile-edit :name] %])}] - (if (or edit? @just-opened?) - [text-input {:ref #(reset! input-ref %) - :style (st/status-input (:height (r/state component))) - :multiline true - :editable true - :on-content-size-change #(do (set-status-height %) - (reset! just-opened? false)) - :max-length 140 - :placeholder (label :t/profile-no-status) - :on-change-text #(let [status (clean-text %)] - (if (str/includes? % "\n") - (.blur @input-ref) - (dispatch [:set-in [:profile-edit :status] status]))) - :default-value status}] - [status-view {:style (st/status-text (:height (r/state component))) - :status status}])])}))) +(defn online-text [last-online] + (let [last-online-date (time/to-date last-online) + now-date (time/now)] + (if (and (pos? last-online) + (<= last-online-date now-date)) + (time/time-ago last-online-date) + (label :t/active-unknown)))) -(defview profile [] - [{whisper-identity :whisper-identity - address :address - username :name - photo-path :photo-path - phone :phone - status :status - :as contact} [:contact]] - [scroll-view {:style st/profile} - [status-bar] - [view - [touchable-highlight {:style st/back-btn-touchable - :on-press (fn [] - (dispatch [:navigate-back]))} - [view (get-in platform-specific [:component-styles :toolbar-nav-action]) - [icon :back st/back-btn-icon]]] - ;; TODO not implemented - #_[touchable-highlight {:style st/actions-btn-touchable - :on-press (fn [] - (.log js/console "Dots pressed!"))} - [view st/actions-btn-container - [icon :dots st/edit-btn-icon]]]] +(defn profile-bage [{:keys [name last-online] :as contact}] + [view st/profile-bage + [my-profile-icon {:account contact + :edit? false}] + [view st/profile-name-container + [text {:style st/profile-name-text} + name]] + (when-not (nil? last-online) + [view st/profile-status-container + [text {:style st/profile-status-text} + (online-text last-online)]])]) - [status-image-view {:account contact - :photo-path photo-path - :edit? false}] +(defn add-to-contacts [pending? chat-id] + [view + (if pending? + [touchable-highlight {:on-press #(dispatch [:add-pending-contact chat-id])} + [view st/add-to-contacts + [text {:style st/add-to-contacts-text + :font (when android? :medium) + :uppercase? (get-in platform-specific [:uppercase?])} + (label :t/add-to-contacts)]]] + [view st/in-contacts + [icon :ok_blue] + [view st/in-contacts-inner + [text {:style st/in-contacts-text + :font (when android? :medium) + :uppercase? (get-in platform-specific [:uppercase?])} + (label :t/in-contacts)]]])]) - [scroll-view (merge st/profile-properties-container {:keyboardShouldPersistTaps true - :bounces false}) +(defn profile-actions [whisper-identity chat-id] + [view st/profile-actions-container + [action-button (label :t/start-conversation) + :chats_blue + #(message-user whisper-identity)] + [action-separator] + [action-button (label :t/send-transaction) + :arrow_right_blue + #(dispatch [:open-chat-with-the-send-transaction chat-id])]]) - [view st/status-block - [view st/btns-container - [touchable-highlight {:onPress #(message-user whisper-identity)} - [view st/message-btn - [text {:style st/message-btn-text} (label :t/message)]]] - ;; TODO not implemented - #_[touchable-highlight {:onPress #(.log js/console "Not yet implemented")} - [view st/more-btn - [icon :more_vertical_blue st/more-btn-image]]]]] +(defn profile-info-item [label value options text-mode] + [view st/profile-setting-item + [view st/profile-setting-text-container + [text {:style st/profile-setting-title} + label] + [view st/profile-setting-spacing] + [text {:style st/profile-setting-text + :numberOfLines 1 + :ellipsizeMode text-mode} + value]] + (when options + [context-menu + [icon :options_gray] + options])]) - [view st/profile-property-with-top-spacing - [selectable-field {:label (label :t/phone-number) - :editable? false - :value (if (and phone (not (str/blank? phone))) - (format-phone-number phone) - (label :t/not-specified))}] - [view st/underline-container]] +(defn show-qr [contact qr-source] + #(dispatch [:navigate-to-modal :qr-code-view {:contact contact + :qr-source qr-source}])) - (when address - [view st/profile-property - [view st/profile-property-row - [view st/profile-property-field - [selectable-field {:label (label :t/address) - :editable? false - :value address - :on-press #(share address (label :t/address))}]] - [show-qr-button {:handler #(dispatch [:navigate-to-modal :qr-code-view {:contact contact - :qr-source :whisper-identity}])}]] - [view st/underline-container]]) +(defn profile-info-address-item [{:keys [address] :as contact}] + [profile-info-item + (label :t/address) + address + (into [] + (concat [{:value (show-qr contact :address) + :text (label :t/show-qr)}] + (share-options address))) + :middle]) - [view st/profile-property - [view st/profile-property-row - [view st/profile-property-field - [selectable-field {:label (label :t/public-key) - :editable? false - :value whisper-identity - :on-press #(share whisper-identity (label :t/public-key))}]] - [show-qr-button {:handler #(dispatch [:navigate-to-modal :qr-code-view {:contact contact - :qr-source :public-key}])}]]] +(defn profile-info-public-key-item [public-key contact] + [profile-info-item + (label :t/public-key) + public-key + (into [] + (concat [{:value (show-qr contact :public-key) + :text (label :t/show-qr)}] + (share-options public-key))) + :middle]) - [view st/underline-container]]]) +(defn info-item-separator [] + [separator st/info-item-separator]) + +(defn tag-view [tag] + [text {:style {:color color-blue} + :font :medium} + (str tag " ")]) + +(defn colorize-status-hashtags [status] + (for [[i status] (map-indexed vector (str/split status #" "))] + (if (.startsWith status "#") + ^{:key (str "item-" i)} + [tag-view status] + ^{:key (str "item-" i)} + (str status " ")))) + +(defn profile-info [{:keys [whisper-identity :whisper-identity + status :status + phone :phone] :as contact}] + [view + [profile-info-item (label :t/status) (colorize-status-hashtags status)] + [info-item-separator] + [profile-info-address-item contact] + [info-item-separator] + [profile-info-public-key-item whisper-identity contact] + [info-item-separator] + [profile-info-item (label :t/phone-number) phone]]) + +(defn my-profile-info [{:keys [public-key :public-key + status :status + phone :phone] :as contact}] + [view + [profile-info-item + (label :t/status) + (colorize-status-hashtags status) + [{:value #(dispatch [:open-edit-my-profile]) + :text (label :t/edit)}]] + [info-item-separator] + [profile-info-address-item contact] + [info-item-separator] + [profile-info-public-key-item public-key contact] + [info-item-separator] + [profile-info-item (label :t/phone-number) phone [{:value #(dispatch [:phone-number-change-requested]) + :text (label :t/edit)}]]]) (defview my-profile [] - [edit? [:get-in [:profile-edit :edit?]] - qr [:get-in [:profile-edit :qr-code]] - current-account [:get-current-account] - changed-account [:get :profile-edit]] - (let [{:keys [phone - address - public-key] - :as account} (if edit? - changed-account - current-account)] - [scroll-view {:style st/profile - :bounces false} + [current-account [:get-current-account]] + (let [shadows? (get-in platform-specific [:group-block-shadows?])] + [view st/profile [status-bar] - [toolbar {:account account - :edit? edit?}] + [my-profile-toolbar] + [view st/my-profile-form + [profile-bage current-account]] + (when shadows? + [bottom-shaddow]) + [view st/profile-info-container + (when shadows? + [top-shaddow]) + [view st/profile-actions-container + [action-button (label :t/share-qr) + :q_r_blue + (show-qr current-account :public-key)]] + [view st/form-separator] + [my-profile-info current-account] + (when shadows? + [bottom-shaddow])]])) - [status-image-view {:account account - :edit? edit?}] - - [scroll-view (merge st/my-profile-properties-container {:bounces false}) - [view st/profile-property - [selectable-field {:label (label :t/phone-number) - :editable? edit? - :value (if (and phone (not (str/blank? phone))) - (format-phone-number phone) - (label :t/not-specified)) - :on-press #(dispatch [:phone-number-change-requested])}] - [view st/underline-container]] - - [view st/profile-property - [view st/profile-property-row - [view st/profile-property-field - [selectable-field {:label (label :t/address) - :editable? edit? - :value address - :on-press #(share address (label :t/address))}]] - [show-qr-button {:handler #(dispatch [:navigate-to-modal :qr-code-view {:contact account - :qr-source :address}])}]] - [view st/underline-container]] - - [view st/profile-property - [view st/profile-property-row - [view st/profile-property-field - [selectable-field {:label (label :t/public-key) - :editable? edit? - :value public-key - :on-press #(share public-key (label :t/public-key))}]] - [show-qr-button {:handler #(dispatch [:navigate-to-modal :qr-code-view {:contact account - :qr-source :public-key}])}]]] - - [view st/underline-container]]])) +(defview profile [] + [{:keys [pending? + whisper-identity] + :as contact} [:contact] + chat-id [:get :current-chat-id]] + (let [shadows? (get-in platform-specific [:group-block-shadows?])] + [view st/profile + [status-bar] + [toolbar] + [scroll-view + [view st/profile-form + [profile-bage contact] + [add-to-contacts pending? chat-id]] + (when shadows? + [bottom-shaddow]) + [view st/profile-info-container + (when shadows? + [top-shaddow]) + [profile-actions whisper-identity chat-id] + [view st/form-separator] + [profile-info contact] + (when shadows? + [bottom-shaddow])]]])) \ No newline at end of file diff --git a/src/status_im/profile/styles.cljs b/src/status_im/profile/styles.cljs index befa265d27..14a5754e95 100644 --- a/src/status_im/profile/styles.cljs +++ b/src/status_im/profile/styles.cljs @@ -1,168 +1,182 @@ (ns status-im.profile.styles + (:require-macros [status-im.utils.styles :refer [defstyle]]) (:require [status-im.components.styles :refer [color-white - color-gray - color-black - color-blue - color-blue-transparent - text1-color - text1-disabled-color - text2-color - color-red - separator-color]] + color-gray4 + color-gray5 + color-light-gray + color-light-blue + color-light-blue-transparent + text1-color]] [status-im.utils.platform :as p])) +(defn ps-profile [item] + (get-in p/platform-specific [:component-styles :profile item])) + (def profile {:flex 1 - :background-color color-white + :background-color color-light-gray :flex-direction :column}) -(def back-btn-touchable - {:position :absolute}) +(def profile-form + {:background-color color-white + :padding-bottom 16}) -(def back-btn-container - {:width 46 - :height 56 - :align-items :center - :justify-content :center}) +(def my-profile-form + {:background-color color-white + :padding-bottom 24}) -(def back-btn-icon - {:width 8 - :height 14}) +(def edit-my-profile-form + {:background-color color-white + :flex 1}) -(def actions-btn-touchable - {:position :absolute - :right 0}) +(defstyle profile-info-container + {:background-color color-white + :ios {:margin-top 16} + :android {:margin-top 12}}) -(def actions-btn-container - {:width 56 - :height 56 - :align-items :center - :justify-content :center}) +(defstyle profile-actions-container + {:android {:padding-top 8 + :padding-bottom 8}}) -(def edit-btn-icon - {:width 4 - :height 16}) +(def profile-bage + (merge (ps-profile :profile-bage) + {:align-items :center})) -(defn ok-btn-icon [enabled?] - {:font-size 22 - :color (if enabled? color-black color-gray)}) +(def edit-profile-bage + {:flex-direction :row + :align-items :center + :padding-left 24 + :padding-top 25}) -(def user-photo-container - {:margin-top 22}) +(def profile-name-container + {:margin-top 12}) -(def username-wrapper - {:width 300 - :margin-top (if p/ios? -18 -22) - :margin-bottom -16}) +(defstyle edit-profile-name-container + {:flex 1 + :ios {:padding-left 32 + :padding-top 11} + :android {:padding-top 16 + :padding-left 16}}) -(defn username-input [edit? valid?] - {:font-size 18 - :text-align :center - :color (if edit? - (if valid? text1-color color-red) - text1-disabled-color)}) +(def edit-name-title + (merge (ps-profile :edit-name-title) + {:color color-gray4})) -(def status-block - {:flex-direction "column" - :align-items "center" - :justifyContent "center" - :margin-left 55 - :margin-right 55}) +(def edit-status-title + edit-name-title) -(defn status-view [height] - {:align-self "stretch" - :font-size 14 - :min-height height - :text-align "center" - :color text2-color}) +(def profile-name-text + (ps-profile :profile-name-text)) -(defn status-input [height] - (merge (status-view height) - {:margin-left (if p/ios? 21 16) - :margin-right 16 - :margin-top (if p/ios? 6 1)})) +(def profile-status-container + {:margin-top 4}) -(defn status-text [height] - (merge (status-view (- height (if p/ios? 5 10))) - {:margin-left 18 - :margin-right 18 - :margin-top 11 - :margin-bottom 0})) +(def profile-status-text + (merge (ps-profile :profile-status-text) + {:color color-gray4})) -(def btns-container - {:margin-top 0 - :flex-direction :row}) +(def profile-setting-item + (merge (ps-profile :profile-setting-item) + {:flex-direction :row + :align-items :center})) -(def message-btn - {:height 40 - :justify-content :center - :background-color color-blue - :padding-left 25 - :padding-right 25 - :border-radius 20}) +(def profile-setting-text-container + {:flex 1 + :padding-right 20}) -(def message-btn-text - {:margin-top -2.5 - :font-size 14 - :color color-white}) +(def profile-setting-title + (merge (ps-profile :profile-setting-title) + {:color color-gray4})) -(def more-btn - {:margin-left 10 - :width 40 - :height 40 - :align-items :center - :justify-content :center - :background-color color-blue-transparent - :padding 8 - :border-radius 20}) +(def profile-setting-text + (ps-profile :profile-setting-text)) -(def more-btn-image - {:width 4 - :height 16}) +(def profile-setting-spacing + (ps-profile :profile-setting-spacing)) -(def profile-properties-container - {:align-items :stretch - :flex-firection :column - :margin-top 16}) - -(def my-profile-properties-container - {:align-items :stretch - :flex-firection :column - :margin-top 32}) - -(def profile-property - {:margin-left 16}) - -(def profile-property-with-top-spacing - {:margin-top 32 - :margin-left 16}) - -(def profile-property-row - {:flex 1 - :flex-direction :row}) - -(def profile-property-field - {:margin-right 96 - :flex 1}) - -(def report-user-text - {:font-size 14 - :line-height 21 - :color text2-color - ;; IOS: - :letter-spacing 0.5}) - -(def qr-code - {:width 250 - :height 250 - :background-color "white" +(def add-to-contacts + {:margin-top 24 + :margin-left 16 + :margin-right 16 + :background-color color-light-blue :border-radius 4 - :align-items :center - :padding-top 15 - :elevation 4}) + :height 52 + :align-items :center + :justify-content :center}) + +(def in-contacts + (merge add-to-contacts + {:flex-direction :row + :padding-right 40 + :padding-left 16 + :justify-content :flex-start + :background-color color-light-blue-transparent})) + +(def in-contacts-inner + {:align-items :center + :flex 1}) + +(def add-to-contacts-text + (merge (ps-profile :add-to-contacts-text) + {:color color-white})) + +(def in-contacts-text + (merge add-to-contacts-text + {:color color-light-blue})) + +(def info-item-separator + {:margin-left 16}) + +(def form-separator + (merge (ps-profile :form-separator) + {:height 1 + :background-color color-gray5 + :opacity 0.5})) + +(def profile-name-wrapper + {:padding-top 0 + :margin-top 0 + :margin-bottom 0 + :height 42 + :padding-bottom 0}) + +(defstyle profile-status-wrapper + {:padding-top 0 + :margin-bottom 0 + :height 85 + :padding-bottom 1 + :ios {:margin-top 3} + :android {:margin-top 1}}) + +(def edit-line-color + (if p/ios? + (str color-gray5 "80") + color-gray5)) + +(def profile-focus-line-color + color-light-blue) + +(def profile-focus-line-height + (get-in p/platform-specific [:component-styles :text-field-focus-line-height])) + +(defstyle profile-name-input + {:color text1-color + :ios {:font-size 17 + :padding-bottom 0 + :line-height 17 + :letter-spacing -0.2} + :android {:font-size 16 + :line-height 16 + :padding-top 5 + :height 30 + :padding-bottom 0}}) + +(defstyle profile-status-input + {:height 82 + :line-height 24;;TODO doesnt' work for multiline because bug in the RN + :android {:padding-top 0}}) + +(def edit-profile-status + {:padding-left 16 + :padding-top 35}) -(def underline-container - {:background-color separator-color - :margin-bottom 18 - :height 1 - :align-items :center}) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index d870ead6b0..8e5b1e8c20 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -68,6 +68,7 @@ ;profile :profile "Profile" + :edit-profile "Edit profile" :report-user "REPORT USER" :message "Message" :username "Username" @@ -77,6 +78,10 @@ :email "Email" :profile-no-status "No status" :add-to-contacts "Add to contacts" + :in-contacts "In contacts" + :start-conversation "Start conversation" + :send-transaction "Send transaction" + :share-qr "Share QR" :error-incorrect-name "Please select another name" :error-incorrect-email "Incorrect e-mail" diff --git a/src/status_im/utils/datetime.cljs b/src/status_im/utils/datetime.cljs index 5e96371d37..a7adffdbbc 100644 --- a/src/status_im/utils/datetime.cljs +++ b/src/status_im/utils/datetime.cljs @@ -1,5 +1,5 @@ (ns status-im.utils.datetime - (:require [cljs-time.core :as t :refer [date-time now plus days hours before?]] + (:require [cljs-time.core :as t :refer [date-time plus days hours before?]] [cljs-time.coerce :refer [from-long to-long from-date]] [cljs-time.format :refer [formatters formatter @@ -8,6 +8,9 @@ [goog.string :as gstring] goog.string.format)) +(defn now [] + (t/now)) + (def hour (* 1000 60 60)) (def day (* hour 24)) (def week (* 7 day)) From b8a491e66da151732e65ba7e3feefb8e121d6d52 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Sun, 26 Mar 2017 11:58:37 +0300 Subject: [PATCH 10/48] fix for https://github.com/status-im/status-react/issues/943 --- src/status_im/data_store/realm/contact_groups.cljs | 4 +--- src/status_im/new_group/handlers.cljs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/status_im/data_store/realm/contact_groups.cljs b/src/status_im/data_store/realm/contact_groups.cljs index bdf43f6936..07b57d5987 100644 --- a/src/status_im/data_store/realm/contact_groups.cljs +++ b/src/status_im/data_store/realm/contact_groups.cljs @@ -42,9 +42,7 @@ (defn- save-contacts [identities contacts] (doseq [contact-identity identities] - (if-let [contact (.find contacts (fn [object _ _] - (= contact-identity (aget object "identity"))))] - (.push contacts (clj->js {:identity contact-identity}))))) + (.push contacts (clj->js {:identity contact-identity})))) (defn add-contacts [group-id identities] diff --git a/src/status_im/new_group/handlers.cljs b/src/status_im/new_group/handlers.cljs index 499ca6fa21..b62e27f7e2 100644 --- a/src/status_im/new_group/handlers.cljs +++ b/src/status_im/new_group/handlers.cljs @@ -284,7 +284,7 @@ (fn [db [_ new-groups]] (-> db (update :contact-groups merge (map #(vector (:group-id %) %) new-groups)) - (assoc db :new-groups new-groups)))) + (assoc :new-groups new-groups)))) (register-handler :save-group-order (u/side-effect! @@ -317,7 +317,7 @@ (defn add-selected-contacts-to-group [{:keys [selected-contacts contact-groups contact-group-id] :as db} _] (let [new-identities (mapv #(hash-map :identity %) selected-contacts)] - (update db [:contact-groups contact-group-id :contacts] concat new-identities))) + (update-in db [:contact-groups contact-group-id :contacts] concat new-identities))) (defn add-selected-contacts-to-group! [{:keys [contact-group-id selected-contacts]} _] From 6ca2f61eb3c7424be858cca5e9e371a88585aa81 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Thu, 23 Mar 2017 17:31:22 +0300 Subject: [PATCH 11/48] fix for https://github.com/status-im/status-react/issues/934 , implemented contacts-list-modal, refactored common styles --- .../res/drawable-hdpi/icon_address_blue.png | Bin 0 -> 486 bytes .../drawable-hdpi/icon_fullscreen_blue.png | Bin 0 -> 439 bytes .../res/drawable-mdpi/icon_address_blue.png | Bin 0 -> 331 bytes .../drawable-mdpi/icon_fullscreen_blue.png | Bin 0 -> 239 bytes .../res/drawable-xhdpi/icon_address_blue.png | Bin 0 -> 515 bytes .../drawable-xhdpi/icon_fullscreen_blue.png | Bin 0 -> 452 bytes .../res/drawable-xxhdpi/icon_address_blue.png | Bin 0 -> 775 bytes .../drawable-xxhdpi/icon_fullscreen_blue.png | Bin 0 -> 736 bytes .../drawable-xxxhdpi/icon_address_blue.png | Bin 0 -> 1012 bytes .../drawable-xxxhdpi/icon_fullscreen_blue.png | Bin 0 -> 1025 bytes .../icon_address_blue.imageset/Contents.json | 21 ++++ .../icon_address_blue.png | Bin 0 -> 515 bytes .../Contents.json | 21 ++++ .../icon_fullscreen_blue.png | Bin 0 -> 452 bytes src/status_im/android/core.cljs | 3 +- src/status_im/android/platform.cljs | 5 - .../action_button/action_button.cljs | 4 +- .../components/action_button/styles.cljs | 46 +++++--- src/status_im/components/common/common.cljs | 32 +++-- src/status_im/components/common/styles.cljs | 43 ++++++- src/status_im/contacts/screen.cljs | 10 +- src/status_im/contacts/styles.cljs | 3 + src/status_im/contacts/subs.cljs | 5 + .../contacts/views/contact_list.cljs | 111 ++++-------------- .../contacts/views/contact_list_modal.cljs | 90 ++++++++++++++ src/status_im/ios/core.cljs | 3 +- src/status_im/ios/platform.cljs | 9 -- .../new_group/views/reorder_groups.cljs | 15 +-- src/status_im/profile/screen.cljs | 66 +++++------ 29 files changed, 298 insertions(+), 189 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_address_blue.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_fullscreen_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_address_blue.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_fullscreen_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_address_blue.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_fullscreen_blue.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_address_blue.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_fullscreen_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_address_blue.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_fullscreen_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_address_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_address_blue.imageset/icon_address_blue.png create mode 100644 ios/StatusIm/Images.xcassets/icon_fullscreen_blue.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_fullscreen_blue.imageset/icon_fullscreen_blue.png create mode 100644 src/status_im/contacts/views/contact_list_modal.cljs diff --git a/android/app/src/main/res/drawable-hdpi/icon_address_blue.png b/android/app/src/main/res/drawable-hdpi/icon_address_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..fb295a44f9f82105534c91bf9c6aede2411eeb53 GIT binary patch literal 486 zcmV@P)Px$ph-kQR9Fe^mCZ^6F%ZXRLZK>xiYKj}>b>AI2!i)|^B}DjE4ugwK7rWv6T709 zdJ>P)gU{d-=*cdk7Zs$^k4;Pp3uWm}v$iZA5(vp|W-`D0XLbW%no+H)p-?CHTc@8>jmGzb)M-)KBOphHdB;j!>G(&n(E?H%#s#Gf6bc0* z>+H?nMNxsWC2J_?cvhVJNQ|*%d5SN!)+uxZD`+>!b0naBA(&U^2LfQCE9iaKeBh~e z$`s7Yp?fV=S@WYZ#PhP1Dk7p}98S{$iVH>^sV`8RFnxidz~oNe7oge9B8X(KPx$aY;l$R9Fe^SHVgHF%X@k?)DG#qNmn>>8*Z)1rY>M^yb}@A_`ta{RX}DW7?Bm z^bgFkiJ9Qiy6q&xvWp;-%XTMkUS3~1nG`^VI3Nym>wu!@C%5mH&bl){pHmp6U=CS- z^mMd2L(IY5$Dl0D)By~s93MAYsjJ76?Td97y)KBcl$d~VFi?dVR~*(BdkHZJ&8>6i zRZjg$3c|!Xxc=_#ooSuDRB@N(ufeq{KtD=2eTCNs-8wN9AlaFS);>*b?x(D}24wHgD|1t(+Ke+D5>;K}{x z5c?FihKJ*=c^luG!%6;zp!k|v-#lGu4!xM&HUx1v$#ckgF(`u3z1dnhoTMQ3DlG#= zP|8qoDCH1c_Dh-6O|Ri4e~EeZV{FUJD*Sf@%ecWMA4y1VQjpT>I+lp6*u5KE^26UC h%$Fe!hy#D&z&AfYe{Rg2*9ZUr002ovPDHLkV1nI+$zA{e literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_address_blue.png b/android/app/src/main/res/drawable-mdpi/icon_address_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..d9ff193fc4e96b8594adac56938ebf7415e7ff44 GIT binary patch literal 331 zcmV-R0kr;!P)Px$1xZ9fR7eeDU>F6XAwZK5NSXY^DP_V_S85o}gw2rufB!H3_y6Cnl!;HXvB{Gn zhSdTF2F50kA^-mUn?k82SS^@aATyJZkqPX2N-bf;=iTH9PqY62|2Gw+hKY$OXHLE} zn2k>lx*T2$K#G$lJgH*%|G$-ik?}tZBa_0ce5pt1hT!944I-F^lnF1zfi8#v@qzSZ z1`f&RFgaproECr#|IhGy|NsC0H5nNhFEMj6InPRG{7tOEFm+gi2)p4@Z(y28p;@pg z2D*Gbs>>0ECr@~?6)5M0u8)y{aqHYd86R|U>_PPZ|0|%vgOFfB7>=$Pg%7j=g+Iy} d4S}H(0s!8`U1PhzgsuPp002ovPDHLkV1lBYjW_@R literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_fullscreen_blue.png b/android/app/src/main/res/drawable-mdpi/icon_fullscreen_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..869831b52c8700720c2a895eaa7eb44fc6fb566c GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|R(iTPhIsHM zCrGd|%QE%6;PaUGA?5Y||Nr-1I4UVAx&5r}gpX{U!i(9K&F4JUaPbBY`{}>wKlp>2 zyN@lK&N}^3W$Px1ea$Odf3h57zv%h5f1?${VfGWVRveW3C6;i6QDf@_VUs7Xl#j1t zyvBUW<>X)gZ4+Mc#QZXN#1NgPc+4o~S6iLY(w+Q3zSzANsoaK3HGTArdLJ^+k!Px$y-7qtRA>e5m%&cLKoEv!79PS-d<$Q|qh7p;iN*_{C#*aPa6}+pG-_g^p1k-H zCf@W0JO$Em2h*kpq0^GpHJK)a&33x|zc0Jn7C;X*pa#@{8c+jjKnEIlmh^mVpM)&pJ^gw#8%Q`Ut5l|9@sANH|e1H%G7=tZ9 zocjhL1{j9HlL0*R4MMz#WAlyfv=#wfgPlfkA44JH(I^aVlfGYSU@_Y{4={{HOwE-I4$+3OJ zHPZnRVMeC>lJ0ZWUJHQ3+b8s;HJ*&a;SH8*qj2NRRp|7%h1bBU@Pn}OkiLn_b|C;? z!n2s%06vA!4d7e&Tma49WIu}F=BEX_YR)%$<6R=`^LGT_Fzc}IR1-sVGH7o;XVvog zWcSD_j)*#W!}FMV!hhFOHTm+(3T4lW0f2B8j~8#1tIWr>uK(o#2I_Xjf7n;&cSEoz z4bRhor-c-RYZ2*GTCa6#Kn3skI literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_fullscreen_blue.png b/android/app/src/main/res/drawable-xhdpi/icon_fullscreen_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..16c489791f303f9354c2dc7ae2e4ae9205b1e9e2 GIT binary patch literal 452 zcmV;#0XzPQP)Px$en~_@RA>e5SW#}mFbu63$Djv-V;}~f6DL9YWK288cA#<&JXtN0<&n5)q71}C zLUNqO&wfrDJ57Th7ytuc01P}c1LOt&dgzuHq7P*uG~nK5rq z`}RlMvGU9+>^Q}FSu24u)3Jmd!M1kn*bQJT^V%?T!+Jbb9)s-$kP0qa=%wMET_@X0 z=Bz$fHdwbVb%^sk_lJ*lqyV4#_$h u8VhKNyHT+t*dZL~!2lQl17H9Q2m`-)>ZcR3wbPXV0000U^?jO;uuoF z`1aQRY!OEh_7CRO&mTr=c1+m2*WQt*qgLmLUc^!Pj;WrH`L8*N^c1=39C?=0GC|&V zjT47dfXTHoGcmKMSvf4+2cLy(vOeb^rgw7PnV)GpN`L6dl$#sBzq{xB*|+Bk-CLNM z1R5Av6c`ve92n4SI&HYeTRUG^w(pzE@vO#S5zFPIgi!k=3T3)m%dqf zTCM30^0=QGuzN#=am@OliF0? znf|?a>UP=P)uCaFZ|&S^QL}mVU;BzAR*&m1wI`V>#7|tq^s^&H_Jp~Lx`UmfCG#iN zlbRC*g#y=?IrN;1?YDdRG1NLj+I4c$v&YwN@6S`~oE7P{(Q{p5Pa)ruZmwC6<|=&L zxW&QK-TQajorf|RS!R|~zHOQwbZYX_tzI8@ZOK0&>v!I<)*|_7Y1h=&9j1yc6P_lw zT@Nn*dP&WKD|Kt_qSB44EN&e;$tA_`yyp3q8)aYBZl1`NJ)ti1TKj~#%xVX_M-j}Q zM2~Y#IB$`&Ao}#CpUO9DmYOvtTSZ>nSgdKjFRFA}YO?ap8G-vZ#)e5Rp15d^TJ9_N zGcIo*PQR7-V}Y?^-RvVGy@_v|Mb0_Twy0{7QlDJ1J7ZJx7R?6}GFVdQ&MBb@0L;Nv3;+NC literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_fullscreen_blue.png b/android/app/src/main/res/drawable-xxhdpi/icon_fullscreen_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..7ba051da597b5f91f9cf4f50206f31286371f880 GIT binary patch literal 736 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-HD>V4CIW;uuoF z_;$9h-(drR*0&sm>`YH1)@X3&9ca458&GG~!D^mx@tuWO?qS)8D?QFpu3c|WN|p}}-d0yyGpBlU)?8&8K3Dte96*g1v z8s0kE;KY=a~GeDFGU*)SM9e@&bp<4vGAwa_xN2*{(Dm=I3%xkX6!h~@4#?GAmPjj1%@OJgR~R@ z216DJV4OSgSeT_UT-_FvVl}kKB9f zUe}4WUhE1Js~6vLs`P2wfqB;dy3frsRI~vH-GMma1?lQH1E)1l?^d5>x@6VVjj7Vn zGbc%32<-c2xFHfbHJuGY&_{*h+NQ~f?pHd%V6(mBh; zbNfT(LU*mXMGk$kvQs=R?zRyszPY0~v*>HCT7^`SgPeW!ZC-~n?%eo%bA&-?|JmPv zJioJqnXd9HyY<^-`%8be6}}sO&3JXxaL46&r@Z;U=<}b8{ZSf!JLml&)n|8oBBZt2>$Ui(`2_c6#q}WK&FDZv9qyOE=@qN$c(^%74zh;&}6C?AtBz p$2Z-2Ep>s7QGfvz-SB0yKX~@o%6OTe1;8ZB;OXk;vd$@?2>@OTL5TnW literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_address_blue.png b/android/app/src/main/res/drawable-xxxhdpi/icon_address_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..e3298dc9b5f7cb1555f3c143fc9429f703e7767b GIT binary patch literal 1012 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>U|#3x;uuoF z`1ZE1zp$eO`-jRh@r7M0T!aH`D%6XN<6IVhd|Q0u$cjd33HzpkW{$QM;d@`ZE_Ta1 zCSCP``9wF{v1LYQ1;d|ZpRB^1_lmX%tn6SHV6&a<@~S$dIhRo}B;^Qmg-KaT zXyrjsJK?%pZx%lnY!Z@h3oBfIcFo+NrBk34URx>{jj_rve!LDhGhoyG1^tDQsc?YNyK z`!>ezGXsxbx8e=`A6qtWS(=+G*pMk5xN~}aY2+wWSuF+1!& zn0{PQ6r!*>F+(&yd$0M$?vKp&J2n`YeNfz(bB-%Th~Y!_UX`y54e^J~y;rg^{IRH8 z#mG=^U6;kku-~pui;>}e-+LQ|2j<7hr5HX;{y3L4;lu2Cw*`MpDE)lz)W=@?s;>Pl z2B(6rxzD!#^33a_X-DY3-T4#W-lAT}X*+2ZIX6DRe zA7gZ#OX&4&N5-~aZg#yM?Fx3XveUeRGapL(zx#Q4-A7;B8nG|4^Z(CCJ=tEtP;+XY zXU+nL^Zlf29cYWFzXu~k?PDQ3|iTDqf?rXo6 zm|LvywrQxHSAV-lW}BS#{?4^KX9TJF`_3>wvG%Ly`q|b-yLM*;RqcPoc&3kk-FKFf zNj9^dYe&fc|9fWT-`c}^&pw}BaiquZ$C>IF{U39iX4ZZ(w0ZgNliRaA+230(|9$wC i$b5jFXXa{u5HBrXTA`SFiwBsE89ZJ6T-G@yGywqng1SHe literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_fullscreen_blue.png b/android/app/src/main/res/drawable-xxxhdpi/icon_fullscreen_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..c2097efc2bf45f2cbecbb7f67f574ed8bed0ee2f GIT binary patch literal 1025 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>VBYQN;uuoF z_;$|eyekGGZErg=UkDv!+gjW9iRD1@6y2nQu1-l8?N~OiXgQMF7*SN&{g8J?dIq<& zfVYI!(H|;H=5os2Ha@;_?nV0`Q{meu>(71fpX?(W&9TRUfdxM@o7=!M@xkHi_sjpC zsq0-TR6bR}+*xL`Z5!W**%Lk$TTXIcKkv<)El;<7m-u+XNoHT|uIjAr!^`_}4>XG} z-yN#Dk7Mb&-yG|1yLo-wEF=0`Pgv^5{^hmD7w;Fb-*#&C?|iwt7SZPFx7I&+_hUTtJ0G8#^eN%!`+09&t<|?X{@)#H zo3Y*U{r7(VJJ)5~9KP8$OuVg7*2>tK+r(&~VAy!%(+i?$XY&JQFA`UK&)L3xk1l)k z-1Q8**)=rPypOV(*=3(v{Ql1kww$TA+rLZ*GXL?+QR}75;kWOm-!8lVb0hBp^}`u^ z!kFvV|KAt1{mSEw^0o7lPV;WloacM~{1oF;Xi@k}bwR!P$N2vEd2g?74$ok6{mk>f zWnRiNzxxl}#h!80K09ufQG_`Mi9e zODh)@yW=Nv?p_esxtVvvxrLt^cSX(a++2C4GLv!34K|V1dF*L3l%KI|&1$}LjrZ!u z3tX>OFT0p~-mGC-fj(DZ_p{d47nANX%)Wi0<{IzZe)S`tzTU0b$jhX_fER73WckOm YV5)=?%k7!7fO(q1)78&qol`;+0N%~N;Q#;t literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_address_blue.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_address_blue.imageset/Contents.json new file mode 100644 index 0000000000..4f72e1ec01 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_address_blue.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_address_blue.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_address_blue.imageset/icon_address_blue.png b/ios/StatusIm/Images.xcassets/icon_address_blue.imageset/icon_address_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..919ae15fbb75bb7820bb24a7a848cb263e038b01 GIT binary patch literal 515 zcmV+e0{s1nP)Px$y-7qtRA>e5m%&cLKoEv!79PS-d<$Q|qh7p;iN*_{C#*aPa6}+pG-_g^p1k-H zCf@W0JO$Em2h*kpq0^GpHJK)a&33x|zc0Jn7C;X*pa#@{8c+jjKnEIlmh^mVpM)&pJ^gw#8%Q`Ut5l|9@sANH|e1H%G7=tZ9 zocjhL1{j9HlL0*R4MMz#WAlyfv=#wfgPlfkA44JH(I^aVlfGYSU@_Y{4={{HOwE-I4$+3OJ zHPZnRVMeC>lJ0ZWUJHQ3+b8s;HJ*&a;SH8*qj2NRRp|7%h1bBU@Pn}OkiLn_b|C;? z!n2s%06vA!4d7e&Tma49WIu}F=BEX_YR)%$<6R=`^LGT_Fzc}IR1-sVGH7o;XVvog zWcSD_j)*#W!}FMV!hhFOHTm+(3T4lW0f2B8j~8#1tIWr>uK(o#2I_Xjf7n;&cSEoz z4bRhor-c-RYZ2*GTCa6#Kn3skI literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_fullscreen_blue.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_fullscreen_blue.imageset/Contents.json new file mode 100644 index 0000000000..d01c848281 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_fullscreen_blue.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_fullscreen_blue.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_fullscreen_blue.imageset/icon_fullscreen_blue.png b/ios/StatusIm/Images.xcassets/icon_fullscreen_blue.imageset/icon_fullscreen_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..16c489791f303f9354c2dc7ae2e4ae9205b1e9e2 GIT binary patch literal 452 zcmV;#0XzPQP)Px$en~_@RA>e5SW#}mFbu63$Djv-V;}~f6DL9YWK288cA#<&JXtN0<&n5)q71}C zLUNqO&wfrDJ57Th7ytuc01P}c1LOt&dgzuHq7P*uG~nK5rq z`}RlMvGU9+>^Q}FSu24u)3Jmd!M1kn*bQJT^V%?T!+Jbb9)s-$kP0qa=%wMET_@X0 z=Bz$fHdwbVb%^sk_lJ*lqyV4#_$h u8VhKNyHT+t*dZL~!2lQl17H9Q2m`-)>ZcR3wbPXV0000 Date: Wed, 22 Mar 2017 01:44:08 -0300 Subject: [PATCH 12/48] fixed share dialog everywhere on iOS --- src/status_im/android/platform.cljs | 2 +- src/status_im/components/context_menu.cljs | 12 +++++------- src/status_im/components/list_selection.cljs | 2 +- src/status_im/ios/platform.cljs | 7 +++++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index f689de4d2e..3ca9148958 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -167,7 +167,7 @@ (defn show-dialog [{:keys [title options callback]}] (let [dialog (new react-native-dialogs)] (.set dialog (clj->js {:title title - :items options + :items (mapv :text options) :itemsCallback callback})) (.show dialog))) diff --git a/src/status_im/components/context_menu.cljs b/src/status_im/components/context_menu.cljs index 6d59ec78cb..f962548747 100644 --- a/src/status_im/components/context_menu.cljs +++ b/src/status_im/components/context_menu.cljs @@ -27,13 +27,11 @@ (def list-selection-fn (:list-selection-fn platform-specific)) (defn open-ios-menu [options] - (let [cancel-option {:text (label :t/cancel)} - options (conj options cancel-option)] - (list-selection-fn {:options options - :callback (fn [index] - (when (< index (count options)) - (when-let [handler (:value (nth options index))] - (handler))))})) + (list-selection-fn {:options options + :callback (fn [index] + (when (< index (count options)) + (when-let [handler (:value (nth options index))] + (handler))))}) nil) (defn context-menu [trigger options] diff --git a/src/status_im/components/list_selection.cljs b/src/status_im/components/list_selection.cljs index ea9c139cbd..299f4f83a9 100644 --- a/src/status_im/components/list_selection.cljs +++ b/src/status_im/components/list_selection.cljs @@ -17,7 +17,7 @@ (defn share [text dialog-title] (let [list-selection-fn (:list-selection-fn platform-specific)] (list-selection-fn {:title dialog-title - :options [(label :t/sharing-copy-to-clipboard) (label :t/sharing-share)] + :options (share-options text) :callback (fn [index] (case index 0 (copy-to-clipboard text) diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 493f639580..8f49736a73 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -1,5 +1,6 @@ (ns status-im.ios.platform (:require [status-im.components.styles :as styles] + [status-im.i18n :refer [label]] [status-im.utils.utils :as utils])) (def component-styles @@ -194,9 +195,11 @@ (def react-native (js/require "react-native")) (defn action-sheet-options [options] - (let [destructive-opt-index (utils/first-index :destructive? options)] + (let [destructive-opt-index (utils/first-index :destructive? options) + cancel-option {:text (label :t/cancel)} + options (conj options cancel-option)] (clj->js (merge {:options (mapv :text options) - :cancelButtonIndex (count options)} + :cancelButtonIndex (dec (count options))} (when destructive-opt-index {:destructiveButtonIndex destructive-opt-index}))))) (defn show-action-sheet [{:keys [options callback]}] From a116600679fe75d389bff4997b03226a0bb3f17f Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Tue, 21 Mar 2017 21:51:41 -0300 Subject: [PATCH 13/48] using KeyboardAvoidingView to fix the issue --- src/status_im/components/react.cljs | 1 + src/status_im/new_group/screen_private.cljs | 22 +++++++++++-------- .../new_group/views/chat_group_settings.cljs | 5 ++++- .../new_group/views/contact_toggle_list.cljs | 11 +++++++--- src/status_im/profile/edit/screen.cljs | 5 ++++- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index c7ec58bc17..cef7e03e7e 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -30,6 +30,7 @@ (def list-view-class (get-class "ListView")) (def scroll-view (get-class "ScrollView")) (def web-view (get-class "WebView")) +(def keyboard-avoiding-view (get-class "KeyboardAvoidingView")) (def text-class (get-class "Text")) (def text-input-class (get-class "TextInput")) diff --git a/src/status_im/new_group/screen_private.cljs b/src/status_im/new_group/screen_private.cljs index 76e9fef227..9f13d72832 100644 --- a/src/status_im/new_group/screen_private.cljs +++ b/src/status_im/new_group/screen_private.cljs @@ -4,6 +4,7 @@ [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.react :refer [view scroll-view + keyboard-avoiding-view list-view list-item]] [status-im.components.confirm-button :refer [confirm-button]] @@ -18,6 +19,7 @@ separator]] [status-im.new-group.validations :as v] [status-im.i18n :refer [label]] + [status-im.utils.platform :refer [ios?]] [cljs.spec :as s])) (def contacts-limit 3) @@ -55,16 +57,17 @@ type [:get :group-type]] (let [save-btn-enabled? (and (s/valid? ::v/name group-name) (not= group-name (:name group)))] - [view st/group-container + [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} + st/group-container) [group-toolbar type true] [group-name-view] - [add-btn #(dispatch [:navigate-to :add-contacts-toggle-list])] - [group-contacts-view group] - [view st/separator] - [delete-btn #(do - (dispatch [:delete-group]) - (dispatch [:navigate-to-clean :contact-list]))] - [view {:flex 1}] + [view {:flex 1} + [add-btn #(dispatch [:navigate-to :add-contacts-toggle-list])] + [group-contacts-view group] + [view st/separator] + [delete-btn #(do + (dispatch [:delete-group]) + (dispatch [:navigate-to-clean :contact-list]))]] (when save-btn-enabled? [confirm-button (label :t/save) save])])) @@ -83,7 +86,8 @@ group-name [:get :new-chat-name] group-type [:get :group-type]] (let [save-btn-enabled? (and (s/valid? ::v/name group-name) (pos? (count contacts)))] - [view st/group-container + [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} + st/group-container) [group-toolbar group-type false] [group-name-view] [view {:flex 1} diff --git a/src/status_im/new_group/views/chat_group_settings.cljs b/src/status_im/new_group/views/chat_group_settings.cljs index f801fd1a2f..1c5b304393 100644 --- a/src/status_im/new_group/views/chat_group_settings.cljs +++ b/src/status_im/new_group/views/chat_group_settings.cljs @@ -4,6 +4,7 @@ [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.react :refer [view scroll-view + keyboard-avoiding-view icon touchable-highlight]] [status-im.components.confirm-button :refer [confirm-button]] @@ -17,6 +18,7 @@ separator]] [status-im.new-group.validations :as v] [status-im.i18n :refer [label]] + [status-im.utils.platform :refer [ios?]] [cljs.spec :as s])) (def contacts-limit 3) @@ -65,7 +67,8 @@ type [:get :group-type]] (let [save-btn-enabled? (and (s/valid? ::v/name new-chat-name) (not= new-chat-name chat-name))] - [view st/group-container + [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} + st/group-container) [view {:flex 1} [group-toolbar type true] [scroll-view diff --git a/src/status_im/new_group/views/contact_toggle_list.cljs b/src/status_im/new_group/views/contact_toggle_list.cljs index 5e549fb404..b3fbdc9345 100644 --- a/src/status_im/new_group/views/contact_toggle_list.cljs +++ b/src/status_im/new_group/views/contact_toggle_list.cljs @@ -3,6 +3,7 @@ (:require [re-frame.core :refer [dispatch]] [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.react :refer [view + keyboard-avoiding-view text list-view list-item]] @@ -10,6 +11,7 @@ [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search]] [status-im.utils.listview :refer [to-datasource]] + [status-im.utils.platform :refer [ios?]] [status-im.new-group.views.toggle-contact :refer [group-toggle-contact group-toggle-participant]] [status-im.components.common.common :refer [separator]] @@ -50,7 +52,8 @@ [contacts [:all-added-group-contacts-filtered] selected-contacts-count [:selected-contacts-count] group-type [:get :group-type]] - [view st/group-container + [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} + st/group-container) [status-bar] [toggle-list-toolbar (label (if (= group-type :contact-group) @@ -74,7 +77,8 @@ [contacts [:all-group-not-added-contacts-filtered] group [:get-contact-group] selected-contacts-count [:selected-contacts-count]] - [view st/group-container + [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} + st/group-container) [status-bar] [toggle-list-toolbar (:name group) selected-contacts-count] [view {:flex 1} @@ -96,7 +100,8 @@ [contacts [:contacts-filtered :all-new-contacts] chat-name [:chat :name] selected-contacts-count [:selected-participants-count]] - [view st/group-container + [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} + st/group-container) [status-bar] [toggle-list-toolbar chat-name selected-contacts-count] [view {:flex 1} diff --git a/src/status_im/profile/edit/screen.cljs b/src/status_im/profile/edit/screen.cljs index c5aa2a2f13..fe4aa60f45 100644 --- a/src/status_im/profile/edit/screen.cljs +++ b/src/status_im/profile/edit/screen.cljs @@ -14,9 +14,11 @@ [status-im.profile.validations :as v] [status-im.components.react :refer [view scroll-view + keyboard-avoiding-view text touchable-highlight text-input]] + [status-im.utils.platform :refer [ios?]] [cljs.spec :as s])) (defn edit-my-profile-toolbartoolbar [] @@ -77,7 +79,8 @@ profile-edit-data-changed? (or (not= (:name current-account) (:name changed-account)) (not= (:status current-account) (:status changed-account)) (not= (:photo-path current-account) (:photo-path changed-account)))] - [view st/profile + [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} + st/profile) [status-bar] [edit-my-profile-toolbartoolbar] [view {:flex 1} From 514f6a6be15690b57e49563ab8f6ef894d10b0f7 Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Mon, 20 Mar 2017 18:50:19 -0300 Subject: [PATCH 14/48] chats list UI fixes --- src/status_im/chats_list/screen.cljs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index 04cfb0d692..45ede3f8a3 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -53,9 +53,11 @@ [toolbar {:nav-action (act/back #(dispatch [:set-in [:chat-list-ui-props :edit?] false])) :title (label :t/edit-chats)}]) -(defn toolbar-search [] +(defview toolbar-search [] + [search-text [:get-in [:toolbar-search :text]]] [toolbar-with-search {:show-search? true + :search-text search-text :search-key :chat-list :title (label :t/chats) :search-placeholder (label :t/search-for)}]) From a543cdfa264bb68c55a18d207d4eabcb88c845a3 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Mon, 20 Mar 2017 18:12:40 +0300 Subject: [PATCH 15/48] fixes for https://github.com/status-im/status-react/issues/911 and https://github.com/status-im/status-react/issues/834 --- src/status_im/android/platform.cljs | 2 +- src/status_im/components/context_menu.cljs | 4 +- src/status_im/components/styles.cljs | 24 ++--- .../components/toolbar_new/styles.cljs | 25 +++--- .../components/toolbar_new/view.cljs | 18 ++-- src/status_im/contacts/screen.cljs | 6 +- src/status_im/contacts/styles.cljs | 3 - src/status_im/contacts/views/contact.cljs | 5 +- .../contacts/views/contact_list.cljs | 5 +- src/status_im/ios/platform.cljs | 6 +- src/status_im/profile/edit/screen.cljs | 3 +- src/status_im/profile/screen.cljs | 89 ++++++++++++------- src/status_im/profile/styles.cljs | 15 +++- 13 files changed, 126 insertions(+), 79 deletions(-) diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 3ca9148958..83b170f919 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -19,7 +19,7 @@ :bar-style "light-content" :color styles/color-black}} :toolbar-new {:height 55 - :padding-top 18 + :padding-top 15 :padding-left 16 :padding-right 16} :toolbar-title-container {:padding-left 30} diff --git a/src/status_im/components/context_menu.cljs b/src/status_im/components/context_menu.cljs index f962548747..aea5ccbf64 100644 --- a/src/status_im/components/context_menu.cljs +++ b/src/status_im/components/context_menu.cljs @@ -34,7 +34,7 @@ (handler))))}) nil) -(defn context-menu [trigger options] +(defn context-menu [trigger options & [customStyles]] (if ios? [touchable-highlight {:on-press #(open-ios-menu options)} @@ -42,7 +42,7 @@ trigger]] [menu {:onSelect #(when % (do (%) nil))} [menu-trigger trigger] - [menu-options st/context-menu-options + [menu-options (st/context-menu-options customStyles) (for [{:keys [style value destructive?] :as option} options] ^{:key option} [menu-option {:value value} diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 861a304d78..84844787bb 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -98,16 +98,20 @@ :align-items :center :background-color color-light-blue}) -(def context-menu-options - {:customStyles {:optionsContainer {:elevation 2 - :margin-top 30 - :padding-top 8 - :width 164 - :padding-bottom 8} - :optionWrapper {:padding-left 16 - :padding-right 16 - :justify-content :center - :height 48}}}) +(defn context-menu-options [custom-styles] + {:customStyles {:optionsContainer + (merge {:elevation 2 + :margin-top 30 + :padding-top 8 + :width 164 + :padding-bottom 8} + (:optionsContainer custom-styles)) + :optionWrapper + (merge {:padding-left 16 + :padding-right 16 + :justify-content :center + :height 48} + (:optionWrapper custom-styles))}}) (defn context-menu-text [destructive?] {:font-size 15 diff --git a/src/status_im/components/toolbar_new/styles.cljs b/src/status_im/components/toolbar_new/styles.cljs index c5a46bb26c..ebff89fd22 100644 --- a/src/status_im/components/toolbar_new/styles.cljs +++ b/src/status_im/components/toolbar_new/styles.cljs @@ -1,9 +1,10 @@ (ns status-im.components.toolbar-new.styles - (:require-macros [status-im.utils.styles :refer [defnstyle]]) + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) (:require [status-im.components.styles :refer [text1-color color-white color-light-gray color-gray5 + color-gray4 color-blue color-black]] [status-im.utils.platform :as p])) @@ -37,10 +38,11 @@ {:flex 1 :align-self :stretch})) -(def toolbar-title-text +(defstyle toolbar-title-text {:color text1-color :letter-spacing -0.2 - :font-size 17}) + :font-size 17 + :ios {:padding-top 2}}) (def toolbar-border-container (get-in p/platform-specific [:component-styles :toolbar-border-container])) @@ -68,13 +70,16 @@ {:flex 1})) (def toolbar-search-input - (merge (get-in p/platform-specific [:component-styles :toolbar-search-input]) - {:flex 1 - :padding-bottom 10 - :font-size 17 - :padding-top 0 - :align-self :stretch - :color color-black})) + (merge {:line-height 24 + :height 24 + :font-size 17 + :padding-top 0 + :padding-left 0 + :padding-bottom 0 + :text-align-vertical :center + :color color-black} + (get-in p/platform-specific [:component-styles :toolbar-search-input]))) + (def action-default {:width 24 diff --git a/src/status_im/components/toolbar_new/view.cljs b/src/status_im/components/toolbar_new/view.cljs index 7e63af229c..400af551aa 100644 --- a/src/status_im/components/toolbar_new/view.cljs +++ b/src/status_im/components/toolbar_new/view.cljs @@ -8,7 +8,8 @@ touchable-highlight]] [status-im.components.sync-state.gradient :refer [sync-state-gradient-view]] [status-im.components.styles :refer [icon-default - icon-search]] + icon-search + color-gray4]] [status-im.components.context-menu :refer [context-menu]] [status-im.components.toolbar-new.actions :as act] [status-im.components.toolbar-new.styles :as st] @@ -83,13 +84,14 @@ [view st/toolbar-with-search-content (if show-search? [text-input - {:style st/toolbar-search-input - :ref #(reset! search-text-input %) - :auto-focus true - :placeholder search-placeholder - :on-change-text #(dispatch [:set-in [:toolbar-search :text] %]) - :on-submit-editing (when on-search-submit - #(toolbar-search-submit on-search-submit))}] + {:style st/toolbar-search-input + :ref #(reset! search-text-input %) + :auto-focus true + :placeholder search-placeholder + :placeholder-text-color color-gray4 + :on-change-text #(dispatch [:set-in [:toolbar-search :text] %]) + :on-submit-editing (when on-search-submit + #(toolbar-search-submit on-search-submit))}] (or custom-title [view [text {:style st/toolbar-title-text diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index eb19e92e86..8fc899fc4b 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -92,9 +92,9 @@ :extended? edit? :on-click (when-not edit? click-handler) :extend-options (when group - [{:value #(dispatch [:hide-contact contact]) - :text (label :t/delete-contact) - :style st/delete-contact-text} + [{:value #(dispatch [:hide-contact contact]) + :text (label :t/delete-contact) + :destructive? true} {:value #(dispatch [:remove-contact-from-group (:whisper-identity contact) (:group-id group)]) diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index 4dc1c71658..09a6549d43 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -193,6 +193,3 @@ :background-color color-white :align-items :center :justify-content :center}) - -(def delete-contact-text - {:color color-light-red}) diff --git a/src/status_im/contacts/views/contact.cljs b/src/status_im/contacts/views/contact.cljs index 7f319d9129..13ddbe267b 100644 --- a/src/status_im/contacts/views/contact.cljs +++ b/src/status_im/contacts/views/contact.cljs @@ -18,8 +18,9 @@ [text {:style st/letter-text} letter])]) (defn options-btn [contact more-options] - (let [options [{:value #(dispatch [:hide-contact contact]) :text (label :t/delete-contact) - :style st/delete-contact-text}]] + (let [options [{:value #(dispatch [:hide-contact contact]) + :text (label :t/delete-contact) + :destructive? true}]] [view st/more-btn [context-menu [icon :options_gray] diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index 78bad154e6..9883d5b500 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -28,8 +28,9 @@ [contact-view {:contact row :extended? edit? :extend-options (when group - [{:value #(dispatch [:hide-contact row]) - :text (label :t/delete-contact)} + [{:value #(dispatch [:hide-contact row]) + :text (label :t/delete-contact) + :destructive? true} {:value #(dispatch [:remove-contact-from-group (:whisper-identity row) (:group-id group)]) diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 8f49736a73..6de4eb77c5 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -19,7 +19,7 @@ :toolbar {:border-bottom-color styles/color-gray3 :border-bottom-width 0.5} :toolbar-new {:height 56 - :padding-top 20 + :padding-top 18 :padding-left 16 :padding-right 16} :toolbar-title-container {:align-items :center} @@ -167,7 +167,9 @@ :bottom-gradient {:height 1} :input-label {:left 0} :input-error-text {:margin-left 0} - :toolbar-search-input {:padding-left 10} + :toolbar-search-input {:padding-left 8 + :padding-top 2 + :letter-spacing -0.2} :toolbar-nav-action {:width 46 :height 56 :align-items :center diff --git a/src/status_im/profile/edit/screen.cljs b/src/status_im/profile/edit/screen.cljs index fe4aa60f45..5e1c242cfe 100644 --- a/src/status_im/profile/edit/screen.cljs +++ b/src/status_im/profile/edit/screen.cljs @@ -48,7 +48,8 @@ [context-menu [my-profile-icon {:account contact :edit? true}] - profile-icon-options]] + profile-icon-options + st/context-menu-custom-styles]] [view st/edit-profile-name-container [text {:style st/edit-name-title} (label :t/name)] diff --git a/src/status_im/profile/screen.cljs b/src/status_im/profile/screen.cljs index 12d3bfd11b..7a44d65171 100644 --- a/src/status_im/profile/screen.cljs +++ b/src/status_im/profile/screen.cljs @@ -80,15 +80,17 @@ :arrow_right_blue #(dispatch [:open-chat-with-the-send-transaction chat-id])]]) -(defn profile-info-item [label value options text-mode] +(defn profile-info-item [{:keys [label value options text-mode empty-value?]}] [view st/profile-setting-item - [view st/profile-setting-text-container + [view (st/profile-setting-text-container options) [text {:style st/profile-setting-title} label] [view st/profile-setting-spacing] - [text {:style st/profile-setting-text - :numberOfLines 1 - :ellipsizeMode text-mode} + [text {:style (if empty-value? + st/profile-setting-text-empty + st/profile-setting-text) + :number-of-lines 1 + :ellipsizeMode text-mode} value]] (when options [context-menu @@ -101,23 +103,23 @@ (defn profile-info-address-item [{:keys [address] :as contact}] [profile-info-item - (label :t/address) - address - (into [] - (concat [{:value (show-qr contact :address) - :text (label :t/show-qr)}] - (share-options address))) - :middle]) + {:label (label :t/address) + :value address + :options (into [] + (concat [{:value (show-qr contact :address) + :text (label :t/show-qr)}] + (share-options address))) + :text-mode :middle}]) (defn profile-info-public-key-item [public-key contact] [profile-info-item - (label :t/public-key) - public-key - (into [] - (concat [{:value (show-qr contact :public-key) - :text (label :t/show-qr)}] - (share-options public-key))) - :middle]) + {:label (label :t/public-key) + :value public-key + :options (into [] + (concat [{:value (show-qr contact :public-key) + :text (label :t/show-qr)}] + (share-options public-key))) + :text-mode :middle}]) (defn info-item-separator [] [separator st/info-item-separator]) @@ -135,25 +137,44 @@ ^{:key (str "item-" i)} (str status " ")))) +(defn profile-info-status-item [status & [options]] + (let [status-empty? (= "" status) + status-text (if status-empty? + (label :t/profile-no-status) + (colorize-status-hashtags status))] + [profile-info-item {:label (label :t/status) + :value status-text + :options options + :empty-value? status-empty?}])) + +(defn profile-info-phone-item [phone & [options]] + (let [phone-empty? (or (nil? phone) (= "" phone)) + phone-text (if phone-empty? + (label :t/not-specified) + phone)] + [profile-info-item {:label (label :t/phone-number) + :value phone-text + :options options + :empty-value? phone-empty?}])) + (defn profile-info [{:keys [whisper-identity :whisper-identity status :status phone :phone] :as contact}] - [view - [profile-info-item (label :t/status) (colorize-status-hashtags status)] - [info-item-separator] - [profile-info-address-item contact] - [info-item-separator] - [profile-info-public-key-item whisper-identity contact] - [info-item-separator] - [profile-info-item (label :t/phone-number) phone]]) + [view + [profile-info-status-item status] + [info-item-separator] + [profile-info-address-item contact] + [info-item-separator] + [profile-info-public-key-item whisper-identity contact] + [info-item-separator] + [profile-info-phone-item phone]]) (defn my-profile-info [{:keys [public-key :public-key status :status phone :phone] :as contact}] - [view - [profile-info-item - (label :t/status) - (colorize-status-hashtags status) + [view st/my-profile-info-container + [profile-info-status-item + status [{:value #(dispatch [:open-edit-my-profile]) :text (label :t/edit)}]] [info-item-separator] @@ -161,8 +182,10 @@ [info-item-separator] [profile-info-public-key-item public-key contact] [info-item-separator] - [profile-info-item (label :t/phone-number) phone [{:value #(dispatch [:phone-number-change-requested]) - :text (label :t/edit)}]]]) + [profile-info-phone-item + phone + [{:value #(dispatch [:phone-number-change-requested]) + :text (label :t/edit)}]]]) (defview my-profile [] [current-account [:get-current-account]] diff --git a/src/status_im/profile/styles.cljs b/src/status_im/profile/styles.cljs index 14a5754e95..8f3cf36a00 100644 --- a/src/status_im/profile/styles.cljs +++ b/src/status_im/profile/styles.cljs @@ -38,6 +38,10 @@ {:android {:padding-top 8 :padding-bottom 8}}) +(defstyle my-profile-info-container + {:android {:padding-top 8 + :padding-bottom 8}}) + (def profile-bage (merge (ps-profile :profile-bage) {:align-items :center})) @@ -48,6 +52,9 @@ :padding-left 24 :padding-top 25}) +(def context-menu-custom-styles + {:optionsContainer {:margin-top 78}}) + (def profile-name-container {:margin-top 12}) @@ -80,9 +87,9 @@ {:flex-direction :row :align-items :center})) -(def profile-setting-text-container +(defn profile-setting-text-container [options] {:flex 1 - :padding-right 20}) + :padding-right (if options 16 40)}) (def profile-setting-title (merge (ps-profile :profile-setting-title) @@ -91,6 +98,10 @@ (def profile-setting-text (ps-profile :profile-setting-text)) +(def profile-setting-text-empty + (merge profile-setting-text + {:color color-gray4})) + (def profile-setting-spacing (ps-profile :profile-setting-spacing)) From b13fa61a14e9528845a9cc2ea6e95ce39507fc0b Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Wed, 22 Mar 2017 16:23:32 +0300 Subject: [PATCH 16/48] fix for https://github.com/status-im/status-react/issues/912 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updated icon ok small can’t reproduce, but i think this change should fix it fixed chat list inner item styles --- .../main/res/drawable-hdpi/icon_ok_small.png | Bin 272 -> 404 bytes .../main/res/drawable-mdpi/icon_ok_small.png | Bin 234 -> 307 bytes .../main/res/drawable-xhdpi/icon_ok_small.png | Bin 343 -> 526 bytes .../main/res/drawable-xxhdpi/icon_ok_small.png | Bin 470 -> 645 bytes .../res/drawable-xxxhdpi/icon_ok_small.png | Bin 567 -> 845 bytes .../icon_ok_small.imageset/icon_ok_small.png | Bin 470 -> 526 bytes src/status_im/chat/views/message.cljs | 4 ++-- src/status_im/chats_list/styles.cljs | 17 +++++++++++------ src/status_im/chats_list/views/inner_item.cljs | 12 +++++++----- 9 files changed, 20 insertions(+), 13 deletions(-) diff --git a/android/app/src/main/res/drawable-hdpi/icon_ok_small.png b/android/app/src/main/res/drawable-hdpi/icon_ok_small.png index 6475aebf6a487334b9ed69679ccdfeb00bd7c160..9ff5646336c5434bbd7b3432cf0af5af91795790 100644 GIT binary patch literal 404 zcmV;F0c-w=P)Px$PDw;TR7eeDU>F6XAwX#eFj8s&NdK8LXIL-ac$v(|_@C#$6!(-wN5>y9b6H>v za%rgHD;WO&5BmR~fr07Cx6eScX2Q&4f-%UUkqw9G|IhIM35*S*$@T#@!xB@00001b5ch_0Itp) z=>Px#%1J~)R45f=WFP|UIdM*l;qTu${}~uKnHZP@miQzxPWT0C; z{{3TEw)@EGLXak08k{UmPJ-l_7#SH3f*4THx98aDE}*ADetuG=S8ifdBvhGw(Zg&iT-pGmPx#?MXyIR5%f1U>F6Aqy)jjRePoX|N7Cv%*3!LHp+W9NG}Vq27opH{C?m+1B1%n zzYHIM`iM6GSu-Oe!`c7b+_f-^nP3bMy=c{LIb=SFjYYFdVxS|)1z-R-VE)qW5r2RF ze7JDQ)I9*B!pY|;Gto8cr-jF*v-aS012SLL5?U-yIj40Se&&0y=1 z4FCx&UcSZZ&mV>zKqfE4e}>OMXLXhwPx#q)9|UR2Ug!WWWJ-A3fW`$nYMaC1LKAN|NrO1 z6u4L!ZvolF!otWD_?O||{{R0O?Ef?Tw?|h1Qp5-%_8&W|^7lVbAp@fr$O@PVAUPCp k;>2yf{UPx$$Vo&&R9Fe^RliHaKoov=X_e~Yq9B5kgW#%*_=8Nf5%I_1(oz&1MgJ9@9jb=9 z6$hzWMWkK)51a&X)}e!`gYnLLjR(h(7;VzYydm%2-OKlVe0P@sB#}6fIPl*cAl){= zwy$Oxb*BwZ&kF_XLFenLfMdJ5$AIr6DIxGqd(sod_3V=>f~rNFW0f3nIfu;WhdZNl zr1Xh6YMmT02@od@(9rQ?7jRUr?lR`tF3He-0J@yd=bq)9%(0#UB*avYn0PRQE=r4luB&Z&J`T@figI+CfFrs=Bd`nXea#PM}N03He}w>=_KH-=J+ z#cbBmiLs7Cj_>~_IoGu~`a>VxC zg3{UD0C{WOaNv{JB!dvrpo1xky}Da}J?#=h&%Oe%DOdzNiY*#bfx@nu+N+NP1z=;4 z2o)p>IpX{%02@#QIIU}O5T>wJBPuy!g$lr?ZxQ!G#5mR%f?RwXjD?^toYxip^t}c8 zYn!WPllJxEpRCzlBftnZcA}E&JfXF?jz+0`X;mtX;n3!!A#osa;Fk`30i43p;@?+A QoB#j-07*qoM6N<$g8X~)vH$=8 literal 343 zcmV-d0jU0oP)Px$5lKWrR45f=WFQgz|NozH@3Av2{}~vw8U8ceVBlZ~Vykz{vQFiGj(AW$)25%KsP`nn9Xb7#Zsvt&Hy= z8-&jQMiv%FXLEyxO#c}eRx$kl9|^*L{{26;|L8>>m?4A=a4|Qy1yTz#L>Z=uf#JXC zpZ~x2fea$n0I(s9j10X9LqIHuLBMES_MZVQ5P@L;@&e2SFn!>F-F@VAKTx0mCWw{B zVE{-iJa+IJgvS6BLqHs?1`#j-!w`_b-eYI`{{8z0N|8W!Vh;nb91;Qd4w4wd{u5^{ p{{3ZCWn%xg-Od$s diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_ok_small.png b/android/app/src/main/res/drawable-xxhdpi/icon_ok_small.png index e824f5e8eb10f63c1018d2a3e54ec6ad6dc1366a..09907c71c79b0b9ae7fb805372234a3b201d0d15 100644 GIT binary patch literal 645 zcmV;00($+4P)Px%KS@MERA>e5m%mHHKorOC#X404(LpCSe<2RiRcR5SwsdfD(3a}r;ve82po5#6 z;v_X#HzySZe+{~I5>XL%5flWeU~6-}Cj=ZWm-NRa1@A$7>E&JC=li`}a%D`1c0fCz z9ncPF2ebp)f&c3OG^6zG{K)|Da(KAE`z8{Jlx2)fB_Owd+G!QP_88-n1Pu%xLjcq1 zbmGoQgyD3;?|y>k#jkT4p6YYP`@WgABV%cb8L;6Icti->7VcP>j=hV{1wI4${6!Zz z?*xyxQ88SOeu&_yFHivlU#fhbIl&Vk2evvh0~IurOy2)CI{Czk+#i{Pm* z5CM&X4@5vC;e8j-Xn0=*sDSq*pin5Z-afo6;*(+&fZcbtcW~A8h|q~SYee*(>(5>-?C5* zPqn22EXI39fGDERO@trtt^)7{a*at=wIck2cNLJGow~tgvLX^deWIE06P_5Pi14{JdiR8w1#ypG%DS0q=!R=V%AC1KI)Y ffObGTpwfXKh9W$A?#I$V00000NkvXXu0mjf9Vr>0 literal 470 zcmV;{0V)28P)Px$kV!;AR7efY)4fUqK@b4onLUdH6cn`(3k@~_Z6c{+niN9x5!6mW1PdFrJY)O;%4?!>R`Ru-gf{V z`Hr|K0@$RC)7`@M-6$v$Qp|qn8ft)er4dO=AIZ6Ww%W&fl8$i^`CcK=x-O(67vwbF z_^~92)K$EMrUv}ck0nKhC|TeOmATpmXnb+cAVG$92AQ?o#q98+1SS%_s68Z~^gN%hVHlTikfR<$J zH8j&OyH}iWyY$Rp{B=gbmo=-qN@QPhevMaRs+Gm-QYO<2&ihy6Z;lcJ@A+e}R{#J2 M07*qoM6N<$f>LtNf&c&j diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_ok_small.png b/android/app/src/main/res/drawable-xxxhdpi/icon_ok_small.png index ced7bb97ca2120cd511e274d6bb75197572b294d..6da22d32b1675016673e3e7da2b1447289ab1c5e 100644 GIT binary patch literal 845 zcmV-T1G4;yP)Px&2T4RhRCodHnayhxK@`B}?KTOz2N67Y^j1+21O?GcgJN1Lf|tb_Xc6>35J7MD zEaKIRHT@9jtr(4==s}?ek9yLRUi=`U#gB?jGUIzo zW>*LfHoykh02^QfY=8~00XDz}*Z><~18jf|45$I66huiqQllsXZC9Jc#nRE5kT+4l z5fJblKs}V6clF}A?7GgF11;d*(&K5N3LnpuhUI-A+hDv}LJiPYO`)=t7 z7}2SebR83TTngX1%FX%y!A+gKtruVlpBYJIr>0JS)PbiuR{sx(2>(GB-f97Hz*{RI zE_f>i#0hVmfVkm}1uQSG?bz7-b{!j@QbMH#zzZ+s&ielNSL&>nNCKYn)m{bW%Vn=# zslCLF#(^LxuDhSWb#gNoCSC>0P0o{oryN5z6U_*+QoXSio@(Gs*sEmyY2kk9P;(2t zt0dtmLu~;{z(gk`+>-8zA|YvbBLP_1>m-26O(oa>PkC$40K8eOQG>A1m0$}zv1kiO zfw+eCe}oC3@488_37+!R7LdiI!XfJ~e;JJm;m=N_xc)hbx z*69c!zJTMNq$Scuc*@&Y05vj|fK6`WteC}P*BM9q`Ttv5qg@^46(u4Gpn=RJ06wMuL7vE z!cs9Sr6}TQ_a!psyFKOCF8cBl2zE>oaLIdupLDQ1cn$#XGH&VwKD~`)sSA$1^}O!_ zXn?|l@)=pHuHas|W!=X=M?W)edejDZ%C#jyD(p38&gY7ba4zF5w&~>r{^l#fk;iO- zC(dn|0S$q7R#$grK36Z{l;00RKA+A{E;PR5BO71?Y=8~00XDz}*Z><~18jf|Bxv9- XmO6|b4nfLs00000NkvXXu0mjf;$C|q literal 567 zcmV-70?7S|P)Px$@kvBMR7efgm%T~@K@i7xHblWENGqn*CQ(c*0vaDcEG$wf0Yw`ND@z*-!9oj# z2!a?SK0_i1CZxD)thBMQ(auU#$c-}_5|aD!F1HD|#oq4B?*4!5&VC$-5hX-~ySllF zLTr)b6aqfQq&!;8q;44jM!{hiM*QO&ZxF?*T@NJe=dx_hj z5E9PwnbbA_U>Bs?G-t4dIbJk~!F_%{^{5swU={^JX>wL;n8$SB?DCa8 z?-6ZF*?h975Ii*09*iQXmfUnGlq*Zwbiofs2Lx+N3vkB`f^BpXuGJbwnP$rMywL^0 zT9U#f$px?E1)~#!wR!tKdqH&Ub{O3dtOL~tvw*_7?uhz*Ic6pxvHoejmp$(e`v5&# z)b8r7t6fs98zqW^Vz0xiOda0nDo=R%`|JTBxQ_ziZA(FUK})dFH&B#H2#78S7qr5J zgy;j&1~UMJ10*ucfDo=A1H(js@B|4B6A{7}BruEy2-fm_81XxSF1;dc@=I>)NC0P@ z_k_b2($K#419akBn*T}Ye`J!HzYyH%a(4DAK-d4(Px$$Vo&&R9Fe^RliHaKoov=X_e~Yq9B5kgW#%*_=8Nf5%I_1(oz&1MgJ9@9jb=9 z6$hzWMWkK)51a&X)}e!`gYnLLjR(h(7;VzYydm%2-OKlVe0P@sB#}6fIPl*cAl){= zwy$Oxb*BwZ&kF_XLFenLfMdJ5$AIr6DIxGqd(sod_3V=>f~rNFW0f3nIfu;WhdZNl zr1Xh6YMmT02@od@(9rQ?7jRUr?lR`tF3He-0J@yd=bq)9%(0#UB*avYn0PRQE=r4luB&Z&J`T@figI+CfFrs=Bd`nXea#PM}N03He}w>=_KH-=J+ z#cbBmiLs7Cj_>~_IoGu~`a>VxC zg3{UD0C{WOaNv{JB!dvrpo1xky}Da}J?#=h&%Oe%DOdzNiY*#bfx@nu+N+NP1z=;4 z2o)p>IpX{%02@#QIIU}O5T>wJBPuy!g$lr?ZxQ!G#5mR%f?RwXjD?^toYxip^t}c8 zYn!WPllJxEpRCzlBftnZcA}E&JfXF?jz+0`X;mtX;n3!!A#osa;Fk`30i43p;@?+A QoB#j-07*qoM6N<$g8X~)vH$=8 literal 470 zcmV;{0V)28P)Px$kV!;AR7efY)4fUqK@b4onLUdH6cn`(3k@~_Z6c{+niN9x5!6mW1PdFrJY)O;%4?!>R`Ru-gf{V z`Hr|K0@$RC)7`@M-6$v$Qp|qn8ft)er4dO=AIZ6Ww%W&fl8$i^`CcK=x-O(67vwbF z_^~92)K$EMrUv}ck0nKhC|TeOmATpmXnb+cAVG$92AQ?o#q98+1SS%_s68Z~^gN%hVHlTikfR<$J zH8j&OyH}iWyY$Rp{B=gbmo=-qN@QPhevMaRs+Gm-QYO<2&ihy6Z;lcJ@A+e}R{#J2 M07*qoM6N<$f>LtNf&c&j diff --git a/src/status_im/chat/views/message.cljs b/src/status_im/chat/views/message.cljs index 22d73c2334..fe0f9aec10 100644 --- a/src/status_im/chat/views/message.cljs +++ b/src/status_im/chat/views/message.cljs @@ -252,7 +252,7 @@ seen-by-everyone?) [view st/delivery-view [image {:source (case status - :seen {:uri :icon_ok_small} + :seen {:uri :icon_ok_small_copy_2} :failed res/delivery-failed-icon nil) :style st/delivery-image}] @@ -296,7 +296,7 @@ (or delivery-status message-status app-db-message-status-value :sending))] [view st/delivery-view [image {:source (case status - :seen {:uri :icon_ok_small} + :seen {:uri :icon_ok_small_copy_2} :failed res/delivery-failed-icon nil) :style st/delivery-image}] diff --git a/src/status_im/chats_list/styles.cljs b/src/status_im/chats_list/styles.cljs index f449465d4a..39cffe5d49 100644 --- a/src/status_im/chats_list/styles.cljs +++ b/src/status_im/chats_list/styles.cljs @@ -61,8 +61,7 @@ (def item-upper-container {:flex 1 - :flex-direction :row - :justify-content :space-between}) + :flex-direction :row}) (def item-lower-container (merge {:flex 1 @@ -70,9 +69,14 @@ :justify-content :space-between} (get-in p/platform-specific [:component-styles :chat-list :item-lower-container]))) +(def message-status-container + {:flex-direction :row + :align-items :center}) + (def name-view {:flex-direction :row - :flex-shrink 1}) + :flex 1 + :margin-right 4}) (def name-text (merge {:color text1-color @@ -112,9 +116,10 @@ :right 16}) (def status-image - {:marginTop 4 - :width 9 - :height 7}) + {:opacity 0.6 + :margin-right 4 + :width 16 + :height 16}) (def datetime-text (merge {:color text4-color} diff --git a/src/status_im/chats_list/views/inner_item.cljs b/src/status_im/chats_list/views/inner_item.cljs index db26966e41..157f8b22bc 100644 --- a/src/status_im/chats_list/views/inner_item.cljs +++ b/src/status_im/chats_list/views/inner_item.cljs @@ -108,10 +108,12 @@ (when private-group? [view st/private-group-icon-container [icon :private_group st/private-group-icon]]) - [text {:style st/name-text} - (if public-group? - (str "#" chat-name) - chat-name)]])) + [view {:flex-shrink 1} + [text {:style st/name-text + :number-of-lines 1} + (if public-group? + (str "#" chat-name) + chat-name)]]])) (defn chat-list-item-inner-view [{:keys [chat-id name color online group-chat contacts public?] :as chat} @@ -126,7 +128,7 @@ [view st/item-upper-container [chat-list-item-name name group-chat public?] (when (and (not edit?) @last-message) - [view + [view st/message-status-container [message-status chat @last-message] [message-timestamp @last-message]])] [view st/item-lower-container From 9d21285c1029e1994048d7d83e5309acebff4c6e Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Wed, 22 Mar 2017 00:38:15 -0300 Subject: [PATCH 17/48] fix contact list, edit icon and reorder screen --- src/status_im/android/platform.cljs | 18 ++++++----------- src/status_im/contacts/styles.cljs | 1 + src/status_im/ios/platform.cljs | 12 ++++------- src/status_im/new_group/styles.cljs | 31 +++++++++++++++++++++-------- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 83b170f919..1f4efde63b 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -66,8 +66,9 @@ :margin-top 0} :contact-list-title {:color styles/text4-color :font-size 14}} - :contacts {:subtitle {:color styles/color-gray4 - :font-size 14} + :contacts {:subtitle {:color styles/color-gray4 + :font-size 14 + :flex-shrink 1} :subtitle-count {:color styles/color-gray4 :font-size 14} :info-container {:margin-left 16} @@ -79,8 +80,8 @@ :height 17} :group-header {:flexDirection :row :alignItems :center - :height 56 - :padding-top 10 + :padding-top 28 + :padding-bottom 20 :padding-left 16 :padding-right 14 :backgroundColor styles/color-light-gray} @@ -125,14 +126,7 @@ :flex-direction :row :align-items :center} :settings-group-container {:margin-top 23}} - :reorder-groups {:order-item-container {:height 56 - :background-color styles/color-white} - :order-item-icon {:padding-right 16} - :order-item-label {:padding-left 16 - :font-size 16 - :color styles/color-black - :line-height 24} - :reorder-list-container {:padding-top 16} + :reorder-groups {:reorder-list-container {:padding-top 16} :order-item-contacts {:font-size 16 :line-height 24} :add-to-contacts-text {:font-size 14 diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index 09a6549d43..8552a93ec8 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -133,6 +133,7 @@ (def more-btn {:width 24 :height 24 + :margin-left 16 :alignItems :center :justifyContent :center}) diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 6de4eb77c5..deecaafa11 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -74,7 +74,8 @@ :font-size 16}} :contacts {:subtitle {:color styles/text1-color :font-size 16 - :letter-spacing -0.2} + :letter-spacing -0.2 + :flex-shrink 1} :subtitle-count {:color styles/color-gray4 :font-size 16 :letter-spacing -0.2} @@ -86,9 +87,10 @@ :group-header {:flexDirection :row :alignItems :center :margin-top 24 + :padding-top 19 + :padding-bottom 15 :padding-left 16 :padding-right 16 - :height 53 :backgroundColor styles/color-white} :show-all {:padding-left 72 :height 64} @@ -151,12 +153,6 @@ :border-radius 50}} :reorder-groups {:order-item-separator {:margin-left 16 :opacity 0.5} - :order-item-container {:height 63} - :order-item-icon {:padding-right 20} - :order-item-label {:padding-left 16 - :font-size 17 - :line-height 20 - :letter-spacing -0.2} :order-item-contacts {:font-size 17 :line-height 20 :letter-spacing -0.2}} diff --git a/src/status_im/new_group/styles.cljs b/src/status_im/new_group/styles.cljs index ede18b385a..591a677fb0 100644 --- a/src/status_im/new_group/styles.cljs +++ b/src/status_im/new_group/styles.cljs @@ -1,6 +1,8 @@ (ns status-im.new-group.styles + (:require-macros [status-im.utils.styles :refer [defstyle]]) (:require [status-im.components.styles :refer [color-white color-blue + color-black text1-color text2-color color-light-blue @@ -165,21 +167,34 @@ (def order-item-container {:background-color color-white}) -(def order-item-inner-container - (merge {:flex-direction :row - :align-items :center} - (ps-reorder :order-item-container))) +(defstyle order-item-inner-container + {:flex-direction :row + :align-items :center + :android {:padding-top 17 + :padding-bottom 15 + :min-height 56 + :background-color color-white} + :ios {:padding-vertical 22 + :min-height 63}}) -(def order-item-label - (ps-reorder :order-item-label)) +(defstyle order-item-label + {:padding-left 16 + :flex-shrink 1 + :android {:font-size 16 + :color color-black + :line-height 24} + :ios {:font-size 17 + :line-height 20 + :letter-spacing -0.2}}) (def order-item-contacts (merge (ps-reorder :order-item-contacts) {:padding-left 8 :color color-gray4})) -(def order-item-icon - (ps-reorder :order-item-icon)) +(defstyle order-item-icon + {:android {:padding-horizontal 16} + :ios {:padding-horizontal 20}}) (def order-item-separator-wrapper {:background-color color-white}) From b54c9f337f8fc9ec0bea3dc5da04404a827e5c6c Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Wed, 8 Mar 2017 23:28:21 -0300 Subject: [PATCH 18/48] chat messages UI refresh --- src/status_im/android/platform.cljs | 4 - src/status_im/chat/screen.cljs | 12 +- src/status_im/chat/styles/datemark.cljs | 18 +-- src/status_im/chat/styles/message.cljs | 130 +++++++++--------- src/status_im/chat/styles/screen.cljs | 33 +++-- src/status_im/chat/subs.cljs | 8 ++ src/status_im/chat/views/message.cljs | 99 ++++++------- src/status_im/chat/views/request_message.cljs | 19 +-- src/status_im/chat/views/toolbar_content.cljs | 20 +-- src/status_im/components/styles.cljs | 1 + src/status_im/contacts/subs.cljs | 5 + src/status_im/ios/platform.cljs | 5 - src/status_im/translations/en.cljs | 4 +- 13 files changed, 163 insertions(+), 195 deletions(-) diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 1f4efde63b..1dedaa4f0a 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -141,10 +141,6 @@ :height 56 :align-items :center :justify-content :center} - :toolbar-last-activity {:color styles/text2-color - :background-color :transparent - :top 0 - :font-size 12} :text-field-focus-line-height 2}) (def fonts diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index 37f4b6d666..d3f27a0c17 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -77,13 +77,14 @@ (list-item [chat-datemark value])) (defmethod message-row :default - [{:keys [contact-by-identity group-chat messages-count row index]}] + [{:keys [contact-by-identity group-chat messages-count row index last-outgoing?]}] (let [message (-> row (add-message-color contact-by-identity) (assoc :group-chat group-chat) (assoc :messages-count messages-count) (assoc :index index) - (assoc :last-message (= (js/parseInt index) (dec messages-count))))] + (assoc :last-message (= (js/parseInt index) (dec messages-count))) + (assoc :last-outgoing? last-outgoing?))] (list-item [chat-message message]))) (defn toolbar-action [] @@ -152,7 +153,9 @@ [messages [:chat :messages] contacts [:chat :contacts] message-extras [:get :message-extras] - loaded? [:all-messages-loaded?]] + loaded? [:all-messages-loaded?] + current-chat-id [:get-current-chat-id] + last-outgoing-message [:get-chat-last-outgoing-message @current-chat-id]] (let [contacts' (contacts-by-identity contacts) messages (messages-with-timemarks messages message-extras)] [list-view {:renderRow (fn [row _ index] @@ -160,7 +163,8 @@ :group-chat group-chat :messages-count (count messages) :row row - :index index})) + :index index + :last-outgoing? (= (:message-id last-outgoing-message) (:message-id row))})) :renderScrollComponent #(invertible-scroll-view (js->clj %)) :onEndReached (when-not loaded? #(dispatch [:load-more-messages])) :enableEmptySections true diff --git a/src/status_im/chat/styles/datemark.cljs b/src/status_im/chat/styles/datemark.cljs index c311ef4467..eb892ea66f 100644 --- a/src/status_im/chat/styles/datemark.cljs +++ b/src/status_im/chat/styles/datemark.cljs @@ -1,19 +1,15 @@ -(ns status-im.chat.styles.datemark) +(ns status-im.chat.styles.datemark + (:require [status-im.components.styles :as st])) (def datemark-wrapper {:flex 1 :align-items :center}) (def datemark - {:background-color "#bbc4cb33" - :padding-left 12 - :padding-right 12 - :margin-top 8 - :margin-bottom 8 - :border-radius 12 - :height 24}) + {:opacity 0.5 + :margin-top 20 + :height 20}) (def datemark-text - {:color "#838c93" - :top 4 - :font-size 12}) + {:color st/color-gray4 + :font-size 15}) diff --git a/src/status_im/chat/styles/message.cljs b/src/status_im/chat/styles/message.cljs index e45e0d223e..b322f187a9 100644 --- a/src/status_im/chat/styles/message.cljs +++ b/src/status_im/chat/styles/message.cljs @@ -1,18 +1,22 @@ (ns status-im.chat.styles.message + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) (:require [status-im.components.styles :refer [color-white color-black color-blue + color-light-blue selected-message-color text1-color text2-color - color-gray]] + color-gray + color-gray4]] [status-im.constants :refer [text-content-type content-type-command]])) -(def style-message-text - {:fontSize 14 - :lineHeight 21 - :color text1-color}) +(defstyle style-message-text + {:fontSize 15 + :color text1-color + :android {:line-height 22} + :ios {:line-height 23}}) (def style-sub-text {:top -2 @@ -22,17 +26,17 @@ :height 16}) (defn message-padding-top - [{:keys [new-day same-author same-direction]}] + [{:keys [first-in-date? same-author same-direction]}] (cond - new-day 0 - same-author 4 - same-direction 20 - :else 10)) + first-in-date? 20 + same-author 8 + same-direction 16 + :else 24)) (defn last-message-padding [{:keys [last-message typing]}] (when (and last-message (not typing)) - {:paddingBottom 20})) + {:paddingBottom 16})) (def message-datemark {:margin-top 10 @@ -42,30 +46,21 @@ {:height 16}) (def message-body-base - {:padding-right 8 - :padding-left 8}) + {:padding-right 10 + :padding-left 10}) (defn message-body [{:keys [outgoing] :as message}] - (let [align (if outgoing :flex-end :flex-start)] + (let [align (if outgoing :flex-end :flex-start) + direction (if outgoing :row-reverse :row)] (merge message-body-base - {:flexDirection :column + {:flexDirection direction :width 260 :paddingTop (message-padding-top message) :alignSelf align :alignItems align} (last-message-padding message)))) -(defn incoming-group-message-body-st - [message] - (merge message-body-base - {:flexDirection :row - :alignSelf :flex-start - :marginTop (message-padding-top message) - :paddingRight 8 - :paddingLeft 8} - (last-message-padding message))) - (def selected-message {:marginTop 18 :marginLeft 40 @@ -75,75 +70,72 @@ (def group-message-wrapper {:flexDirection :column}) -(def group-message-view - {:flexDirection :column - :width 260 - :paddingLeft 8 - :alignItems :flex-start}) +(defn group-message-view + [{:keys [outgoing] :as message}] + (let [align (if outgoing :flex-end :flex-start)] + {:flexDirection :column + :width 260 + :padding-left 10 + :padding-right 10 + :alignItems align})) -(def message-author {:width 24}) +(def message-author + {:width 36 + :alignSelf :flex-start}) (def photo-view {:borderRadius 12}) (def photo {:borderRadius 12 - :width 24 - :height 24}) + :width 36 + :height 36}) (def delivery-view {:flexDirection :row - :marginTop 2}) + :marginTop 2 + :opacity 0.5}) -(def delivery-image - {:marginTop 6 - :width 9 - :height 7}) - -(def delivery-text - {:fontSize 12 - :color text2-color - :marginLeft 5}) +(defstyle delivery-text + {:color color-gray4 + :marginLeft 5 + :android {:font-size 13} + :ios {:font-size 14}}) (defn text-message [{:keys [outgoing group-chat incoming-group]}] (merge style-message-text - {:marginTop (if incoming-group - 4 - 0)} - (when (and outgoing group-chat) - {:color color-white}))) + {:marginTop (if incoming-group 4 0)})) -(defn message-view +(defnstyle message-view [{:keys [content-type outgoing group-chat selected]}] - (merge {:borderRadius 14 - :padding 12 - :backgroundColor color-white} + (merge {:padding 12 + :backgroundColor color-white + :android {:border-radius 4} + :ios {:border-radius 8}} (when (= content-type content-type-command) {:paddingTop 10 - :paddingBottom 14}) - (if outgoing - (when (and group-chat (= content-type text-content-type)) - {:backgroundColor color-blue}) - (when selected - {:backgroundColor selected-message-color})))) + :paddingBottom 14}))) -(def author - {:color color-gray}) +(defstyle author + {:color color-gray4 + :margin-bottom 5 + :android {:font-size 13} + :ios {:font-size 14}}) (def comand-request-view {:paddingRight 16}) (def command-request-message-view - {:borderRadius 14 - :padding 12 - :paddingRight 28 - :backgroundColor color-white}) + {:borderRadius 14 + :padding-vertical 10 + :paddingRight 28 + :backgroundColor color-white}) (def command-request-from-text (merge style-sub-text {:marginBottom 2})) -(defn command-request-image-touchable [top-offset?] +(defn command-request-image-touchable [] {:position :absolute - :top (if top-offset? 4 -1) + :top 0 :right -8 :alignItems :center :justifyContent :center @@ -177,14 +169,16 @@ :height 14}) (def content-command-view - {:flexDirection :column}) + {:flexDirection :column + :alignItems :flex-start}) (def command-container {:flexDirection :row + :margin-top 4 :marginRight 32}) (def command-image - {:margin-top 5 + {:margin-top 9 :width 12 :height 13 :tint-color :#a9a9a9cc}) diff --git a/src/status_im/chat/styles/screen.cljs b/src/status_im/chat/styles/screen.cljs index aa7a6229c5..b5528dfc32 100644 --- a/src/status_im/chat/styles/screen.cljs +++ b/src/status_im/chat/styles/screen.cljs @@ -1,9 +1,12 @@ (ns status-im.chat.styles.screen + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) (:require [status-im.components.styles :refer [chat-background selected-message-color separator-color text1-color - text2-color]] + text2-color + text4-color + color-gray6]] [status-im.components.toolbar.styles :refer [toolbar-background1]])) (def chat-view @@ -41,16 +44,15 @@ :width 8 :height 14}) -(defn chat-name-view [show-actions] +(defnstyle chat-name-view [show-actions] {:flex 1 - :margin-bottom 2 :margin-left (if show-actions 16 0) - :align-items :flex-start - :justify-content :center}) + :justify-content :center + :android {:align-items :flex-start} + :ios {:align-items :center}}) (def chat-name-text - {:color text1-color - :margin-top 2 + {:color color-gray6 :fontSize 16}) (def group-icon @@ -63,14 +65,17 @@ {:width 14 :height 8}) -(def members - {:marginTop -0.5 - :marginLeft 4 - :fontSize 12 - :color text2-color}) +(defstyle members + {:color text4-color + :ios {:font-size 14 + :margin-top 4} + :android {:font-size 13}}) -(def last-activity - {:height 18}) +(defstyle last-activity-text + {:color text4-color + :ios {:font-size 14 + :margin-top 4} + :android {:font-size 13}}) (defn actions-wrapper [status-bar-height] {:backgroundColor toolbar-background1 diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index e2615a7821..41cca401ff 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -275,3 +275,11 @@ (let [last-message (subscribe [:get-last-message chat-id])] (reaction (get-in @db [:message-data :short-preview (:message-id @last-message)]))))) + +(register-sub :get-chat-last-outgoing-message + (fn [db [_ chat-id]] + (reaction + (->> (:messages (get-in @db [:chats chat-id])) + (filter :outgoing) + (sort-by :clock-value >) + (first))))) diff --git a/src/status_im/chat/views/message.cljs b/src/status_im/chat/views/message.cljs index fe0f9aec10..4daefe5a15 100644 --- a/src/status_im/chat/views/message.cljs +++ b/src/status_im/chat/views/message.cljs @@ -1,7 +1,6 @@ (ns status-im.chat.views.message (:require-macros [status-im.utils.views :refer [defview]]) - (:require [clojure.string :as s] - [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [subscribe dispatch]] [reagent.core :as r] [status-im.i18n :refer [message-status-label]] [status-im.components.react :refer [view @@ -41,6 +40,14 @@ (def window-width (:width (get-dimensions "window"))) +(defview message-author-name [{:keys [outgoing from] :as message}] + [current-account [:get-current-account] + incoming-name [:contact-name-by-identity from]] + (if-let [name (if outgoing + (:name current-account) + (or incoming-name "Unknown contact"))] + [text {:style st/author} name])) + (defn message-content-status [_] (let [{:keys [chat-id group-chat name color]} (subscribe [:chat-properties [:chat-id :group-chat :name :color]]) members (subscribe [:current-chat-contacts])] @@ -143,28 +150,16 @@ :current-chat-id current-chat-id}]])) (defn message-view - [{:keys [username same-author index] :as message} content] + [{:keys [same-author index group-chat] :as message} content] [view (st/message-view message) - (when (and username (or (= 1 index) (not same-author))) - [text {:style st/author} username]) + (when group-chat [message-author-name message]) content]) -(defmulti message-content (fn [_ message _] - (message :content-type))) - -(defmethod message-content content-type-command-request - [wrapper message] - [wrapper message [message-content-command-request message]]) - -(defmethod message-content c/content-type-wallet-request - [wrapper message] - [wrapper message [message-content-command-request message]]) - (def replacements {"\\*[^*]+\\*" {:font-weight :bold} "~[^~]+~" {:font-style :italic}}) -(def regx (re-pattern (s/join "|" (map first replacements)))) +(def regx (re-pattern (str/join "|" (map first replacements)))) (defn get-style [string] (->> replacements @@ -179,7 +174,7 @@ ;; todo rewrite this, naive implementation (defn- parse-text [string] (if (string? string) - (let [general-text (s/split string regx) + (let [general-text (str/split string regx) general-text' (if (zero? (count general-text)) [nil] general-text) @@ -205,13 +200,23 @@ simple-text? (= (count parsed-text) 2)] (if simple-text? [autolink {:style (st/text-message message) - :font :default :text (apply str parsed-text) :onPress #(browse %)}] - [text {:style (st/text-message message) - :font :default} + [text {:style (st/text-message message)} (parse-text content)]))]) +(defmulti message-content (fn [_ message _] (message :content-type))) + +(defmethod message-content content-type-command-request + [wrapper message] + [wrapper message + [message-view message [message-content-command-request message]]]) + +(defmethod message-content c/content-type-wallet-request + [wrapper message] + [wrapper message + [message-view message [message-content-command-request message]]]) + (defmethod message-content text-content-type [wrapper message] [wrapper message [text-message message]]) @@ -251,11 +256,6 @@ (if (or (zero? (count user-statuses)) seen-by-everyone?) [view st/delivery-view - [image {:source (case status - :seen {:uri :icon_ok_small_copy_2} - :failed res/delivery-failed-icon - nil) - :style st/delivery-image}] [text {:style st/delivery-text :font :default} (message-status-label @@ -295,11 +295,6 @@ :else (or delivery-status message-status app-db-message-status-value :sending))] [view st/delivery-view - [image {:source (case status - :seen {:uri :icon_ok_small_copy_2} - :failed res/delivery-failed-icon - nil) - :style st/delivery-image}] [text {:style st/delivery-text :font :default} (message-status-label status)]])) @@ -307,37 +302,26 @@ (defview member-photo [from] [photo-path [:photo-path from]] [view st/photo-view - [image {:source {:uri (if (s/blank? photo-path) + [image {:source {:uri (if (str/blank? photo-path) (identicon from) photo-path)} :style st/photo}]]) -(defn incoming-group-message-body - [{:keys [selected same-author from index] :as message} content] +(defn message-body + [{:keys [last-outgoing? message-type same-author from index] :as message} content] (let [delivery-status :seen-by-everyone] [view st/group-message-wrapper - (when selected - [text {:style st/selected-message - :font :default} - "Mar 7th, 15:22"]) - [view (st/incoming-group-message-body-st message) + [view (st/message-body message) [view st/message-author - (when (or (= index 1) - (not same-author)) [member-photo from])] - [view st/group-message-view + (when (and (or (= index 1) (not same-author)) + (not= from "me")) + [member-photo from])] + [view (st/group-message-view message) content - ;; TODO show for last or selected - (when (and selected delivery-status) - [message-delivery-status message])]]])) - -(defn message-body - [{:keys [outgoing message-type] :as message} content] - [view (st/message-body message) - content - (when outgoing - (if (= (keyword message-type) :group-user-message) - [group-message-delivery-status message] - [message-delivery-status message]))]) + (when last-outgoing? + (if (= (keyword message-type) :group-user-message) + [group-message-delivery-status message] + [message-delivery-status message]))]]])) (defn message-container-animation-logic [{:keys [to-value val callback]}] (fn [_] @@ -399,8 +383,5 @@ #(share content (label :t/message)))} [view (let [incoming-group (and group-chat (not outgoing))] - [message-content - (if incoming-group - incoming-group-message-body - message-body) - (merge message {:incoming-group incoming-group})])]]])}))) + [message-content message-body (merge message + {:incoming-group incoming-group})])]]])}))) diff --git a/src/status_im/chat/views/request_message.cljs b/src/status_im/chat/views/request_message.cljs index 725b4c52b0..5903c61f65 100644 --- a/src/status_im/chat/views/request_message.cljs +++ b/src/status_im/chat/views/request_message.cljs @@ -41,7 +41,7 @@ (anim/start (button-animation val min-scale loop? answered?))))) -(defn request-button [message-id _ _ top-offset?] +(defn request-button [message-id _ _] (let [scale-anim-val (anim/create-value min-scale) answered? (subscribe [:is-request-answered? message-id]) loop? (r/atom true) @@ -60,7 +60,7 @@ [touchable-highlight {:on-press (when (and (not @answered?) status-initialized?) #(set-chat-command message-id command)) - :style (st/command-request-image-touchable top-offset?) + :style (st/command-request-image-touchable) :accessibility-label (id/chat-request-message-button (:name command))} [animated-view {:style (st/command-request-image-view command scale-anim-val)} (when command-icon @@ -68,8 +68,7 @@ (defn message-content-command-request [{:keys [message-id _ _ _]}] - (let [top-offset (r/atom {:specified? false}) - commands-atom (subscribe [:get-responses]) + (let [commands-atom (subscribe [:get-responses]) answered? (subscribe [:is-request-answered? message-id]) status-initialized? (subscribe [:get :status-module-initialized?]) preview (subscribe [:get-in [:message-data :preview message-id]])] @@ -85,19 +84,10 @@ {:on-press (when (and (not @answered?) @status-initialized?) #(set-chat-command message-id command))} [view st/command-request-message-view - (when incoming-group - [text {:style st/command-request-from-text - :font :default} - from]) (if (and @preview (not (string? @preview))) [view @preview] [text {:style st/style-message-text - :on-layout #(reset! top-offset {:specified? true - :value (-> (.-nativeEvent %) - (.-layout) - (.-height) 
 - (> 25))}) :font :default} (or @preview content)])]] (when (:request-text command) @@ -105,5 +95,4 @@ [text {:style st/style-sub-text :font :default} (:request-text command)]]) - (when (:specified? @top-offset) - [request-button message-id command @status-initialized? (:value @top-offset)])])))) + [request-button message-id command @status-initialized?]])))) diff --git a/src/status_im/chat/views/toolbar_content.cljs b/src/status_im/chat/views/toolbar_content.cljs index 999f896d79..ab704e362f 100644 --- a/src/status_im/chat/views/toolbar_content.cljs +++ b/src/status_im/chat/views/toolbar_content.cljs @@ -10,7 +10,6 @@ label label-pluralize]] [status-im.chat.styles.screen :as st] - [status-im.components.refreshable-text.view :refer [refreshable-text]] [status-im.utils.datetime :as time] [status-im.utils.platform :refer [platform-specific]] [status-im.utils.gfycat.core :refer [generate-gfy]] @@ -41,13 +40,11 @@ (defview last-activity [{:keys [online-text sync-state]}] [state [:get :sync-data]] - [refreshable-text {:style st/last-activity - :text-style (get-in platform-specific [:component-styles :toolbar-last-activity]) - :font :default - :value (case sync-state - :in-progress (in-progress-text state) - :synced (label :t/sync-synced) - online-text)}]) + [text {:style st/last-activity-text} + (case sync-state + :in-progress (in-progress-text state) + :synced (label :t/sync-synced) + online-text)]) (defn group-last-activity [{:keys [contacts sync-state public?]}] (if (or (= sync-state :in-progress) @@ -55,13 +52,10 @@ [last-activity {:sync-state sync-state}] (if public? [view {:flex-direction :row} - [text {:font :default - :style (get-in platform-specific [:component-styles :toolbar-last-activity])} + [text {:style (get-in platform-specific [:component-styles :toolbar-last-activity])} (label :t/public-group-status)]] [view {:flex-direction :row} - [icon :group st/group-icon] - [text {:style st/members - :font :medium} + [text {:style st/members} (if public? (label :t/public-group-status) (let [cnt (inc (count contacts))] diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 84844787bb..142b2d7d28 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -10,6 +10,7 @@ (def color-gray3 "#00000040") (def color-gray4 "#939ba1") (def color-gray5 "#d9dae1") +(def color-gray6 "#212121") (def color-steel "#838b91") (def color-white "white") (def color-light-blue "#628fe3") diff --git a/src/status_im/contacts/subs.cljs b/src/status_im/contacts/subs.cljs index cabc09d707..565b23483e 100644 --- a/src/status_im/contacts/subs.cljs +++ b/src/status_im/contacts/subs.cljs @@ -156,6 +156,11 @@ (fn [db [_ identity]] (reaction (get-in @db [:contacts identity])))) +(register-sub :contact-name-by-identity + (fn [db [_ identity]] + (let [contacts (subscribe [:get-contacts])] + (reaction (:name (@contacts identity)))))) + (register-sub :all-new-contacts (fn [db _] (contacts-by-current-chat remove db))) diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index deecaafa11..0efffddf12 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -174,10 +174,6 @@ :toolbar-border {:height 1 :background-color styles/color-gray5 :opacity 0.5} - :toolbar-last-activity {:color styles/text2-color - :background-color :transparent - :top 0 - :font-size 14} :text-field-focus-line-height 1}) (def fonts @@ -223,4 +219,3 @@ :public-group-icon-container {:margin-top 2} :private-group-icon-container {:margin-top 2} :public-group-chat-hash-style {:top 6 :left 3}}) - diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 8e5b1e8c20..b95cbc2392 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -25,8 +25,8 @@ :members {:one "1 member" :other "{{count}} members" :zero "no members"} - :members-active {:one "1 member, 1 active" - :other "{{count}} members, {{count}} active" + :members-active {:one "1 member" + :other "{{count}} members" :zero "no members"} :public-group-status "Public" :active-online "Online" From 9c89c566797ddd70f3ddc57fec5b93f3e8f2dfd6 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Mon, 27 Mar 2017 17:57:07 +0300 Subject: [PATCH 19/48] fixes for code review (+1 squashed commit) Squashed commits: [58e9394] fix for https://github.com/status-im/status-react/issues/928 (+1 squashed commit) Squashed commits: [f56e7ad] fixes after rebase (+1 squashed commit) Squashed commits: [bb4a409] fixes after rebase (+1 squashed commit) Squashed commits: [297b52d] rebase onto ui-refresh --- .../main/res/drawable-hdpi/icon_ok_dark.png | Bin 0 -> 802 bytes .../main/res/drawable-mdpi/icon_ok_dark.png | Bin 0 -> 503 bytes .../main/res/drawable-xhdpi/icon_ok_dark.png | Bin 0 -> 1079 bytes .../main/res/drawable-xxhdpi/icon_ok_dark.png | Bin 0 -> 1593 bytes .../res/drawable-xxxhdpi/icon_ok_dark.png | Bin 0 -> 2206 bytes .../icon_ok_dark.imageset/Contents.json | 21 ++ .../icon_ok_dark.imageset/icon_ok_dark.png | Bin 0 -> 1079 bytes src/status_im/android/platform.cljs | 16 -- .../action_button/action_button.cljs | 9 + .../components/action_button/styles.cljs | 21 +- src/status_im/components/common/common.cljs | 6 + src/status_im/components/common/styles.cljs | 4 + src/status_im/components/text_field/view.cljs | 21 +- src/status_im/ios/platform.cljs | 23 -- src/status_im/profile/edit/screen.cljs | 69 +++--- src/status_im/profile/screen.cljs | 148 ++++++------ src/status_im/profile/styles.cljs | 212 +++++++++--------- src/status_im/translations/en.cljs | 3 + 18 files changed, 295 insertions(+), 258 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_ok_dark.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_ok_dark.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_ok_dark.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_ok_dark.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_ok_dark.png create mode 100644 ios/StatusIm/Images.xcassets/icon_ok_dark.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_ok_dark.imageset/icon_ok_dark.png diff --git a/android/app/src/main/res/drawable-hdpi/icon_ok_dark.png b/android/app/src/main/res/drawable-hdpi/icon_ok_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..84836c6a2e79ff838d990135added46cf38ba2de GIT binary patch literal 802 zcmV+-1Ks?IP)Px%+(|@1R9Fe^mdj65K@^A2xer}{sQ6l%=)#2t(Wnul(PHhQP~xU(F|mN`{GWuj z8@O}>6sYCBF~(O^qKL$e3q`~S8gxJu1PwfcM)di5 z5z7MP3$&fLgc#$@t(L)&VN^wP4;qmd>%pXLH!|4lx;J?D0$4E2Idd?*7x9O#g1f&v z`mz{b+p3T+(0Y+97$I1J0sM}rxCeS7uZn?@HrsZ~8vUV57QirH?fq%T2;US%cMljH zuZx9|b_Eq8BIKq_PEPWl-MFzbmn{+u1FJBahBxEg;i-*xXItbcFcmAdbDFN!$GgHa_TEzZHG!m4`N)xl zqxMzisX2Zqsxo18)Ls3tj`yWNWbR!TNE)u(B6+2=zh4kP%VQccqO+L}OZ}afL%9z5 zGvTquTwJOD+H0IMpHyABvE4Azf5C^*4s7?c(^DT$)zm%#0d)*B!?|=jZghUI*PY%` gz)`?apacc}0X7W$KvNKnHvj+t07*qoM6N<$f=}3Y1poj5 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_ok_dark.png b/android/app/src/main/res/drawable-mdpi/icon_ok_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..34903a27e979edabe42c0dcf6d0230d09e3299be GIT binary patch literal 503 zcmVPx$u}MThR7ef&lRHZTK@i7h_7p#Xr70~$#7|*ym&8ZB1dH57EDT6QYnxyzh$1Q? z;;YddSg5%mg7_${QmCMawVjP`%{ZHIa7j!^V!$Tb%0eMzB(A5{rsf#{o~WLn^Ttns&32?z$7Ak2%)6h0h-*KT71rYo`}W)@ErjI zhdUdmZjR#KRO@THvA~(fBwP_RkhHe!LPkviIAgrLd01pS28eHnqMzY;t#JaO<5X%T zT+<^<1evIW3#7heV*99+zN$CK!b9dV0gdv5z5uYhPGL*UUuW*gr{ogmrFgT^X9=m<~B3xVRZ6YD3=eL0&~ zfl!1gOP5*7@sq-MJT5rk8c`080=y}!GPu+iwZa!Nd%nJDAAnl84Kr+886M#;pSfJ^ zz}h~O!b(?B04Y>MhL{ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_ok_dark.png b/android/app/src/main/res/drawable-xhdpi/icon_ok_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c19cf293953dac89886a0f13b09e9b9d3ecc7b4a GIT binary patch literal 1079 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

; literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_ok_dark.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_ok_dark.imageset/Contents.json new file mode 100644 index 0000000000..b0484a2440 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_ok_dark.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_ok_dark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_ok_dark.imageset/icon_ok_dark.png b/ios/StatusIm/Images.xcassets/icon_ok_dark.imageset/icon_ok_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c19cf293953dac89886a0f13b09e9b9d3ecc7b4a GIT binary patch literal 1079 zcmV-71jze|P)Px&@kvBMRA>e5mrG9*Q547TnOBQwVl**vVWNpF#OQ*B>o%xSP=b%D@kLd_j)mWV z?_f*}PpJfoRnZn%xY6heV+<;w0v$x&r~xC5is@X>X&k-NGFXtdE@qOZ=l4Va}Lj551%dAx%*5(VbSzpf6t6vcVKrT zS31F$o~)?l2CpOrVDLpzwSsV4{q$l?(qdw+v;_Q#^K~XXad5`h#p4UR?3fh08`;)t zYHB2OzMgY-LF^j<-pgy1Zc!8C{~`f`f7%yqKzP3h#{edn#P)?78^2g|p^)<_lz{J# zHYLNO^W(BAdAiyI0|IYKnA1g^fbZ3tah{(|A{$dd^M*qWLrHo{F=q+*d^hEJh%_^U zov}~>jJhQ7-feG=T6CL2PTm6qALE@jaEm!Da?yg7RK*(!Ue`r^sW|H+@XPrYbpDhG zh9Dy{xV({2{jjM2Ezas9#yPK`^R3D7xZAwb6xp*}cuFp7BS7%oeR>}1MIEa<@SVwjT09A9}Bh# z0EZ`*XLEKK7h@|;EsHJ`2tGRbxdYGjrGiW!C2xSqo;xkIlcK&Fv26mf>OPM>_ggx_ zJ)F)jxE@m4`Tc%(bZYJ{jh5I3j|Z>ui^|g#x;`c9s}-k!m=BJ$)qX_RiV?tioW;Xe zcduSYUr%OTf}fr@?%}jMU}}kfG(b`CRB7`$XsNrxf^7oyJaWygX_y4QEiD(nSaPD` zDoH-y<-D0#Jd7WI`^75Qrq}Jx&nP_g_uECW^W?bvlz;2@xbYZwl`WQg5?le!cHn62 z6?Gi7SNS-4p-|HYQO`u2Rsz&XvVm(Un#P@ANTe-Q^S??JfEpqb>8gT_N8Q2SnPkGuV=DwXHmqE_!`FH!3Nj* x%3$!?pM(}` Date: Tue, 28 Mar 2017 14:00:19 +0300 Subject: [PATCH 20/48] fix for https://github.com/status-im/status-react/issues/935 --- src/status_im/contacts/screen.cljs | 13 ++++--------- src/status_im/contacts/views/contact.cljs | 3 ++- src/status_im/navigation/handlers.cljs | 4 +--- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index 8fc899fc4b..f3f8212935 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -3,7 +3,7 @@ (:require [reagent.core :as r] [clojure.string :as str] [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.components.common.common :refer [separator]] + [status-im.components.common.common :refer [separator top-shaddow bottom-shaddow]] [status-im.components.react :refer [view text image @@ -12,7 +12,6 @@ scroll-view list-view list-item] :as react] - [status-im.components.common.common :refer [top-shaddow bottom-shaddow]] [status-im.components.native-action-button :refer [native-action-button native-action-button-item]] [status-im.components.status-bar :refer [status-bar]] @@ -74,7 +73,7 @@ (when extended? [options-btn group])]) -(defn contact-group-form [{:keys [contacts contacts-count group edit? click-handler]}] +(defn contact-group-form [{:keys [contacts contacts-count group edit?]}] (let [subtitle (:name group)] [view st/contact-group (when subtitle @@ -90,7 +89,6 @@ [contact-view {:contact contact :extended? edit? - :on-click (when-not edit? click-handler) :extend-options (when group [{:value #(dispatch [:hide-contact contact]) :text (label :t/delete-contact) @@ -139,7 +137,6 @@ (defview contact-list [current-view?] [contacts [:get-added-contacts-with-limit contacts-limit] contacts-count [:added-contacts-count] - click-handler [:get :contacts-click-handler] edit? [:get-in [:contacts-ui-props :edit?]] groups [:all-added-groups] tabs-hidden? [:tabs-hidden?]] @@ -152,13 +149,11 @@ (when (pos? contacts-count) [contact-group-form {:contacts contacts :contacts-count contacts-count - :edit? edit? - :click-handler click-handler}]) + :edit? edit?}]) (for [group groups] ^{:key group} [contact-group-view {:group group - :edit? edit? - :click-handler click-handler}])] + :edit? edit?}])] [view st/empty-contact-groups [react/icon :group_big st/empty-contacts-icon] [text {:style st/empty-contacts-text} (label :t/no-contacts)]]) diff --git a/src/status_im/contacts/views/contact.cljs b/src/status_im/contacts/views/contact.cljs index 13ddbe267b..c8bd2af14c 100644 --- a/src/status_im/contacts/views/contact.cljs +++ b/src/status_im/contacts/views/contact.cljs @@ -10,7 +10,8 @@ (defn- on-press [{:keys [whisper-identity] :as contact}] (dispatch [:send-contact-request! contact]) - (dispatch [:start-chat whisper-identity {} :navigation-replace])) + (dispatch [:navigate-to-clean :chat-list]) + (dispatch [:start-chat whisper-identity {}])) (defn letter-view [letter] [view st/letter-container diff --git a/src/status_im/navigation/handlers.cljs b/src/status_im/navigation/handlers.cljs index a63a752eec..d6867a8810 100644 --- a/src/status_im/navigation/handlers.cljs +++ b/src/status_im/navigation/handlers.cljs @@ -52,9 +52,7 @@ (replace-view db view-id))) (defn- can-navigate-back? [db] - (and (not (db :creating-account?)) - ;; ... - )) + (and (not (db :creating-account?)))) (register-handler :navigate-back (enrich -preload-data!) From 60680f7293955f69633df4f6283224826a936866 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Thu, 30 Mar 2017 11:07:14 +0300 Subject: [PATCH 21/48] fixed active button position --- src/status_im/contacts/screen.cljs | 35 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index f3f8212935..a8ef755d26 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -140,22 +140,23 @@ edit? [:get-in [:contacts-ui-props :edit?]] groups [:all-added-groups] tabs-hidden? [:tabs-hidden?]] - [view (st/contacts-list-container tabs-hidden?) - (if edit? - [toolbar-edit] - [toolbar-view]) - (if (pos? (+ (count groups) contacts-count)) - [scroll-view {:style st/contact-groups} - (when (pos? contacts-count) - [contact-group-form {:contacts contacts - :contacts-count contacts-count - :edit? edit?}]) - (for [group groups] - ^{:key group} - [contact-group-view {:group group - :edit? edit?}])] - [view st/empty-contact-groups - [react/icon :group_big st/empty-contacts-icon] - [text {:style st/empty-contacts-text} (label :t/no-contacts)]]) + [view {:flex 1} + [view (st/contacts-list-container tabs-hidden?) + (if edit? + [toolbar-edit] + [toolbar-view]) + (if (pos? (+ (count groups) contacts-count)) + [scroll-view {:style st/contact-groups} + (when (pos? contacts-count) + [contact-group-form {:contacts contacts + :contacts-count contacts-count + :edit? edit?}]) + (for [group groups] + ^{:key group} + [contact-group-view {:group group + :edit? edit?}])] + [view st/empty-contact-groups + [react/icon :group_big st/empty-contacts-icon] + [text {:style st/empty-contacts-text} (label :t/no-contacts)]])] (when (and (not edit?) (get-in platform-specific [:contacts :action-button?])) [contacts-action-button])]) From ae632b6acc7c14dacd3127955e89565371b482f2 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Fri, 31 Mar 2017 18:18:24 +0300 Subject: [PATCH 22/48] rebase --- resources/default_contact_groups.json | 35 ++++++++++++++++ resources/default_contacts.json | 40 +++++++++++++------ src/status_im/contacts/handlers.cljs | 30 +++++++++----- .../data_store/realm/contact_groups.cljs | 4 +- src/status_im/new_group/handlers.cljs | 26 ++++++++++-- src/status_im/utils/js_resources.cljs | 1 + 6 files changed, 109 insertions(+), 27 deletions(-) create mode 100644 resources/default_contact_groups.json diff --git a/resources/default_contact_groups.json b/resources/default_contact_groups.json new file mode 100644 index 0000000000..c297b33d5d --- /dev/null +++ b/resources/default_contact_groups.json @@ -0,0 +1,35 @@ +{ + "dapps": + { + "name": + { + "en": "ÐApps" + }, + "contacts": + [ + "wallet", + "oaken-water-meter", + "melonport", + "bchat", + "Dentacoin", + "Augur", + "Ethlance", + "Commiteth" + ] + }, + "state-of-dapps": + { + "name": + { + "en": "State of the ÐApps" + }, + "contacts": + [ + "flight-delays-suck", + "FirstBlood", + "auction-house", + "gnosis", + "mkr-market" + ] + } +} diff --git a/resources/default_contacts.json b/resources/default_contacts.json index bada6ae94c..dfbd675ea4 100644 --- a/resources/default_contacts.json +++ b/resources/default_contacts.json @@ -10,7 +10,8 @@ }, "photo-path": "icon_wallet_avatar", "add-chat?": true, - "dapp?": true + "dapp?": true, + "groups": ["dapps"] }, "0x0428c9d6c1aaaa8369a7c63819684f30e34396dc0907d49afeac85a0a774ccb919b3482097d992e66bcc538e7a0c6acf874c77748f396f53c0a102e10d1a37765b": @@ -35,7 +36,8 @@ "dapp-url": { "en": "http://auctionhouse.dappbench.com" - } + }, + "groups": ["state-of-dapps"] }, "flight-delays-suck": @@ -49,7 +51,8 @@ "dapp-url": { "en": "https://fdd.etherisc.com" - } + }, + "groups": ["state-of-dapps"] }, "mkr-market": @@ -63,7 +66,8 @@ "dapp-url": { "en": "https://mkr.market" - } + }, + "groups": ["state-of-dapps"] }, "FirstBlood": @@ -77,7 +81,8 @@ "dapp-url": { "en": "https://app.firstblood.io" - } + }, + "groups": ["state-of-dapps"] }, "oaken-water-meter": @@ -91,7 +96,8 @@ "dapp-url": { "en": "http://waterflowdapp.projectoaken.com" - } + }, + "groups": ["dapps"] }, "gnosis": @@ -105,7 +111,8 @@ "dapp-url": { "en": "https://beta.gnosis.pm" - } + }, + "groups": ["state-of-dapps"] }, "melonport": @@ -119,7 +126,8 @@ "dapp-url": { "en": "https://portal.melonport.com/" - } + }, + "groups": ["dapps"] }, "bchat": @@ -133,7 +141,8 @@ "dapp-url": { "en": "http://swarm-gateways.net/bzz:/go-bchat.eth/" - } + }, + "groups": ["dapps"] }, "Dentacoin": @@ -147,7 +156,8 @@ "dapp-url": { "en": "http://dentacoin.com/testnet/" - } + }, + "groups": ["dapps"] }, "Augur": @@ -161,7 +171,8 @@ "dapp-url": { "en": "https://app.augur.net" - } + }, + "groups": ["dapps"] }, "Ethlance": @@ -175,7 +186,8 @@ "dapp-url": { "en": "https://madvas.github.io/ethlance/resources/public/" - } + }, + "groups": ["dapps"] }, "Commiteth": @@ -189,6 +201,8 @@ "dapp-url": { "en": "https://commiteth.com" + }, + "groups": ["dapps"] } }, @@ -203,6 +217,8 @@ "dapp-url": { "en": "http://test.etherplay.io" + }, + "groups": ["dapps"] } } } diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index 9ce02127ab..c75e4a09c4 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -174,6 +174,13 @@ (register-handler :get-contacts-identities (u/side-effect! get-identities-by-contacts!)) +(defn add-contacts-to-groups [{:keys [new-contacts]} _] + (let [default-contacts js-res/default-contacts] + (doseq [{:keys [whisper-identity]} new-contacts] + (let [groups (:groups ((keyword whisper-identity) default-contacts))] + (doseq [group groups] + (dispatch [:add-contacts-to-group group [whisper-identity]])))))) + (defn save-contacts! [{:keys [new-contacts]} _] (contacts/save-all new-contacts)) @@ -209,8 +216,15 @@ (u/side-effect! (fn [{:keys [chats groups]}] (let [default-contacts js-res/default-contacts - default-dapps-group-contacts (mapv #(hash-map :identity (clojure.core/name (first %))) - (filter #(true? (:dapp? (second %))) default-contacts))] + default-groups js-res/default-contact-groups] + (dispatch [:add-groups (mapv + (fn [[id {:keys [name contacts]}]] + {:group-id (clojure.core/name id) + :name (:en name) + :order 0 + :timestamp (random/timestamp) + :contacts (mapv #(hash-map :identity %) contacts)}) + default-groups)]) (doseq [[id {:keys [name photo-path public-key add-chat? dapp? dapp-url dapp-hash]}] default-contacts] (let [id' (clojure.core/name id)] @@ -224,16 +238,12 @@ :public-key public-key :dapp? dapp? :dapp-url (:en dapp-url) - :dapp-hash dapp-hash}]])))) - (dispatch [:add-groups [{:group-id "dapps" - :name (label :t/contacts-group-dapps) - :order 0 - :timestamp (random/timestamp) - :contacts default-dapps-group-contacts}]]))))) + :dapp-hash dapp-hash}]])))))))) (register-handler :add-contacts - (after save-contacts!) - add-new-contacts) + (-> add-new-contacts + ((after save-contacts!)) + ((after add-contacts-to-groups)))) (defn add-new-contact [db [_ {:keys [whisper-identity] :as contact}]] (-> db diff --git a/src/status_im/data_store/realm/contact_groups.cljs b/src/status_im/data_store/realm/contact_groups.cljs index 07b57d5987..f063cc9ef6 100644 --- a/src/status_im/data_store/realm/contact_groups.cljs +++ b/src/status_im/data_store/realm/contact_groups.cljs @@ -42,7 +42,9 @@ (defn- save-contacts [identities contacts] (doseq [contact-identity identities] - (.push contacts (clj->js {:identity contact-identity})))) + (when-not (.find contacts (fn [object _ _] + (= contact-identity (aget object "identity")))) + (.push contacts (clj->js {:identity contact-identity}))))) (defn add-contacts [group-id identities] diff --git a/src/status_im/new_group/handlers.cljs b/src/status_im/new_group/handlers.cljs index b62e27f7e2..78e182cb5f 100644 --- a/src/status_im/new_group/handlers.cljs +++ b/src/status_im/new_group/handlers.cljs @@ -236,10 +236,11 @@ (defn add-new-groups [{:keys [contact-groups] :as db} [_ new-groups]] (let [identities (set (keys contact-groups)) + old-groups-count (count identities) new-groups' (->> new-groups (map #(update-pending-status contact-groups %)) (remove #(identities (:group-id %))) - (map #(vector (:group-id %) %)) + (map #(vector (:group-id %2) (assoc %2 :order %1)) (iterate inc old-groups-count)) (into {}))] (-> db (update :contact-groups merge new-groups') @@ -317,7 +318,7 @@ (defn add-selected-contacts-to-group [{:keys [selected-contacts contact-groups contact-group-id] :as db} _] (let [new-identities (mapv #(hash-map :identity %) selected-contacts)] - (update-in db [:contact-groups contact-group-id :contacts] concat new-identities))) + (update-in db [:contact-groups contact-group-id :contacts] #(into [] (set (concat % new-identities)))))) (defn add-selected-contacts-to-group! [{:keys [contact-group-id selected-contacts]} _] @@ -325,8 +326,25 @@ (register-handler :add-selected-contacts-to-group - (-> add-selected-contacts-to-group - ((after add-selected-contacts-to-group!)))) + (after add-selected-contacts-to-group!) + add-selected-contacts-to-group) + +(defn add-contacts-to-group + [db [_ group-id contacts]] + (let [new-identities (mapv #(hash-map :identity %) contacts)] + (if (get-in db [:contact-groups group-id]) + (update-in db [:contact-groups group-id :contacts] #(into [] (set (concat % new-identities)))) + db))) + +(defn add-contacts-to-group! + [db [_ group-id contacts]] + (when (get-in db [:contact-groups group-id]) + (groups/add-contacts group-id contacts))) + +(register-handler + :add-contacts-to-group + (after add-contacts-to-group!) + add-contacts-to-group) (defn delete-group [] (fn [{:keys [contact-group-id] :as db} _] diff --git a/src/status_im/utils/js_resources.cljs b/src/status_im/utils/js_resources.cljs index 146e647512..0f7e019596 100644 --- a/src/status_im/utils/js_resources.cljs +++ b/src/status_im/utils/js_resources.cljs @@ -3,6 +3,7 @@ (:require [status-im.utils.types :refer [json->clj]])) (def default-contacts (json->clj (slurp "resources/default_contacts.json"))) +(def default-contact-groups (json->clj (slurp "resources/default_contact_groups.json"))) (def commands-js (slurp "resources/commands.js")) (def console-js (slurp "resources/console.js")) From 895b848dfe34a38258ceb28429749ed04919735d Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Fri, 31 Mar 2017 19:27:40 +0300 Subject: [PATCH 23/48] json fix --- resources/default_contacts.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/default_contacts.json b/resources/default_contacts.json index dfbd675ea4..7a912085c0 100644 --- a/resources/default_contacts.json +++ b/resources/default_contacts.json @@ -203,7 +203,6 @@ "en": "https://commiteth.com" }, "groups": ["dapps"] - } }, "Etherplay": @@ -219,6 +218,5 @@ "en": "http://test.etherplay.io" }, "groups": ["dapps"] - } } } From 74380bf3bbaef636cee191fb04ac601dd8a1cd76 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Wed, 29 Mar 2017 15:10:30 +0300 Subject: [PATCH 24/48] common components in chats list (+3 squashed commits) Squashed commits: [aecb167] removed old group settings screen [2fec747] common components in new chat screen [718e445] small fixes (+1 squashed commit) Squashed commits: [4a9be3c] rebase (+1 squashed commit) Squashed commits: [ef4f140] clear code, refactored groups using common components, moved styles from platform using defstyle macro (+1 squashed commit) Squashed commits: [b1ddb03] ns fixes (+2 squashed commits) Squashed commits: [236ec35] moved toggle contact item to components [42e0aa9] implemented list-separator, list-footer, list-header, renderers, contact-list-item, removed unused code --- src/status_im/android/core.cljs | 4 - src/status_im/android/platform.cljs | 64 +------ src/status_im/chats_list/screen.cljs | 34 +--- src/status_im/chats_list/styles.cljs | 19 -- .../components/action_button/styles.cljs | 3 +- src/status_im/components/common/common.cljs | 34 +++- src/status_im/components/common/styles.cljs | 55 ++++-- src/status_im/components/confirm_button.cljs | 13 -- src/status_im/components/contact/contact.cljs | 50 +++++ src/status_im/components/contact/styles.cljs | 69 +++++++ src/status_im/components/context_menu.cljs | 26 ++- .../components/renderers/renderers.cljs | 14 ++ src/status_im/components/sticky_button.cljs | 29 +++ src/status_im/components/styles.cljs | 27 --- src/status_im/contacts/default_contacts.cljs | 17 -- src/status_im/contacts/handlers.cljs | 7 + src/status_im/contacts/screen.cljs | 86 ++++----- src/status_im/contacts/search_results.cljs | 36 ---- src/status_im/contacts/styles.cljs | 136 +++----------- src/status_im/contacts/views/contact.cljs | 44 ----- .../contacts/views/contact_inner.cljs | 25 --- .../contacts/views/contact_list.cljs | 27 +-- .../contacts/views/contact_list_modal.cljs | 33 ++-- src/status_im/group_settings/screen.cljs | 174 ------------------ .../group_settings/styles/color_settings.cljs | 78 -------- .../group_settings/styles/group_settings.cljs | 163 ---------------- .../group_settings/views/color_settings.cljs | 48 ----- .../group_settings/views/member.cljs | 12 -- src/status_im/ios/core.cljs | 4 - src/status_im/ios/platform.cljs | 77 +------- src/status_im/new_chat/screen.cljs | 98 ++++------ src/status_im/new_chat/styles.cljs | 79 +------- src/status_im/new_group/screen_private.cljs | 29 ++- src/status_im/new_group/styles.cljs | 157 ++++++++-------- .../new_group/views/chat_group_settings.cljs | 50 +++-- .../new_group/views/contact_list.cljs | 111 +++++------ .../new_group/views/contact_toggle_list.cljs | 92 ++++----- src/status_im/new_group/views/group.cljs | 35 ++-- .../new_group/views/reorder_groups.cljs | 10 +- .../new_group/views/toggle_contact.cljs | 27 +-- src/status_im/participants/views/contact.cljs | 2 +- src/status_im/profile/edit/screen.cljs | 4 +- 42 files changed, 598 insertions(+), 1504 deletions(-) delete mode 100644 src/status_im/components/confirm_button.cljs create mode 100644 src/status_im/components/contact/contact.cljs create mode 100644 src/status_im/components/contact/styles.cljs create mode 100644 src/status_im/components/renderers/renderers.cljs create mode 100644 src/status_im/components/sticky_button.cljs delete mode 100644 src/status_im/contacts/default_contacts.cljs delete mode 100644 src/status_im/contacts/search_results.cljs delete mode 100644 src/status_im/contacts/views/contact.cljs delete mode 100644 src/status_im/contacts/views/contact_inner.cljs delete mode 100644 src/status_im/group_settings/screen.cljs delete mode 100644 src/status_im/group_settings/styles/color_settings.cljs delete mode 100644 src/status_im/group_settings/styles/group_settings.cljs delete mode 100644 src/status_im/group_settings/views/color_settings.cljs delete mode 100644 src/status_im/group_settings/views/member.cljs diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 2caed63d27..16125f6bcd 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -13,7 +13,6 @@ http-bridge]] [status-im.components.main-tabs :refer [main-tabs]] [status-im.components.context-menu :refer [menu-context]] - [status-im.contacts.search-results :refer [contacts-search-results]] [status-im.contacts.views.contact-list :refer [contact-list]] [status-im.contacts.views.contact-list-modal :refer [contact-list-modal]] [status-im.contacts.views.new-contact :refer [new-contact]] @@ -38,7 +37,6 @@ [status-im.new-group.views.reorder-groups :refer [reorder-groups]] [status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.remove :refer [remove-participants]] - [status-im.group-settings.screen :refer [group-settings]] [status-im.profile.screen :refer [profile my-profile]] [status-im.profile.edit.screen :refer [edit-my-profile]] [status-im.profile.photo-capture.screen :refer [profile-photo-capture]] @@ -125,10 +123,8 @@ :edit-group-contact-list edit-group-contact-list :edit-chat-group-contact-list edit-chat-group-contact-list :new-public-group new-public-group - :group-settings group-settings :contact-list main-tabs :contact-toggle-list contact-toggle-list - :contact-list-search-results contacts-search-results :group-contacts contact-list :reorder-groups reorder-groups :new-contact new-contact diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index a1eb6c5dec..0a60fb17fd 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -55,69 +55,7 @@ :item {:status-text {:color styles/color-black :line-height 22 :font-size 14}}} - :new-chat {:option-inner-container {:height 56} - :option-icon-container {:background-color styles/color-white - :margin-top 8} - :option-name-text {:font-size 16 - :color styles/text1-color} - :contact-list-title-container {:background-color styles/color-light-gray - :padding-top 28 - :padding-bottom 20 - :margin-top 0} - :contact-list-title {:color styles/text4-color - :font-size 14}} - :contacts {:subtitle {:color styles/color-gray4 - :font-size 14 - :flex-shrink 1} - :subtitle-count {:color styles/color-gray4 - :font-size 14} - :info-container {:margin-left 16} - :contact-inner-container {:height 56} - :contact-list-spacing {:background-color styles/color-white - :height 8} - :icon-check {:border-radius 2 - :width 17 - :height 17} - :group-header {:flexDirection :row - :alignItems :center - :padding-top 28 - :padding-bottom 20 - :padding-left 16 - :padding-right 14 - :backgroundColor styles/color-light-gray} - :show-all {:padding-left 72 - :height 56} - :show-all-text {:fontSize 14 - :color styles/color-blue - :letter-spacing 0.5} - :show-all-text-font :medium - :contact-container {:padding-right 16} - :name-text {:fontSize 16 - :line-height 24 - :color styles/text1-color}} - :new-group {:group-name-text {:font-size 12} - :members-text {:font-size 14} - :members-text-count {:font-size 14} - :add-text {:margin-left 16 - :line-height 24 - :font-size 16} - :contact-container {:height 56} - :settings-group-text {:letter-spacing 0.5 - :font-size 16} - :delete-group-prompt-text {:font-size 12} - :settings-group-item {:padding-left 16 - :height 56 - :flex-direction :row - :align-items :center} - :settings-group-container {:margin-top 23}} - :reorder-groups {:reorder-list-container {:padding-top 16} - :order-item-contacts {:font-size 16 - :line-height 24} - :add-to-contacts-text {:font-size 14 - :letter-spacing 0.5}} - :confirm-button-label {:color styles/color-white - :font-size 14 - :letter-spacing 0.5} + :contacts {:show-all-text-font :medium} :bottom-gradient {:height 3} :input-label {:left 4} :input-error-text {:margin-left 4} diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index 45ede3f8a3..f65eb93b86 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -1,6 +1,8 @@ (ns status-im.chats-list.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [dispatch]] + [status-im.components.common.common :as common] + [status-im.components.renderers.renderers :as renderers] [status-im.components.react :refer [list-view list-item view @@ -8,6 +10,7 @@ text icon image + linear-gradient touchable-highlight]] [status-im.components.native-action-button :refer [native-action-button]] [status-im.components.drawer.view :refer [open-drawer]] @@ -17,7 +20,6 @@ [status-im.components.toolbar-new.actions :as act] [status-im.components.toolbar-new.styles :as tst] [status-im.components.icons.custom-icons :refer [ion-icon]] - [status-im.components.react :refer [linear-gradient]] [status-im.components.sync-state.offline :refer [offline-view]] [status-im.components.context-menu :refer [context-menu]] [status-im.components.tabs.styles :refer [tabs-height]] @@ -70,25 +72,6 @@ :spacing 13 :on-press #(dispatch [:navigate-to :new-chat])}]) -(defn chat-list-padding [] - [view {:height (if ios? 0 8) - :background-color :white}]) - -(defn chat-shadow-item [] - (when-not ios? - [view {:height 12} - [chat-list-padding] - [linear-gradient {:style {:height 4} - :colors st/gradient-top-bottom-shadow}]])) - -(defn render-separator-fn [chats] - (fn [_ row-id _] - (list-item - (when (< row-id (dec (count chats))) - ^{:key (str "separator-" row-id)} - [view st/chat-separator-wrapper - [view st/chat-separator-item]])))) - (defview chats-list [] [chats [:filtered-chats] edit? [:get-in [:chat-list-ui-props :edit?]] @@ -102,10 +85,11 @@ [list-view {:dataSource (to-datasource chats) :renderRow (fn [[id :as row] _ _] (list-item ^{:key id} [chat-list-item row edit?])) - :renderHeader #(when (seq chats) (list-item [chat-list-padding])) - :renderFooter #(when (seq chats) (list-item [chat-shadow-item])) - :renderSeparator (when (get-in platform-specific [:chats :render-separator?]) - (render-separator-fn chats)) + :renderHeader renderers/list-header-renderer + :renderFooter #(list-item [view + [common/list-footer] + [common/bottom-shaddow]]) + :renderSeparator renderers/list-separator-renderer :style (st/list-container tabs-hidden?)}] (when (and (not edit?) (not search?) diff --git a/src/status_im/chats_list/styles.cljs b/src/status_im/chats_list/styles.cljs index 39cffe5d49..8524db3fcb 100644 --- a/src/status_im/chats_list/styles.cljs +++ b/src/status_im/chats_list/styles.cljs @@ -18,18 +18,6 @@ (merge {:background-color toolbar-background1} (get-in p/platform-specific [:component-styles :toolbar]))) - -(def gradient-top-bottom-shadow - ["rgba(24, 52, 76, 0.165)" - "rgba(24, 52, 76, 0.03)" - "rgba(24, 52, 76, 0.01)"]) - -(def chat-separator-wrapper - {:background-color color-white - :opacity 0.5 - :height 1 - :padding-left 72}) - (def chat-separator-item {:border-bottom-width 1 :border-bottom-color color-gray5}) @@ -153,13 +141,6 @@ {:flex-direction :row :padding-right 14}) -(def toolbar-btn - {:width 24 - :height 56 - :margin-left 24 - :alignItems :center - :justifyContent :center}) - (def opts-btn {:width 24 :height 24 diff --git a/src/status_im/components/action_button/styles.cljs b/src/status_im/components/action_button/styles.cljs index 9ffee17d9c..fd1cd4c17a 100644 --- a/src/status_im/components/action_button/styles.cljs +++ b/src/status_im/components/action_button/styles.cljs @@ -32,8 +32,7 @@ :font-size 17 :line-height 20} :android {:color color-black - :font-size 16 - :line-height 24}}) + :font-size 16}}) (defstyle actions-list {:background-color color-white diff --git a/src/status_im/components/common/common.cljs b/src/status_im/components/common/common.cljs index e89cc8fb2e..6b1ba9e108 100644 --- a/src/status_im/components/common/common.cljs +++ b/src/status_im/components/common/common.cljs @@ -1,5 +1,6 @@ (ns status-im.components.common.common - (:require [status-im.components.react :refer [view text linear-gradient]] + (:require [status-im.components.react :refer [view text icon linear-gradient]] + [status-im.components.context-menu :refer [context-menu]] [status-im.utils.platform :as p] [status-im.components.common.styles :as st])) @@ -28,14 +29,29 @@ (defn list-separator [] [separator st/list-separator]) -(defn form-title [label & [count-value]] +(defn list-footer [] + [view st/list-header-footer-spacing]) + +(defn list-header [] + [view st/list-header-footer-spacing]) + +(defn form-title [label & [{:keys [count-value extended? options]}]] [view [view st/form-title-container - [text {:style st/form-title - :font :medium} - label] - (when-not (nil? count-value) - [text {:style st/form-title-count - :font :medium} - count-value])] + [view st/form-title-inner-container + [text {:style st/form-title + :font :medium} + label] + (when-not (nil? count-value) + [text {:style st/form-title-count + :font :medium} + count-value])] + (when extended? + [view + [view {:flex 1}]]) + (when extended? + [view st/form-title-extend-container + [context-menu + [icon :options_gray] + options]])] [top-shaddow]]) diff --git a/src/status_im/components/common/styles.cljs b/src/status_im/components/common/styles.cljs index fc1801151a..e5921f45df 100644 --- a/src/status_im/components/common/styles.cljs +++ b/src/status_im/components/common/styles.cljs @@ -39,31 +39,50 @@ {:margin-left 72}) (defstyle form-title-container - {:padding-left 16 - :flex 1 + {:flex-direction :row}) + +(defstyle form-title-inner-container + {:padding-left 16 + :padding-right 16 + :flex 1 :flex-direction :row - :ios {:background-color color-white - :padding-top 19 - :padding-bottom 15 - :margin-top 16} - :android {:background-color color-light-gray - :padding-top 25 - :padding-bottom 18 - :margin-top 0}}) + :ios {:background-color color-white + :padding-top 19 + :padding-bottom 15 + :margin-top 16} + :android {:background-color color-light-gray + :padding-top 20 + :padding-bottom 17 + :margin-top 8}}) + +(defstyle form-title-extend-container + {:padding-right 16 + :ios {:margin-top 16 + :padding-top 16 + :background-color color-white} + :android {:margin-top 24 + :background-color color-light-gray}}) (defstyle form-title - {:ios {:color text1-color - :font-size 16} - :android {:color text4-color - :font-size 14}}) + {:flex-shrink 1 + :ios {:color text1-color + :letter-spacing -0.2 + :font-size 16} + :android {:color text4-color + :font-size 14}}) (def form-title-count (merge form-title - {:opacity 0.6 - :padding-left 8 - :color text4-color})) - + {:flex-shrink 0 + :opacity 0.6 + :padding-left 8 + :padding-right 5 + :color text4-color})) (defstyle form-spacer {:ios {:height 16} :android {:height 11}}) + +(defstyle list-header-footer-spacing + {:android {:background-color color-white + :height 8}}) \ No newline at end of file diff --git a/src/status_im/components/confirm_button.cljs b/src/status_im/components/confirm_button.cljs deleted file mode 100644 index 1becdba24d..0000000000 --- a/src/status_im/components/confirm_button.cljs +++ /dev/null @@ -1,13 +0,0 @@ -(ns status-im.components.confirm-button - (:require [status-im.components.styles :as st] - [status-im.utils.platform :refer [platform-specific]] - [status-im.components.react :refer [view - text - touchable-highlight]])) - -(defn confirm-button [label on-press] - [touchable-highlight {:on-press on-press} - [view st/confirm-button - [text {:style (get-in platform-specific [:component-styles :confirm-button-label]) - :uppercase? (get-in platform-specific [:uppercase?])} - label]]]) \ No newline at end of file diff --git a/src/status_im/components/contact/contact.cljs b/src/status_im/components/contact/contact.cljs new file mode 100644 index 0000000000..91bbf181a3 --- /dev/null +++ b/src/status_im/components/contact/contact.cljs @@ -0,0 +1,50 @@ +(ns status-im.components.contact.contact + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [status-im.components.react :refer [view icon touchable-highlight text]] + [status-im.components.chat-icon.screen :refer [contact-icon-contacts-tab]] + [status-im.components.context-menu :refer [context-menu]] + [status-im.components.contact.styles :as st] + [status-im.utils.gfycat.core :refer [generate-gfy]] + [status-im.i18n :refer [get-contact-translated label]])) + +(defn contact-photo [contact] + [view + [contact-icon-contacts-tab contact]]) + +(defn contact-inner-view + ([{:keys [info style] {:keys [whisper-identity name] :as contact} :contact}] + [view (merge st/contact-inner-container style) + [contact-photo contact] + [view st/info-container + [text {:style st/name-text + :number-of-lines 1} + (if (pos? (count (:name contact))) + (get-contact-translated whisper-identity :name name) + ;;TODO is this correct behaviour? + (generate-gfy))] + (when info + [text {:style st/info-text} + info])]])) + +(defn contact-view [{:keys [contact extended? on-press extend-options info]}] + [touchable-highlight (when-not extended? + {:on-press (when on-press #(on-press contact))}) + [view + [view st/contact-container + [contact-inner-view {:contact contact :info info}] + (when extended? + [view st/more-btn + [context-menu + [icon :options_gray] + extend-options]])]]]) + +(defview toogle-contact-view [{:keys [whisper-identity] :as contact} selected-key on-toggle-handler] + [checked [selected-key whisper-identity]] + [touchable-highlight {:on-press #(on-toggle-handler checked whisper-identity)} + [view + [view (merge st/contact-container (when checked {:style st/selected-contact})) + [contact-inner-view (merge {:contact contact} + (when checked {:style st/selected-contact}))] + [view (st/icon-check-container checked) + (when checked + [icon :check_on st/check-icon])]]]]) \ No newline at end of file diff --git a/src/status_im/components/contact/styles.cljs b/src/status_im/components/contact/styles.cljs new file mode 100644 index 0000000000..ed2aa3cfea --- /dev/null +++ b/src/status_im/components/contact/styles.cljs @@ -0,0 +1,69 @@ +(ns status-im.components.contact.styles + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) + (:require [status-im.components.styles :as common] + [status-im.utils.platform])) + +(defstyle contact-inner-container + {:flex 1 + :flexDirection :row + :align-items :center + :padding-left 16 + :backgroundColor common/color-white + :android {:height 56} + :ios {:height 63}}) + +(def info-container + {:flex 1 + :flexDirection :column + :margin-left 16 + :margin-right 5 + :justify-content :center}) + +(defstyle name-text + {:color common/text1-color + :android {:fontSize 16 + :line-height 24} + :ios {:fontSize 17 + :line-height 20 + :letter-spacing -0.2}}) + +(def info-text + {:marginTop 1 + :fontSize 12 + :color common/text2-color}) + +(def contact-container + {:flex-direction :row + :align-items :center + :background-color common/color-white + :padding-right 16}) + +(def more-btn + {:width 24 + :height 24 + :alignItems :center + :justifyContent :center}) + +(def selected-contact + {:background-color common/selected-contact-color}) + +(def toggle-container + {:width 56 + :height 56 + :alignItems :center + :justifyContent :center}) + +(defnstyle icon-check-container [checked] + {:background-color (if checked common/color-light-blue common/color-gray5) + :alignItems :center + :justifyContent :center + :android {:border-radius 2 + :width 17 + :height 17} + :ios {:border-radius 50 + :width 24 + :height 24}}) + +(def check-icon + {:width 12 + :height 12}) \ No newline at end of file diff --git a/src/status_im/components/context_menu.cljs b/src/status_im/components/context_menu.cljs index aea5ccbf64..0248bdf18f 100644 --- a/src/status_im/components/context_menu.cljs +++ b/src/status_im/components/context_menu.cljs @@ -1,6 +1,6 @@ (ns status-im.components.context-menu (:require [reagent.core :as r] - [status-im.components.styles :as st] + [status-im.components.styles :as common] [status-im.i18n :refer [label]] [status-im.utils.platform :refer [platform-specific ios?]] [re-frame.core :refer [dispatch]] @@ -24,6 +24,26 @@ (def menu-options (get-class "MenuOptions")) (def menu-option (get-class "MenuOption")) +(defn context-menu-options [custom-styles] + {:customStyles {:optionsContainer + (merge {:elevation 2 + :margin-top 30 + :padding-top 8 + :width 164 + :padding-bottom 8} + (:optionsContainer custom-styles)) + :optionWrapper + (merge {:padding-left 16 + :padding-right 16 + :justify-content :center + :height 48} + (:optionWrapper custom-styles))}}) + +(defn context-menu-text [destructive?] + {:font-size 15 + :line-height 20 + :color (if destructive? common/color-light-red common/text1-color)}) + (def list-selection-fn (:list-selection-fn platform-specific)) (defn open-ios-menu [options] @@ -42,9 +62,9 @@ trigger]] [menu {:onSelect #(when % (do (%) nil))} [menu-trigger trigger] - [menu-options (st/context-menu-options customStyles) + [menu-options (context-menu-options customStyles) (for [{:keys [style value destructive?] :as option} options] ^{:key option} [menu-option {:value value} - [text {:style (merge (st/context-menu-text destructive?) style)} + [text {:style (merge (context-menu-text destructive?) style)} (:text option)]])]])) diff --git a/src/status_im/components/renderers/renderers.cljs b/src/status_im/components/renderers/renderers.cljs new file mode 100644 index 0000000000..ddf3c8d650 --- /dev/null +++ b/src/status_im/components/renderers/renderers.cljs @@ -0,0 +1,14 @@ +(ns status-im.components.renderers.renderers + (:require [status-im.components.react :refer [list-item]] + [status-im.components.common.common :as common])) + +(defn list-separator-renderer [_ row-id _] + (list-item + ^{:key row-id} + [common/list-separator])) + +(defn list-header-renderer [& _] + (list-item [common/list-header])) + +(defn list-footer-renderer [& _] + (list-item [common/list-footer])) diff --git a/src/status_im/components/sticky_button.cljs b/src/status_im/components/sticky_button.cljs new file mode 100644 index 0000000000..85c53ac5fd --- /dev/null +++ b/src/status_im/components/sticky_button.cljs @@ -0,0 +1,29 @@ +(ns status-im.components.sticky-button + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) + (:require [status-im.components.styles :as common] + [status-im.utils.platform :refer [platform-specific]] + [status-im.components.react :refer [view + text + touchable-highlight]])) + +(def sticky-button-style + {:flex-direction :row + :height 52 + :justify-content :center + :align-items :center + :background-color common/color-light-blue}) + +(defstyle sticky-button-label-style + {:color common/color-white + :ios {:font-size 17 + :line-height 20 + :letter-spacing -0.2} + :android {:font-size 14 + :letter-spacing 0.5}}) + +(defn sticky-button [label on-press] + [touchable-highlight {:on-press on-press} + [view sticky-button-style + [text {:style sticky-button-label-style + :uppercase? (get-in platform-specific [:uppercase?])} + label]]]) \ No newline at end of file diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 142b2d7d28..972d71c7ef 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -91,30 +91,3 @@ (def button-input {:flex 1 :flexDirection :column}) - -(def confirm-button - {:flex-direction :row - :height 52 - :justify-content :center - :align-items :center - :background-color color-light-blue}) - -(defn context-menu-options [custom-styles] - {:customStyles {:optionsContainer - (merge {:elevation 2 - :margin-top 30 - :padding-top 8 - :width 164 - :padding-bottom 8} - (:optionsContainer custom-styles)) - :optionWrapper - (merge {:padding-left 16 - :padding-right 16 - :justify-content :center - :height 48} - (:optionWrapper custom-styles))}}) - -(defn context-menu-text [destructive?] - {:font-size 15 - :line-height 20 - :color (if destructive? color-light-red text1-color)}) diff --git a/src/status_im/contacts/default_contacts.cljs b/src/status_im/contacts/default_contacts.cljs deleted file mode 100644 index dc6e976f9d..0000000000 --- a/src/status_im/contacts/default_contacts.cljs +++ /dev/null @@ -1,17 +0,0 @@ -(ns status-im.contacts.default-contacts - (:require [status-im.constants :refer [wallet-chat-id]] - [clojure.string :as s])) - -(def contacts - [{:whisper-identity wallet-chat-id - :name (s/capitalize wallet-chat-id) - :photo-path :icon_wallet_avatar - :dapp? true - :add-chat? true} - - {:whisper-identity "dapp-auction" - :name "Auction House" - :photo-path "http://auctionhouse.dappbench.com/images/auctionhouse.png" - :dapp? true - :dapp-url "http://auctionhouse.dappbench.com"} - ]) diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index c75e4a09c4..37ffa5b52f 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -380,3 +380,10 @@ :new-chat-name "") (assoc-in [:toolbar-search :show] nil) (assoc-in [:toolbar-search :text] "")))) + +(register-handler :open-chat-with-contact + (u/side-effect! + (fn [_ [_ {:keys [whisper-identity] :as contact}]] + (dispatch [:send-contact-request! contact]) + (dispatch [:navigate-to-clean :chat-list]) + (dispatch [:start-chat whisper-identity {}])))) \ No newline at end of file diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index a8ef755d26..1c7993c11a 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -1,9 +1,7 @@ (ns status-im.contacts.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [reagent.core :as r] - [clojure.string :as str] - [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.components.common.common :refer [separator top-shaddow bottom-shaddow]] + (:require [re-frame.core :refer [dispatch]] + [status-im.components.common.common :as common] [status-im.components.react :refer [view text image @@ -11,18 +9,17 @@ touchable-highlight scroll-view list-view - list-item] :as react] + list-item]] [status-im.components.native-action-button :refer [native-action-button native-action-button-item]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar]] [status-im.components.toolbar-new.actions :as act] - [status-im.components.toolbar-new.styles :as tst] [status-im.components.drawer.view :refer [open-drawer]] [status-im.components.icons.custom-icons :refer [ion-icon]] [status-im.components.context-menu :refer [context-menu]] - [status-im.contacts.views.contact :refer [contact-view]] - [status-im.utils.platform :refer [platform-specific]] + [status-im.components.contact.contact :refer [contact-view]] + [status-im.utils.platform :refer [platform-specific ios? android?]] [status-im.i18n :refer [label]] [status-im.contacts.styles :as st] [status-im.components.styles :refer [color-blue @@ -37,9 +34,8 @@ {:text (label :t/reorder-groups) :value #(dispatch [:navigate-to :reorder-groups])}]) (defn toolbar-actions [] - (let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?])] - [(act/search #(dispatch [:navigate-to :group-contacts nil :show-search])) - (act/opts (if new-contact? toolbar-options (rest toolbar-options)))])) + [(act/search #(dispatch [:navigate-to :group-contacts nil :show-search])) + (act/opts (if ios? toolbar-options (rest toolbar-options)))]) (defn toolbar-view [] [toolbar {:title (label :t/contacts) @@ -51,37 +47,29 @@ :actions [{:image :blank}] :title (label :t/edit-contacts)}]) -(defn options-btn [group] - (let [options [{:value #(dispatch [:navigate-to :edit-group group :contact-group]) - :text (label :t/edit-group)}]] - [view st/more-btn - [context-menu - [icon :options_gray] - options]])) +(defn contact-options [contact group] + (let [options [{:value #(dispatch [:hide-contact contact]) + :text (label :t/delete-contact) + :destructive? true}]] + (if group + (conj options + {:value #(dispatch [:remove-contact-from-group + (:whisper-identity contact) + (:group-id group)]) + :text (label :t/remove-from-group)}) + options))) -(defn subtitle-view [subtitle contacts-count group extended?] - [view (get-in platform-specific [:component-styles :contacts :group-header]) - [text {:style (get-in platform-specific [:component-styles :contacts :subtitle]) - :font :medium} - subtitle] - [text {:style (merge st/contact-group-count - (get-in platform-specific [:component-styles :contacts :subtitle-count])) - :uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?]) - :font :medium} - (str contacts-count)] - [view {:flex 1}] - (when extended? - [options-btn group])]) - -(defn contact-group-form [{:keys [contacts contacts-count group edit?]}] +(defn contact-group-form [{:keys [contacts contacts-count group edit? click-handler]}] (let [subtitle (:name group)] - [view st/contact-group + [view (when subtitle - [subtitle-view subtitle contacts-count group edit?]) - (when subtitle - [top-shaddow]) + [common/form-title subtitle + {:count-value contacts-count + :extended? edit? + :options [{:value #(dispatch [:navigate-to :edit-group group :contact-group]) + :text (label :t/edit-group)}]}]) [view st/contacts-list - [view st/contact-list-spacing] + [common/list-footer] (doall (map (fn [contact] ^{:key contact} @@ -89,20 +77,14 @@ [contact-view {:contact contact :extended? edit? - :extend-options (when group - [{:value #(dispatch [:hide-contact contact]) - :text (label :t/delete-contact) - :destructive? true} - {:value #(dispatch [:remove-contact-from-group - (:whisper-identity contact) - (:group-id group)]) - :text (label :t/remove-from-group)}])}] + :on-press #(dispatch [:open-chat-with-contact %]) + :extend-options (contact-options contact group)}] (when-not (= contact (last contacts)) - [separator st/contact-item-separator])]) + [common/list-separator])]) contacts))] (when (< contacts-limit contacts-count) [view - [separator st/contact-item-separator] + [common/list-separator] [view st/show-all [touchable-highlight {:on-press #(do (when edit? @@ -113,7 +95,7 @@ :uppercase? (get-in platform-specific [:uppercase?]) :font (get-in platform-specific [:component-styles :contacts :show-all-text-font])} (str (- contacts-count contacts-limit) " " (label :t/more))]]]]]) - [bottom-shaddow]])) + [common/bottom-shaddow]])) (defview contact-group-view [{:keys [group] :as params}] [contacts [:all-added-group-contacts-with-limit (:group-id group) contacts-limit] @@ -134,7 +116,7 @@ [ion-icon {:name :md-create :style create-icon}]]]) -(defview contact-list [current-view?] +(defview contact-list [_] [contacts [:get-added-contacts-with-limit contacts-limit] contacts-count [:added-contacts-count] edit? [:get-in [:contacts-ui-props :edit?]] @@ -156,7 +138,7 @@ [contact-group-view {:group group :edit? edit?}])] [view st/empty-contact-groups - [react/icon :group_big st/empty-contacts-icon] + [icon :group_big st/empty-contacts-icon] [text {:style st/empty-contacts-text} (label :t/no-contacts)]])] - (when (and (not edit?) (get-in platform-specific [:contacts :action-button?])) + (when (and android? (not edit?)) [contacts-action-button])]) diff --git a/src/status_im/contacts/search_results.cljs b/src/status_im/contacts/search_results.cljs deleted file mode 100644 index 55e47fb96d..0000000000 --- a/src/status_im/contacts/search_results.cljs +++ /dev/null @@ -1,36 +0,0 @@ -(ns status-im.contacts.search-results - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.components.status-bar :refer [status-bar]] - [status-im.components.react :refer [view - text - icon - list-view - list-item]] - [status-im.components.toolbar.view :refer [toolbar]] - [status-im.components.toolbar.actions :as act] - [status-im.contacts.views.contact :refer [contact-view]] - [status-im.utils.listview :refer [to-datasource]] - [status-im.utils.platform :refer [platform-specific]] - [status-im.i18n :refer [label]] - [status-im.contacts.styles :as st])) - -(defview contacts-search-results [] - [search-text [:get :contact-list-search-text] - contacts [:contacts-with-letters]] - [view st/search-container - [status-bar] - [toolbar {:nav-action (act/back #(dispatch [:navigate-back])) - :title search-text - :style (get-in platform-specific [:component-styles :toolbar])}] - (if (empty? contacts) - [view st/search-empty-view - ;; todo change icon - [icon :group_big st/empty-contacts-icon] - [text {:style st/empty-contacts-text} - "No contacts found"]] - [list-view {:dataSource (to-datasource contacts) - :renderRow (fn [row _ _] - (list-item [contact-view {:contact row - :letter? true - :extended? true}]))}])]) diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index 8552a93ec8..a0b2faeb42 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -1,18 +1,7 @@ (ns status-im.contacts.styles - (:require-macros [status-im.utils.styles :refer [defnstyle]]) - (:require [status-im.components.styles :refer [text1-color - text2-color - text3-color - color-white - color-separator - color-gray2 - color-gray4 - color-blue - color-light-red - color-gray]] - [status-im.components.toolbar.styles :refer [toolbar-background1 toolbar-background2]] - [status-im.components.tabs.styles :as tabs-st] - [status-im.utils.platform :as p])) + (:require-macros [status-im.utils.styles :refer [defnstyle defstyle]]) + (:require [status-im.components.styles :as common] + [status-im.components.tabs.styles :as tabs-st])) ;; Contacts list @@ -21,7 +10,7 @@ (def contact-groups {:flex 1 - :background-color toolbar-background2}) + :background-color common/color-light-gray}) (defnstyle contacts-list-container [tabs-hidden?] {:flex 1 @@ -29,10 +18,10 @@ :ios {:margin-bottom (if tabs-hidden? 20 (+ 16 tabs-st/tabs-height))}}) (def contacts-list - {:background-color color-white}) + {:background-color common/color-white}) (def contacts-list-modal - {:background-color toolbar-background2}) + {:background-color common/color-light-gray}) (def empty-contact-groups (merge contact-groups @@ -46,55 +35,27 @@ (def empty-contacts-text {:margin-top 12 :font-size 16 - :color color-gray2}) - -(def contact-group - {:flex-direction :column}) + :color common/color-gray2}) (def contact-group-count {:margin-left 8 :opacity 0.6}) -(def show-all - (merge (get-in p/platform-specific [:component-styles :contacts :show-all]) - {:flexDirection :row - :alignItems :center - :backgroundColor color-white})) +(defstyle show-all + {:flexDirection :row + :alignItems :center + :backgroundColor common/color-white + :padding-left 72 + :android {:height 56} + :ios {:height 64}}) -(def show-all-text - (get-in p/platform-specific [:component-styles :contacts :show-all-text])) - -(def contact-item-separator - {:margin-left 72}) - -(def contact-container - (merge (get-in p/platform-specific [:component-styles :contacts :contact-container]) - {:flex-direction :row - :align-items :center - :background-color color-white})) - -(def letter-container - {:paddingTop 11 - :paddingLeft 20 - :width 56}) - -(def letter-text - {:fontSize 24 - :color text3-color}) - -(def option-inner-container - {:flex 1 - :flex-direction :row - :height 56 - :background-color color-white - :border-bottom-color color-separator - :border-bottom-width 0.5}) - -(def option-inner - {:width 48 - :height 48 - :margin-top 4 - :margin-left 12}) +(defstyle show-all-text + {:android {:fontSize 14 + :color common/color-blue + :letter-spacing 0.5} + :ios {:fontSize 16 + :color common/color-gray4 + :letter-spacing -0.2}}) (def option-inner-image {:width 24 @@ -104,38 +65,7 @@ (def group-icon (assoc option-inner-image - :tint-color color-gray)) - -(def contact-list-spacing - (get-in p/platform-specific [:component-styles :contacts :contact-list-spacing])) - -(def contact-inner-container - (merge (get-in p/platform-specific [:component-styles :contacts :contact-inner-container]) - {:flex 1 - :flexDirection :row - :align-items :center - :padding-left 16 - :backgroundColor color-white})) - -(def info-container - (merge (get-in p/platform-specific [:component-styles :contacts :info-container]) - {:flex 1 - :flexDirection :column})) - -(def name-text - (get-in p/platform-specific [:component-styles :contacts :name-text])) - -(def info-text - {:marginTop 1 - :fontSize 12 - :color text2-color}) - -(def more-btn - {:width 24 - :height 24 - :margin-left 16 - :alignItems :center - :justifyContent :center}) + :tint-color common/color-gray)) ; New contact @@ -164,33 +94,17 @@ (def address-explication {:textAlign :center - :color color-gray}) + :color common/color-gray}) (def qr-input {:margin-right 42}) -(def enter-address-icon - {:margin-left 21 - :margin-right 21 - :margin-top 19 - :width 20 - :height 18}) - -(def scan-qr-icon - {:margin-left 21 - :margin-right 20 - :margin-top 18 - :width 20 - :height 20}) - -;; Contacts search - (def search-container {:flex 1 - :background-color color-white}) + :background-color common/color-white}) (def search-empty-view {:flex 1 - :background-color color-white + :background-color common/color-white :align-items :center :justify-content :center}) diff --git a/src/status_im/contacts/views/contact.cljs b/src/status_im/contacts/views/contact.cljs deleted file mode 100644 index c8bd2af14c..0000000000 --- a/src/status_im/contacts/views/contact.cljs +++ /dev/null @@ -1,44 +0,0 @@ -(ns status-im.contacts.views.contact - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [status-im.components.react :refer [view text icon touchable-highlight]] - [re-frame.core :refer [dispatch]] - [status-im.contacts.styles :as st] - [status-im.contacts.views.contact-inner :refer [contact-inner-view]] - [status-im.components.context-menu :refer [context-menu]] - [status-im.i18n :refer [label]] - [status-im.utils.platform :refer [platform-specific]])) - -(defn- on-press [{:keys [whisper-identity] :as contact}] - (dispatch [:send-contact-request! contact]) - (dispatch [:navigate-to-clean :chat-list]) - (dispatch [:start-chat whisper-identity {}])) - -(defn letter-view [letter] - [view st/letter-container - (when letter - [text {:style st/letter-text} letter])]) - -(defn options-btn [contact more-options] - (let [options [{:value #(dispatch [:hide-contact contact]) - :text (label :t/delete-contact) - :destructive? true}]] - [view st/more-btn - [context-menu - [icon :options_gray] - (or more-options options)]])) - -;;TODO: maybe it's better to have only one global component contact-view with the types: default, extended and toggle -;;TODO: at the moment toggle in the other component new-group-contact -(defview contact-view [{{:keys [whisper-identity letter] :as contact} :contact - :keys [extended? letter? on-click extend-options info]}] - [chat [:get-chat whisper-identity]] - [touchable-highlight - (when-not extended? - {:on-press #((or on-click on-press) contact)}) - [view - [view st/contact-container - (when letter? - [letter-view letter]) - [contact-inner-view {:contact contact :info info}] - (when extended? - [options-btn contact extend-options])]]]) diff --git a/src/status_im/contacts/views/contact_inner.cljs b/src/status_im/contacts/views/contact_inner.cljs deleted file mode 100644 index 752c7a3752..0000000000 --- a/src/status_im/contacts/views/contact_inner.cljs +++ /dev/null @@ -1,25 +0,0 @@ -(ns status-im.contacts.views.contact-inner - (:require [status-im.components.react :refer [view image text]] - [status-im.components.chat-icon.screen :refer [contact-icon-contacts-tab]] - [status-im.contacts.styles :as st] - [status-im.utils.gfycat.core :refer [generate-gfy]] - [status-im.i18n :refer [get-contact-translated label]])) - -(defn contact-photo [contact] - [view - [contact-icon-contacts-tab contact]]) - -(defn contact-inner-view - ([{:keys [info style] {:keys [whisper-identity name] :as contact} :contact}] - [view (merge st/contact-inner-container style) - [contact-photo contact] - [view st/info-container - [text {:style st/name-text - :number-of-lines 1} - (if (pos? (count (:name contact))) - (get-contact-translated whisper-identity :name name) - ;; todo is this correct behaviour? - (generate-gfy))] - (when info - [text {:style st/info-text} - info])]])) diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index 9883d5b500..af0e02e44c 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -1,14 +1,16 @@ (ns status-im.contacts.views.contact-list (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.components.common.common :refer [separator]] + [status-im.components.common.common :as common] + [status-im.components.renderers.renderers :as renderers] + [status-im.components.contact.contact :refer [contact-view]] + [status-im.contacts.screen :refer [contact-options]] [status-im.components.react :refer [view text image icon touchable-highlight list-view list-item]] - [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.text-field.view :refer [text-field]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search toolbar]] @@ -26,15 +28,9 @@ (list-item ^{:key row} [contact-view {:contact row + :on-press #(dispatch [:open-chat-with-contact %]) :extended? edit? - :extend-options (when group - [{:value #(dispatch [:hide-contact row]) - :text (label :t/delete-contact) - :destructive? true} - {:value #(dispatch [:remove-contact-from-group - (:whisper-identity row) - (:group-id group)]) - :text (label :t/remove-from-group)}])}]))) + :extend-options (contact-options row group)}]))) (defview contact-list-toolbar-edit [group] [toolbar {:nav-action (act/back #(dispatch [:set-in [:contact-list-ui-props :edit?] false])) @@ -57,20 +53,15 @@ :actions [(act/opts [{:text (label :t/edit) :value #(dispatch [:set-in [:contact-list-ui-props :edit?] true])}])]})) -(defn render-separator [_ row-id _] - (list-item ^{:key row-id} - [separator st/contact-item-separator])) - (defview contacts-list-view [group edit?] [contacts [:all-added-group-contacts-filtered (:group-id group)]] [list-view {:dataSource (lw/to-datasource contacts) :enableEmptySections true :renderRow (render-row group edit?) - :bounces false :keyboardShouldPersistTaps true - :renderHeader #(list-item [view st/contact-list-spacing]) - :renderFooter #(list-item [view st/contact-list-spacing]) - :renderSeparator render-separator + :renderHeader renderers/list-header-renderer + :renderFooter renderers/list-footer-renderer + :renderSeparator renderers/list-separator-renderer :style st/contacts-list}]) (defview contact-list [] diff --git a/src/status_im/contacts/views/contact_list_modal.cljs b/src/status_im/contacts/views/contact_list_modal.cljs index be52833d56..c1ceec9a8b 100644 --- a/src/status_im/contacts/views/contact_list_modal.cljs +++ b/src/status_im/contacts/views/contact_list_modal.cljs @@ -1,14 +1,15 @@ (ns status-im.contacts.views.contact-list-modal (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.components.common.common :refer [list-separator form-title bottom-shaddow]] + (:require [re-frame.core :refer [dispatch]] + [status-im.components.common.common :as common] + [status-im.components.renderers.renderers :as renderers] [status-im.components.react :refer [view text image icon touchable-highlight list-view list-item]] - [status-im.contacts.views.contact :refer [contact-view]] + [status-im.components.contact.contact :refer [contact-view]] [status-im.components.action-button.action-button :refer [action-button action-separator]] [status-im.components.action-button.styles :refer [actions-list]] @@ -16,17 +17,10 @@ [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search toolbar]] [status-im.components.toolbar-new.actions :as act] - [status-im.components.toolbar-new.styles :refer [toolbar-background1]] - [status-im.components.drawer.view :refer [drawer-view open-drawer]] - [status-im.components.image-button.view :refer [scan-button]] + [status-im.components.drawer.view :refer [drawer-view]] [status-im.contacts.styles :as st] [status-im.utils.listview :as lw] - [status-im.i18n :refer [label]] - [status-im.utils.platform :refer [platform-specific]])) - -(defn render-separator [_ row-id _] - (list-item ^{:key row-id} - [list-separator])) + [status-im.i18n :refer [label]])) (defview contact-list-modal-toolbar [] [show-search [:get-in [:toolbar-search :show]] @@ -60,7 +54,7 @@ (list-item ^{:key row} [contact-view {:contact row - :on-click #(when click-handler + :on-press #(when click-handler (click-handler row action params))}]))) (defview contact-list-modal [] @@ -80,11 +74,12 @@ :renderHeader #(list-item [view [actions-view action click-handler] - [bottom-shaddow] - [form-title (label :t/choose-from-contacts) (count contacts)] - [view st/contact-list-spacing]]) + [common/bottom-shaddow] + [common/form-title (label :t/choose-from-contacts) + {:count-value (count contacts)}] + [common/list-header]]) :renderFooter #(list-item [view - [view st/contact-list-spacing] - [bottom-shaddow]]) - :renderSeparator render-separator + [common/list-footer] + [common/bottom-shaddow]]) + :renderSeparator renderers/list-separator-renderer :style st/contacts-list-modal}]]]) diff --git a/src/status_im/group_settings/screen.cljs b/src/status_im/group_settings/screen.cljs deleted file mode 100644 index 0bb40c0c44..0000000000 --- a/src/status_im/group_settings/screen.cljs +++ /dev/null @@ -1,174 +0,0 @@ -(ns status-im.group-settings.screen - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.components.react :refer [view - text-input - text - image - icon - modal - picker - picker-item - scroll-view - touchable-highlight]] - [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar]] - [status-im.components.chat-icon.screen :refer [chat-icon-view-action]] - [status-im.group-settings.styles.group-settings :as st] - [status-im.group-settings.views.member :refer [member-view]] - [status-im.i18n :refer [label]] - [status-im.group-settings.views.color-settings :refer [color-settings]])) - -(defn remove-member [] - (dispatch [:remove-participants])) - -(defn close-member-menu [] - (dispatch [:set :selected-participants #{}])) - -;; TODO not in design -(defview member-menu [] - [{:keys [name] :as participant} [:selected-participant]] - (when participant - [modal {:animationType :none - :transparent false - :onRequestClose close-member-menu} - [touchable-highlight {:style st/modal-container - :on-press close-member-menu} - [view st/modal-inner-container - [text {:style st/modal-member-name} name] - [touchable-highlight {:on-press remove-member} - [view - [text {:style st/modal-remove-text} - (label :t/remove)]]]]]])) - -(defview chat-members [] - [members [:current-chat-contacts]] - [view st/chat-members-container - (for [member members] - ^{:key member} [member-view member])]) - -(defn setting-view [{:keys [icon-style custom-icon handler title subtitle] - icon-name :icon}] - [touchable-highlight {:on-press handler} - [view st/setting-row - [view st/setting-icon-view - (or custom-icon - [icon icon-name icon-style])] - [view st/setting-view - [text {:style st/setting-title} title] - (when-let [subtitle subtitle] - [text {:style st/setting-subtitle} - subtitle])]]]) - -(defview chat-color-icon [] - [chat-color [:chat :color]] - [view {:style (st/chat-color-icon chat-color)}]) - -(defn show-chat-color-picker [] - (dispatch [:group-settings :show-color-picker true])) - -(defn settings-view [] - (let [settings [{:custom-icon [chat-color-icon] - :title (label :t/change-color) - :handler show-chat-color-picker} - ;; TODO not implemented: Notifications - (merge {:title (label :t/notifications-title) - :subtitle (label :t/not-implemented) - :handler nil} - (if true - {:icon :notifications-on - :icon-style {:width 16 - :height 21}} - {:icon :muted - :icon-style {:width 18 - :height 21}})) - {:icon :close-gray - :icon-style {:width 12 - :height 12} - :title (label :t/clear-history) - ;; TODO show confirmation dialog? - :handler #(dispatch [:clear-history])} - {:icon :bin - :icon-style {:width 12 - :height 18} - :title (label :t/delete-and-leave) - ;; TODO show confirmation dialog? - :handler #(dispatch [:leave-group-chat])}]] - [view st/settings-container - (for [setting settings] - ^{:key setting} [setting-view setting])])) - -(defview chat-icon [] - [chat-id [:chat :chat-id] - group-chat [:chat :group-chat] - name [:chat :name] - color [:chat :color]] - [view st/action - [chat-icon-view-action chat-id group-chat name color false]]) - -(defn new-group-toolbar [] - [view - [status-bar] - [toolbar {:title (label :t/chat-settings) - :custom-action [chat-icon]}]]) - -(defn focus [] - (dispatch [:set ::name-input-focused true])) - -(defn blur [] - (dispatch [:set ::name-input-focused false])) - -(defn save [] - (dispatch [:set-chat-name])) - -(defview chat-name [] - [name [:chat :name] - new-name [:get :new-chat-name] - validation-messages [:new-chat-name-validation-messages] - focused? [:get ::name-input-focused] - valid? [:new-chat-name-valid?]] - [view - [text {:style st/chat-name-text} (label :t/chat-name)] - [view (st/chat-name-value-container focused?) - [text-input {:style st/chat-name-value - :ref #(when (and % focused?) (.focus %)) - :on-change-text #(dispatch [:set :new-chat-name %]) - :on-focus focus - :on-blur blur} - name] - (if (or focused? (not= name new-name)) - [touchable-highlight {:style (st/chat-name-btn-edit-container valid?) - :on-press save} - [view [icon :ok_purple st/add-members-icon]]] - [touchable-highlight {:style (st/chat-name-btn-edit-container true) - :on-press focus} - [view [text {:style st/chat-name-btn-edit-text} (label :t/edit)]]])] - (when (pos? (count validation-messages)) - [text {:style st/chat-name-validation-message} (first validation-messages)])]) - -(defview members [] - [current-pk [:get :current-public-key] - group-admin [:chat :group-admin]] - (when (= current-pk group-admin) - [view - [text {:style st/members-text} (label :t/members-title)] - [touchable-highlight {:on-press #(dispatch [:navigate-to :add-participants])} - ;; TODO add participants view is not in design - [view st/add-members-container - [icon :add_gray st/add-members-icon] - [text {:style st/add-members-text} - (label :t/add-members)]]] - [chat-members]])) - -(defview group-settings [] - [public? [:chat :public?]] - [view st/group-settings - [new-group-toolbar] - [scroll-view st/body - (when-not public? [chat-name]) - [members] - [text {:style st/settings-text} - (label :t/settings)] - [settings-view]] - [color-settings] - [member-menu]]) diff --git a/src/status_im/group_settings/styles/color_settings.cljs b/src/status_im/group_settings/styles/color_settings.cljs deleted file mode 100644 index 1180edfe55..0000000000 --- a/src/status_im/group_settings/styles/color_settings.cljs +++ /dev/null @@ -1,78 +0,0 @@ -(ns status-im.group-settings.styles.color-settings) - -(def color-highlight - {:flex 0.25}) - -(def color-icon-comtainer - {:justify-content :center - :align-items :center}) - -(defn color-item [color] - {:width 70 - :height 70 - :border-radius 70 - :background-color color - :justify-content :center - :align-items :center}) - -(def icon-ok - {:width 17.5 - :height 13.5}) - -(def container-height 225) - -(def label-container-top-margin 16) -(def label-container-bottom-margin 8) -(def font-size 16) - -(def color-settings-container - {:position :absolute - :right 0 - :left 0 - :bottom 0 - :height container-height - :background-color :white - :border-top-color :#0000001f - :border-top-width 1 - :align-items :stretch}) - -(def label-container - {:margin-top label-container-top-margin - :align-items :center - :margin-bottom 8}) - -(def label - {:font-size 16 - :color :black}) - -(def close-highlight - {:position :absolute - :bottom (- container-height 15 - label-container-top-margin - label-container-bottom-margin) - :right 18}) - -(def close-container-size 24) -(def close-settings-container - {:width close-container-size - :height close-container-size - :justify-content :center - :align-items :center}) - -(def close-icon - {:width 12 - :height 12}) - -(def all-colors-container - {:flex-direction :column - :align-items :stretch - :height (- container-height - label-container-top-margin - font-size - close-container-size)}) - -(def color-container - {:flex 0.5 - :flex-direction :row - :align-items :center - :justify-content :center}) diff --git a/src/status_im/group_settings/styles/group_settings.cljs b/src/status_im/group_settings/styles/group_settings.cljs deleted file mode 100644 index 3e98cf9547..0000000000 --- a/src/status_im/group_settings/styles/group_settings.cljs +++ /dev/null @@ -1,163 +0,0 @@ -(ns status-im.group-settings.styles.group-settings - (:require [status-im.components.styles :refer [color-white - color-purple - separator-color - text1-color - text2-color]])) - -(def modal-container - {:flex 1 - :justifyContent :center - :padding 20}) - -(def modal-inner-container - {:borderRadius 10 - :alignItems :center - :padding 5 - :backgroundColor color-white}) - -(def modal-member-name - {:color text2-color - :fontSize 14 - :lineHeight 20}) - -(def modal-remove-text - {:margin 10 - :color text1-color - :fontSize 14 - :lineHeight 20}) - -(def modal-color-picker-inner-container - {:borderRadius 10 - :padding 5 - :backgroundColor color-white}) - -(def modal-color-picker-save-btn-text - {:margin 10 - :alignSelf :center - :color text1-color - :fontSize 14 - :lineHeight 20}) - -(def chat-members-container - {:marginBottom 10}) - -(def action - {:width 56 - :height 56 - :alignItems :center - :justifyContent :center}) - -(def group-settings - {:flex 1 - :flexDirection :column - :backgroundColor color-white}) - -(def body - {:flex 1 - :flexDirection :column}) - -(def chat-name-text - {:marginTop 24 - :marginLeft 16 - :marginBottom 16 - :color text2-color - :fontSize 14 - :lineHeight 20}) - -(defn chat-name-value-container [focused?] - {:flexDirection :row - :marginLeft 16 - :height 56 - :alignItems :center - :justifyContent :center - :borderBottomWidth 2 - :borderBottomColor (if focused? color-purple separator-color)}) - -(def chat-name-value - {:flex 1 - :fontSize 16 - :color text1-color}) - -(def chat-name-validation-message - {:marginTop 8 - :marginLeft 16 - :color :red}) - -(defn chat-name-btn-edit-container [enabled?] - {:padding 16 - :justifyContent :center - :opacity (if enabled? 1 0.3)}) - -(def chat-name-btn-edit-text - {:color text2-color - :fontSize 16 - :lineHeight 20}) - -(def members-text - {:marginTop 24 - :marginLeft 16 - :marginBottom 16 - :color text2-color - :fontSize 14 - :lineHeight 20}) - -(def add-members-icon - {:marginVertical -1 - :marginLeft 19 - :marginHorizontal 3 - :width 17 - :height 17}) - -(def add-members-container - {:flexDirection :row}) - -(def add-members-text - {:marginTop 18 - :marginLeft 32 - :color text2-color - :fontSize 16 - :lineHeight 20}) - -(def settings-text - {:marginTop 24 - :marginLeft 16 - :marginBottom 16 - :color text2-color - :fontSize 14 - :lineHeight 20}) - -(def settings-container - {:flexDirection :column}) - -(def setting-row - {:flexDirection :row - :height 56}) - -(def setting-icon-view - {:width 56 - :height 56 - :alignItems :center - :justifyContent :center}) - -(def setting-view - {:flex 1 - :marginLeft 16 - :alignItems :flex-start - :justifyContent :center}) - -(def setting-title - {:marginTop -2.5 - :color text1-color - :fontSize 16}) - -(def setting-subtitle - {:marginTop 1 - :color text2-color - :fontSize 12}) - -(defn chat-color-icon [color] - {:borderRadius 12 - :width 24 - :height 24 - :backgroundColor color}) diff --git a/src/status_im/group_settings/views/color_settings.cljs b/src/status_im/group_settings/views/color_settings.cljs deleted file mode 100644 index 7c305f8b87..0000000000 --- a/src/status_im/group_settings/views/color_settings.cljs +++ /dev/null @@ -1,48 +0,0 @@ -(ns status-im.group-settings.views.color-settings - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [dispatch]] - [status-im.components.react :refer [view - text - icon - touchable-highlight]] - [status-im.i18n :refer [label]] - [status-im.group-settings.styles.color-settings :as st])) - -(defn close-chat-color-picker [] - (dispatch [:group-settings :show-color-picker false])) - -(def all-colors - (->> [:#a187d5 :#7099e6 :#424874 :#96c0b7 - :#d3b99f :#eb6464 :#6d98ba :#c17767] - (partition 4) - (map-indexed vector))) - -(defn color-icon [current-color color] - (let [selected-color? (= (keyword current-color) color)] - [touchable-highlight - {:on-press #(dispatch [:set-chat-color color]) - :style st/color-highlight} - [view st/color-icon-comtainer - [view (st/color-item color) - (when selected-color? - [icon :ok st/icon-ok])]]])) - -(defview color-settings [] - [show-color-picker [:group-settings :show-color-picker] - current-color [:chat :color]] - (when show-color-picker - [view st/color-settings-container - [view st/label-container - [text st/label (label :t/change-color)]] - [touchable-highlight - {:on-press close-chat-color-picker - :style st/close-highlight} - [view st/close-settings-container - [icon :close_gray st/close-icon]]] - [view st/all-colors-container - (for [[idx colors] all-colors] - ^{:key idx} - [view st/color-container - (for [color (take-last 4 colors)] - ^{:key color} - [color-icon current-color color])])]])) diff --git a/src/status_im/group_settings/views/member.cljs b/src/status_im/group_settings/views/member.cljs deleted file mode 100644 index e2edc020d7..0000000000 --- a/src/status_im/group_settings/views/member.cljs +++ /dev/null @@ -1,12 +0,0 @@ -(ns status-im.group-settings.views.member - (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.contacts.views.contact :refer [contact-view]] - [status-im.i18n :refer [label]])) - -(defn member-view [{:keys [whisper-identity role] :as contact}] - ;; TODO implement :role property for group chat contact - [contact-view - {:contact contact - :extended? true - :info role - :on-click #(dispatch [:set :selected-participants #{whisper-identity}])}]) diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index b7c68a94bb..9e7652a71b 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -11,7 +11,6 @@ splash-screen http-bridge]] [status-im.components.main-tabs :refer [main-tabs]] - [status-im.contacts.search-results :refer [contacts-search-results]] [status-im.contacts.views.contact-list :refer [contact-list]] [status-im.contacts.views.contact-list-modal :refer [contact-list-modal]] [status-im.contacts.views.new-contact :refer [new-contact]] @@ -36,7 +35,6 @@ [status-im.new-group.screen-public :refer [new-public-group]] [status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.remove :refer [remove-participants]] - [status-im.group-settings.screen :refer [group-settings]] [status-im.profile.screen :refer [profile my-profile]] [status-im.profile.edit.screen :refer [edit-my-profile]] [status-im.profile.photo-capture.screen :refer [profile-photo-capture]] @@ -107,10 +105,8 @@ :add-participants-toggle-list add-participants-toggle-list :reorder-groups reorder-groups :new-public-group new-public-group - :group-settings group-settings :contact-list main-tabs :contact-toggle-list contact-toggle-list - :contact-list-search-results contacts-search-results :group-contacts contact-list :new-contact new-contact :qr-scanner qr-scanner diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index edb43e9fcf..473c7f4caa 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -61,82 +61,7 @@ :icon {:padding-top 0 :bottom -4 :justify-content :flex-end}}} - :new-chat {:option-inner-container {:height 64} - :option-icon-container {:background-color styles/color-blue-transparent - :margin-top 12} - :option-name-text {:font-size 17 - :color styles/color-light-blue} - :contact-list-title-container {:background-color styles/color-white - :padding-top 19 - :padding-bottom 15 - :margin-top 16} - :contact-list-title {:color styles/text1-color - :font-size 16}} - :contacts {:subtitle {:color styles/text1-color - :font-size 16 - :letter-spacing -0.2 - :flex-shrink 1} - :subtitle-count {:color styles/color-gray4 - :font-size 16 - :letter-spacing -0.2} - :info-container {:margin-left 16} - :contact-inner-container {:height 63} - :icon-check {:border-radius 50 - :width 24 - :height 24} - :group-header {:flexDirection :row - :alignItems :center - :margin-top 24 - :padding-top 19 - :padding-bottom 15 - :padding-left 16 - :padding-right 16 - :backgroundColor styles/color-white} - :show-all {:padding-left 72 - :height 64} - :show-all-text {:fontSize 16 - :color styles/color-gray4 - :letter-spacing -0.2} - :show-all-text-font :default - :contact-container {:padding-right 16} - :name-text {:fontSize 17 - :line-height 20 - :letter-spacing -0.2 - :color styles/text1-color}} - :new-group {:group-name-text {:font-size 13} - :members-text {:letter-spacing -0.2 - :font-size 16} - :members-text-count {:letter-spacing -0.2 - :font-size 16} - :add-text {:margin-left 14 - :letter-spacing -0.2 - :font-size 17 - :line-height 20} - :contact-container {:height 63} - :settings-group-text {:color styles/color-light-blue - :letter-spacing -0.2 - :font-size 17 - :line-height 20} - :settings-group-item {:padding-left 16 - :height 64 - :flex-direction :row - :align-items :center} - :settings-group-container {:margin-top 25} - :settings-icon-container {:background-color "#628fe333" - :border-radius 50} - :delete-group-prompt-text {:font-size 14 - :letter-spacing -0.2} - :delete-icon-container {:background-color "#d84b4b33" - :border-radius 50}} - :reorder-groups {:order-item-separator {:margin-left 16 - :opacity 0.5} - :order-item-contacts {:font-size 17 - :line-height 20 - :letter-spacing -0.2}} - :confirm-button-label {:color styles/color-white - :font-size 17 - :line-height 20 - :letter-spacing -0.2} + :contacts {:show-all-text-font :default} :bottom-gradient {:height 1} :input-label {:left 0} :input-error-text {:margin-left 0} diff --git a/src/status_im/new_chat/screen.cljs b/src/status_im/new_chat/screen.cljs index 90902a1889..35df0908e9 100644 --- a/src/status_im/new_chat/screen.cljs +++ b/src/status_im/new_chat/screen.cljs @@ -1,85 +1,53 @@ (ns status-im.new-chat.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [dispatch]] + [status-im.components.common.common :as common] + [status-im.components.renderers.renderers :as renderers] + [status-im.components.action-button.action-button :refer [action-button + action-separator]] + [status-im.components.action-button.styles :refer [actions-list]] [status-im.components.react :refer [view text linear-gradient image touchable-highlight list-view list-item]] - [status-im.contacts.views.contact :refer [contact-view]] + [status-im.components.contact.contact :refer [contact-view]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search]] [status-im.components.drawer.view :refer [drawer-view]] [status-im.new-chat.styles :as st] [status-im.utils.listview :as lw] - [status-im.i18n :refer [label]] - [status-im.utils.platform :refer [ios?]])) - -(defn list-bottom-shadow [] - [linear-gradient {:style {:height 4} - :colors st/list-bottom-shadow}]) - -(defn list-top-shadow [] - [linear-gradient {:style {:height 3} - :colors st/list-top-shadow}]) - -(defn list-separator [] - (when ios? - [view st/list-separator-wrapper - [view st/list-separator]])) - -(defn options-list-item [{:keys [on-press icon-uri label-key]}] - [touchable-highlight {:on-press on-press} - [view st/option-container - [view st/option-inner-container - [view st/option-icon-container - [image {:source {:uri icon-uri} - :style st/option-icon}]] - [view st/option-info-container - [text {:style st/option-name-text} - (label label-key)]]]]]) + [status-im.i18n :refer [label]])) (defn options-list [] - [view - [view (st/options-list) - [options-list-item {:on-press #(dispatch [:open-contact-toggle-list :chat-group]) - :icon-uri :icon_private_group_big - :label-key :t/new-group-chat}] - [list-separator] - [options-list-item {:on-press #(dispatch [:navigate-to :new-public-group]) - :icon-uri :icon_public_group_big - :label-key :t/new-public-group-chat}] - [list-separator] - [options-list-item {:on-press #(dispatch [:navigate-to :new-contact]) - :icon-uri :icon_add_blue - :label-key :t/add-new-contact}]] - (when-not ios? [list-bottom-shadow])]) + [view actions-list + [action-button (label :t/new-group-chat) + :private_group_big + #(dispatch [:open-contact-toggle-list :chat-group])] + [action-separator] + [action-button (label :t/new-public-group-chat) + :public_group_big + #(dispatch [:navigate-to :new-public-group])] + [action-separator] + [action-button (label :t/add-new-contact) + :add_blue + #(dispatch [:navigate-to :new-contact])]]) (defn contact-list-row [] (fn [row _ _] - (list-item ^{:key row} [contact-view {:contact row}]))) - -(defn contact-list-title [contact-count] - [view - [view st/contact-list-title-container - [text {:style st/contact-list-title - :font :medium} - (label :t/choose-from-contacts) - (when ios? [text {:style st/contact-list-title-count - :font :medium} - " " contact-count])]] - (when-not ios? [list-top-shadow])]) - -(defn contact-list-separator [_ row-id _] - (when ios? (list-item ^{:key row-id} [list-separator]))) + (list-item ^{:key row} + [contact-view {:contact row + :on-press #(dispatch [:open-chat-with-contact %])}]))) (defview new-chat-toolbar [] - [show-search [:get-in [:toolbar-search :show]]] + [show-search [:get-in [:toolbar-search :show]] + search-text [:get-in [:toolbar-search :text]]] [view [status-bar] (toolbar-with-search {:show-search? (= show-search :contact-list) + :search-text search-text :search-key :contact-list :title (label :t/contacts-group-new-chat) :search-placeholder (label :t/search-for)})]) @@ -99,10 +67,12 @@ :renderHeader #(list-item [view [options-list] - [contact-list-title (count contacts)] - (when-not ios? [view st/spacing-top])]) - :renderSeparator contact-list-separator - :renderFooter #(list-item (when-not ios? [view - [view st/spacing-bottom] - [list-bottom-shadow]])) + [common/bottom-shaddow] + [common/form-title (label :t/choose-from-contacts) + {:count-value (count contacts)}] + [common/list-header]]) + :renderSeparator renderers/list-separator-renderer + :renderFooter #(list-item [view + [common/list-footer] + [common/bottom-shaddow]]) :style st/contacts-list}])]]) diff --git a/src/status_im/new_chat/styles.cljs b/src/status_im/new_chat/styles.cljs index 982858336d..41d4d6e69a 100644 --- a/src/status_im/new_chat/styles.cljs +++ b/src/status_im/new_chat/styles.cljs @@ -1,85 +1,10 @@ (ns status-im.new-chat.styles - (:require [status-im.components.styles :as st] - [status-im.utils.platform :as p])) - -(def list-bottom-shadow - ["rgba(24, 52, 76, 0.165)" - "rgba(24, 52, 76, 0.03)" - "rgba(24, 52, 76, 0.01)"]) - -(def list-top-shadow - ["rgba(24, 52, 76, 0.01)" - "rgba(24, 52, 76, 0.03)"]) - -(def list-separator - {:border-bottom-width 1 - :border-bottom-color st/color-gray5 - :margin-left 72 - :opacity 0.5}) - -(def list-separator-wrapper - {:background-color st/color-white - :height 1}) - -(defn options-list [] - {:padding-top (if p/ios? 0 8) - :padding-bottom (if p/ios? 0 8) - :background-color st/color-white}) - -(def option-container - {:flex-direction :row - :background-color st/color-white}) - -(def option-inner-container - (merge {:flex 1 - :flex-direction :row - :background-color st/color-white} - (get-in p/platform-specific [:component-styles :new-chat :option-inner-container]))) - -(def option-icon-container - (merge {:width 40 - :height 40 - :border-radius 50 - :margin-left 16} - (get-in p/platform-specific [:component-styles :new-chat :option-icon-container]))) - -(def option-icon - {:width 24 - :height 24 - :top 8 - :left 8}) - -(def option-info-container - {:flex 1 - :flexDirection :column - :margin-left 16 - :justifyContent :center}) - -(def option-name-text - (get-in p/platform-specific [:component-styles :new-chat :option-name-text])) - -(def contact-list-title-container - (merge {:padding-left 16} - (get-in p/platform-specific [:component-styles :new-chat :contact-list-title-container]))) - -(def contact-list-title - (get-in p/platform-specific [:component-styles :new-chat :contact-list-title])) - -(def contact-list-title-count - {:color st/text4-color - :opacity 0.5}) + (:require [status-im.components.styles :as common])) (def contacts-list-container {:flex 1 :margin-bottom 0}) (def contacts-list - {:backgroundColor st/color-light-gray}) + {:backgroundColor common/color-light-gray}) -(def spacing-top - {:background-color st/color-white - :height 8}) - -(def spacing-bottom - {:background-color st/color-white - :height 8}) diff --git a/src/status_im/new_group/screen_private.cljs b/src/status_im/new_group/screen_private.cljs index 9f13d72832..0140c117dd 100644 --- a/src/status_im/new_group/screen_private.cljs +++ b/src/status_im/new_group/screen_private.cljs @@ -1,13 +1,15 @@ (ns status-im.new-group.screen-private (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [dispatch]] - [status-im.contacts.views.contact :refer [contact-view]] + [status-im.components.contact.contact :refer [contact-view]] + [status-im.components.common.common :as common] [status-im.components.react :refer [view scroll-view keyboard-avoiding-view list-view list-item]] - [status-im.components.confirm-button :refer [confirm-button]] + [status-im.components.renderers.renderers :as renderers] + [status-im.components.sticky-button :refer [sticky-button]] [status-im.utils.listview :refer [to-datasource]] [status-im.new-group.styles :as st] [status-im.new-group.views.group :refer [group-toolbar @@ -15,8 +17,7 @@ group-name-view add-btn more-btn - delete-btn - separator]] + delete-btn]] [status-im.new-group.validations :as v] [status-im.i18n :refer [label]] [status-im.utils.platform :refer [ios?]] @@ -29,7 +30,7 @@ contacts-count [:all-added-group-contacts-count (:group-id group)]] [view (when (pos? contacts-count) - [separator]) + [common/list-separator]) [view (doall (map (fn [row] @@ -43,14 +44,11 @@ :text (label :t/remove-from-group)}] :extended? true}] (when-not (= row (last contacts)) - [separator])]) + [common/list-separator])]) contacts))] (when (< contacts-limit contacts-count) [more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-group-contact-list])])]) -(defn save [] - (dispatch [:set-group-name])) - (defview edit-group [] [group-name [:get :new-chat-name] group [:get-contact-group] @@ -69,17 +67,12 @@ (dispatch [:delete-group]) (dispatch [:navigate-to-clean :contact-list]))]] (when save-btn-enabled? - [confirm-button (label :t/save) save])])) - -(defn render-separator [_ row-id _] - (list-item ^{:key row-id} - [separator])) + [sticky-button (label :t/save) #(dispatch [:set-group-name])])])) (defn render-row [row _ _] (list-item ^{:key row} - [contact-view {:contact row - :on-click #()}])) + [contact-view {:contact row}])) (defview new-group [] [contacts [:selected-group-contacts] @@ -96,9 +89,9 @@ :renderRow render-row :bounces false :keyboardShouldPersistTaps true - :renderSeparator render-separator}]] + :renderSeparator renderers/list-separator-renderer}]] (when save-btn-enabled? - [confirm-button (label :t/save) + [sticky-button (label :t/save) (if (= group-type :contact-group) #(dispatch [:create-new-group group-name]) #(dispatch [:create-new-group-chat group-name]))])])) diff --git a/src/status_im/new_group/styles.cljs b/src/status_im/new_group/styles.cljs index 591a677fb0..f3ef2edc43 100644 --- a/src/status_im/new_group/styles.cljs +++ b/src/status_im/new_group/styles.cljs @@ -13,12 +13,6 @@ color-gray5]] [status-im.utils.platform :refer [platform-specific] :as p])) -(defn ps-reorder [item] - (get-in platform-specific [:component-styles :reorder-groups item])) - -(defn ps-new-group [item] - (get-in platform-specific [:component-styles :new-group item])) - (defn toolbar-icon [enabled?] {:width 20 :height 18 @@ -34,9 +28,9 @@ :flex-direction :column :background-color color-light-gray}) -(def reorder-list-container - (merge {:flex 1} - (ps-reorder :reorder-list-container))) +(defstyle reorder-list-container + {:flex 1 + :android {:padding-top 16}}) (def chat-name-container {:margin-top 21 @@ -71,24 +65,25 @@ :height 40 :padding-bottom 0}) -(def group-name-text - (merge (ps-new-group :group-name-text) - {:letter-spacing -0.1 - :color color-gray4})) +(defstyle group-name-text + {:letter-spacing -0.1 + :color color-gray4 + :ios {:font-size 13} + :android {:font-size 12}}) -(def members-container - {:flex-direction :row - :padding-top 20}) +(defstyle members-text + {:color color-gray4 + :ios {:letter-spacing -0.2 + :font-size 16} + :android {:font-size 14}}) -(def members-text - (merge (ps-new-group :members-text) - {:color color-gray4})) - -(def members-text-count - (merge (ps-new-group :members-text-count) - {:margin-left 8 - :color color-gray4 - :opacity 0.6})) +(defstyle members-text-count + {:margin-left 8 + :color color-gray4 + :opacity 0.6 + :ios {:letter-spacing -0.2 + :font-size 16} + :android {:font-size 14}}) (def add-container {:flex-direction :row @@ -96,73 +91,70 @@ :height 64 :margin-top 12}) -(def settings-icon-container - (merge (ps-new-group :settings-icon-container) - {:width 40 - :height 40 - :align-items :center - :justify-content :center})) +(defstyle settings-icon-container + {:width 40 + :height 40 + :align-items :center + :justify-content :center + :ios {:background-color "#628fe333" + :border-radius 50}}) (def add-icon {:align-items :center :width 24 :height 24}) -(def add-group-text - (merge (ps-new-group :settings-group-text) - {:color color-light-blue})) +(defstyle add-group-text + {:color color-light-blue + :ios {:color color-light-blue + :letter-spacing -0.2 + :font-size 17 + :line-height 20} + :android {:letter-spacing 0.5 + :font-size 16}}) (def settings-group-text - (merge (ps-new-group :settings-group-text))) + add-group-text) (def settings-group-text-container {:padding-left 16}) (def delete-group-text - (merge (ps-new-group :settings-group-text) + (merge add-group-text {:color color-light-red})) -(def delete-group-prompt-text - (merge (ps-new-group :delete-group-prompt-text) - {:color color-gray4 - :padding-top 5})) +(defstyle delete-group-prompt-text + {:color color-gray4 + :padding-top 5 + :ios {:font-size 14 + :letter-spacing -0.2} + :android {:font-size 12}}) -(def contact-container - (merge (ps-new-group :contact-container) - {:flex-direction :row - :justify-content :center - :align-items :center})) +(defstyle contact-container + {:flex-direction :row + :justify-content :center + :align-items :center + :ios {:height 63} + :android {:height 56}}) -(def selected-contact - {:background-color selected-contact-color}) +(defstyle settings-group-container + {:ios {:margin-top 25} + :android {:margin-top 23}}) -(def icon-check-container - (merge (get-in platform-specific [:component-styles :contacts :icon-check]) - {:alignItems :center - :justifyContent :center})) +(defstyle settings-group-item + {:padding-left 16 + :flex-direction :row + :align-items :center + :ios {:height 64} + :android {:height 56}}) -(def toggle-container - {:width 56 - :height 56 - :alignItems :center - :justifyContent :center}) - -(def check-icon - {:width 12 - :height 12}) - -(def settings-group-container - (ps-new-group :settings-group-container)) - -(def settings-group-item - (ps-new-group :settings-group-item)) - -(def delete-icon-container - (merge (ps-new-group :delete-icon-container) - {:width 40 - :height 40 - :align-items :center - :justify-content :center})) +(defstyle delete-icon-container + {:width 40 + :height 40 + :align-items :center + :justify-content :center + :ios {:background-color "#d84b4b33" + :border-radius 50}}) (def order-item-container {:background-color color-white}) @@ -187,10 +179,14 @@ :line-height 20 :letter-spacing -0.2}}) -(def order-item-contacts - (merge (ps-reorder :order-item-contacts) - {:padding-left 8 - :color color-gray4})) +(defstyle order-item-contacts + {:padding-left 8 + :color color-gray4 + :ios {:font-size 17 + :line-height 20 + :letter-spacing -0.2} + :android {:font-size 16 + :line-height 24}}) (defstyle order-item-icon {:android {:padding-horizontal 16} @@ -200,9 +196,10 @@ {:background-color color-white}) (def order-item-separator - (merge {:height 1 - :background-color color-gray5} - (ps-reorder :order-item-separator))) + {:height 1 + :background-color color-gray5 + :ios {:margin-left 16 + :opacity 0.5}}) (def toolbar-title-with-count-text {:color text1-color diff --git a/src/status_im/new_group/views/chat_group_settings.cljs b/src/status_im/new_group/views/chat_group_settings.cljs index 1c5b304393..962f33ab7d 100644 --- a/src/status_im/new_group/views/chat_group_settings.cljs +++ b/src/status_im/new_group/views/chat_group_settings.cljs @@ -1,38 +1,35 @@ (ns status-im.new-group.views.chat-group-settings (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [dispatch]] - [status-im.contacts.views.contact :refer [contact-view]] - [status-im.components.react :refer [view - scroll-view - keyboard-avoiding-view - icon - touchable-highlight]] - [status-im.components.confirm-button :refer [confirm-button]] - [status-im.new-group.styles :as st] - [status-im.new-group.views.group :refer [group-toolbar - group-chat-settings-btns - group-name-view - add-btn - more-btn - delete-btn - separator]] - [status-im.new-group.validations :as v] - [status-im.i18n :refer [label]] - [status-im.utils.platform :refer [ios?]] - [cljs.spec :as s])) + [status-im.components.contact.contact :refer [contact-view]] + [status-im.components.common.common :as common] + [status-im.components.react :refer [view + scroll-view + keyboard-avoiding-view + icon + touchable-highlight]] + [status-im.components.sticky-button :refer [sticky-button]] + [status-im.new-group.styles :as st] + [status-im.new-group.views.group :refer [group-toolbar + group-chat-settings-btns + group-name-view + add-btn + more-btn + delete-btn]] + [status-im.new-group.validations :as v] + [status-im.i18n :refer [label]] + [status-im.utils.platform :refer [ios?]] + [cljs.spec :as s])) (def contacts-limit 3) -(defn save-chat-name [] - (dispatch [:set-chat-name])) - (defview chat-group-contacts-view [admin?] [contacts [:current-chat-contacts]] (let [limited-contacts (take contacts-limit contacts) contacts-count (count contacts)] [view (when (and admin? (pos? contacts-count)) - [separator]) + [common/list-separator]) [view (doall (map (fn [row] @@ -40,14 +37,13 @@ [view [contact-view {:contact row - :on-click #() :extend-options [{:value #(do (dispatch [:set :selected-participants #{(:whisper-identity row)}]) (dispatch [:remove-participants])) - :text (label :t/remove)}] + :text (label :t/remove)}] :extended? admin?}] (when-not (= row (last limited-contacts)) - [separator])]) + [common/list-separator])]) limited-contacts))] (when (< contacts-limit contacts-count) [more-btn contacts-limit contacts-count #(dispatch [:navigate-to :edit-chat-group-contact-list])])])) @@ -77,4 +73,4 @@ [view st/separator] [group-chat-settings-btns]]] (when save-btn-enabled? - [confirm-button (label :t/save) save-chat-name])])) + [sticky-button (label :t/save) #(dispatch [:set-chat-name])])])) diff --git a/src/status_im/new_group/views/contact_list.cljs b/src/status_im/new_group/views/contact_list.cljs index c4a1a60d2c..3aad6fd504 100644 --- a/src/status_im/new_group/views/contact_list.cljs +++ b/src/status_im/new_group/views/contact_list.cljs @@ -1,20 +1,17 @@ (ns status-im.new-group.views.contact-list (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [dispatch]] - [status-im.contacts.views.contact :refer [contact-view]] + [status-im.components.contact.contact :refer [contact-view]] + [status-im.components.renderers.renderers :as renderers] [status-im.components.react :refer [view text list-view list-item]] - [status-im.components.confirm-button :refer [confirm-button]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search]] [status-im.utils.listview :refer [to-datasource]] - [status-im.new-group.views.group :refer [separator]] [status-im.new-group.styles :as st] - [status-im.contacts.styles :as cst] - [status-im.i18n :refer [label]] - [status-im.components.toolbar-new.actions :as act])) + [status-im.i18n :refer [label]])) (defview contact-list-toolbar [title] [show-search [:get-in [:toolbar-search :show]] @@ -26,37 +23,51 @@ :title title :search-placeholder (label :t/search-contacts)})) -(defn render-separator [_ row-id _] - (list-item ^{:key row-id} - [separator])) - -(defn render-spacing [] - #(list-item [view cst/contact-list-spacing])) - -(defn render-row [group] - (fn [row _ _] - (list-item - ^{:key row} - [contact-view {:contact row - :extended? true - :extend-options (when group - [{:value #(dispatch [:remove-contact-from-group - (:whisper-identity row) - (:group-id group)]) - :text (label :t/remove-from-group)}]) - :on-click nil}]))) - -(defview contacts-list-view [group] - [contacts [:all-added-group-contacts-filtered (:group-id group)]] +(defn contacts-list [contacts renderer-function] [view {:flex 1} [list-view {:dataSource (to-datasource contacts) :enableEmptySections true - :renderRow (render-row group) + :renderRow renderer-function :bounces false :keyboardShouldPersistTaps true - :renderSeparator render-separator - :renderFooter (render-spacing) - :renderHeader (render-spacing)}]]) + :renderSeparator renderers/list-separator-renderer + :renderFooter renderers/list-footer-renderer + :renderHeader renderers/list-header-renderer}]]) + +(defview chat-contacts-list-view [] + [contacts [:contacts-filtered :current-chat-contacts] + current-pk [:get :current-public-key] + group-admin [:chat :group-admin]] + (let [admin? (= current-pk group-admin)] + [contacts-list contacts (fn [row _ _] + (list-item + ^{:key row} + [contact-view {:contact row + :extended? admin? + :extend-options [{:value #(do + (dispatch [:set :selected-participants + #{(:whisper-identity row)}]) + (dispatch [:remove-participants])) + :text (label :t/remove)}]}]))])) + +(defview contacts-list-view [group] + [contacts [:all-added-group-contacts-filtered (:group-id group)]] + [contacts-list contacts (fn [row _ _] + (list-item + ^{:key row} + [contact-view {:contact row + :extended? true + :extend-options [{:value #(dispatch [:remove-contact-from-group + (:whisper-identity row) + (:group-id group)]) + :text (label :t/remove-from-group)}]}]))]) + +(defview edit-chat-group-contact-list [] + [chat-name [:chat :name]] + [view st/group-container + [status-bar] + [contact-list-toolbar chat-name] + [chat-contacts-list-view]]) (defview edit-group-contact-list [] [group [:get-contact-group] @@ -64,38 +75,4 @@ [view st/group-container [status-bar] [contact-list-toolbar (:name group)] - [contacts-list-view group]]) - -(defn render-chat-row [admin?] - (fn [row _ _] - (list-item - ^{:key row} - [contact-view {:contact row - :extended? admin? - :extend-options [{:value #(do - (dispatch [:set :selected-participants #{(:whisper-identity row)}]) - (dispatch [:remove-participants])) - :text (label :t/remove)}] - :on-click #()}]))) - -(defview chat-contacts-list-view [] - [contacts [:contacts-filtered :current-chat-contacts] - current-pk [:get :current-public-key] - group-admin [:chat :group-admin]] - (let [admin? (= current-pk group-admin)] - [view {:flex 1} - [list-view {:dataSource (to-datasource contacts) - :enableEmptySections true - :renderRow (render-chat-row admin?) - :bounces false - :keyboardShouldPersistTaps true - :renderSeparator render-separator - :renderFooter (render-spacing) - :renderHeader (render-spacing)}]])) - -(defview edit-chat-group-contact-list [] - [chat-name [:chat :name]] - [view st/group-container - [status-bar] - [contact-list-toolbar chat-name] - [chat-contacts-list-view]]) \ No newline at end of file + [contacts-list-view group]]) \ No newline at end of file diff --git a/src/status_im/new_group/views/contact_toggle_list.cljs b/src/status_im/new_group/views/contact_toggle_list.cljs index b3fbdc9345..607099cd75 100644 --- a/src/status_im/new_group/views/contact_toggle_list.cljs +++ b/src/status_im/new_group/views/contact_toggle_list.cljs @@ -1,24 +1,24 @@ (ns status-im.new-group.views.contact-toggle-list (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [dispatch]] - [status-im.contacts.views.contact :refer [contact-view]] - [status-im.components.react :refer [view - keyboard-avoiding-view - text - list-view - list-item]] - [status-im.components.confirm-button :refer [confirm-button]] - [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar-new.view :refer [toolbar-with-search]] - [status-im.utils.listview :refer [to-datasource]] - [status-im.utils.platform :refer [ios?]] - [status-im.new-group.views.toggle-contact :refer [group-toggle-contact - group-toggle-participant]] - [status-im.components.common.common :refer [separator]] - [status-im.new-group.styles :as st] - [status-im.contacts.styles :as cst] - [status-im.i18n :refer [label]] - [status-im.components.toolbar-new.actions :as act])) + [status-im.components.contact.contact :refer [contact-view]] + [status-im.components.renderers.renderers :as renderers] + [status-im.components.react :refer [view + keyboard-avoiding-view + text + list-view + list-item]] + [status-im.components.sticky-button :refer [sticky-button]] + [status-im.components.status-bar :refer [status-bar]] + [status-im.components.toolbar-new.view :refer [toolbar-with-search]] + [status-im.utils.listview :refer [to-datasource]] + [status-im.utils.platform :refer [ios?]] + [status-im.new-group.views.toggle-contact :refer [group-toggle-contact + group-toggle-participant]] + [status-im.new-group.styles :as st] + [status-im.contacts.styles :as cst] + [status-im.i18n :refer [label]] + [status-im.components.toolbar-new.actions :as act])) (defn title-with-count [title count-value] [view st/toolbar-title-with-count @@ -41,12 +41,17 @@ :custom-title (title-with-count title contacts-count) :search-placeholder (label :t/search-contacts)})) -(defn render-separator [_ row-id _] - (list-item ^{:key row-id} - [separator cst/contact-item-separator])) - -(defn render-spacing [] - #(list-item [view cst/contact-list-spacing])) +(defn toggle-list [contacts render-function] + [view {:flex 1} + [list-view + {:dataSource (to-datasource contacts) + :renderRow (fn [row _ _] + (list-item ^{:key row} [render-function row])) + :renderSeparator renderers/list-separator-renderer + :renderFooter renderers/list-footer-renderer + :renderHeader renderers/list-header-renderer + :style cst/contacts-list + :keyboardShouldPersistTaps true}]]) (defview contact-toggle-list [] [contacts [:all-added-group-contacts-filtered] @@ -60,18 +65,9 @@ :t/new-group :t/new-group-chat)) selected-contacts-count] - [view {:flex 1} - [list-view - {:dataSource (to-datasource contacts) - :renderRow (fn [row _ _] - (list-item ^{:key row} [group-toggle-contact row])) - :renderSeparator render-separator - :renderFooter (render-spacing) - :renderHeader (render-spacing) - :style cst/contacts-list - :keyboardShouldPersistTaps true}]] + [toggle-list contacts group-toggle-contact] (when (pos? selected-contacts-count) - [confirm-button (label :t/next) #(dispatch [:navigate-to :new-group])])]) + [sticky-button (label :t/next) #(dispatch [:navigate-to :new-group])])]) (defview add-contacts-toggle-list [] [contacts [:all-group-not-added-contacts-filtered] @@ -81,18 +77,9 @@ st/group-container) [status-bar] [toggle-list-toolbar (:name group) selected-contacts-count] - [view {:flex 1} - [list-view - {:dataSource (to-datasource contacts) - :renderRow (fn [row _ _] - (list-item ^{:key row} [group-toggle-contact row])) - :renderSeparator render-separator - :renderFooter (render-spacing) - :renderHeader (render-spacing) - :style cst/contacts-list - :keyboardShouldPersistTaps true}]] + [toggle-list contacts group-toggle-contact] (when (pos? selected-contacts-count) - [confirm-button (label :t/save) #(do + [sticky-button (label :t/save) #(do (dispatch [:add-selected-contacts-to-group]) (dispatch [:navigate-back]))])]) @@ -104,18 +91,9 @@ st/group-container) [status-bar] [toggle-list-toolbar chat-name selected-contacts-count] - [view {:flex 1} - [list-view - {:dataSource (to-datasource contacts) - :renderRow (fn [row _ _] - (list-item ^{:key row} [group-toggle-participant row])) - :renderSeparator render-separator - :renderFooter (render-spacing) - :renderHeader (render-spacing) - :style cst/contacts-list - :keyboardShouldPersistTaps true}]] + [toggle-list contacts group-toggle-participant] (when (pos? selected-contacts-count) - [confirm-button (label :t/save) #(do + [sticky-button (label :t/save) #(do (dispatch [:add-new-participants]) (dispatch [:navigate-back]))])]) diff --git a/src/status_im/new_group/views/group.cljs b/src/status_im/new_group/views/group.cljs index b8a8f8cd80..fb9b25c081 100644 --- a/src/status_im/new_group/views/group.cljs +++ b/src/status_im/new_group/views/group.cljs @@ -2,7 +2,10 @@ (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [dispatch]] [status-im.contacts.styles :as cst] - [status-im.components.common.common :as cmn] + [status-im.components.common.common :as common] + [status-im.components.action-button.action-button :refer [action-button + action-button-disabled + action-separator]] [status-im.components.react :refer [view text icon @@ -15,9 +18,6 @@ [status-im.new-group.styles :as st] [status-im.i18n :refer [label]])) -(defn separator [] - [cmn/separator cst/contact-item-separator]) - (defview group-name-input [] [new-group-name [:get :new-chat-name]] [view @@ -49,14 +49,9 @@ [group-name-input]]) (defn add-btn [on-press] - [view st/add-button-container - [touchable-highlight {:on-press on-press} - [view st/add-container - [view st/settings-icon-container - [icon :add_blue st/add-icon]] - [view st/settings-group-text-container - [text {:style st/add-group-text} - (label :t/add-members)]]]]]) + [action-button (label :t/add-members) + :add_blue + on-press]) (defn delete-btn [on-press] [view st/settings-group-container @@ -80,15 +75,11 @@ [view st/settings-group-text-container [text {:style st/settings-group-text} (label :t/mute-notifications)]]]]] - [separator] - [touchable-highlight {:on-press #(dispatch [:clear-history])} - [view st/settings-group-item - [view st/settings-icon-container - [icon :close_blue st/add-icon]] - [view st/settings-group-text-container - [text {:style st/settings-group-text} - (label :t/clear-history)]]]] - [separator] + [action-separator] + [action-button (label :t/clear-history) + :close_blue + #(dispatch [:clear-history])] + [action-separator] [touchable-highlight {:on-press #(dispatch [:leave-group-chat])} [view st/settings-group-item [view st/delete-icon-container @@ -99,7 +90,7 @@ (defn more-btn [contacts-limit contacts-count on-press] [view - [separator] + [common/list-separator] [view cst/show-all [touchable-highlight {:on-press on-press} [view diff --git a/src/status_im/new_group/views/reorder_groups.cljs b/src/status_im/new_group/views/reorder_groups.cljs index d12970325a..169b6cccb6 100644 --- a/src/status_im/new_group/views/reorder_groups.cljs +++ b/src/status_im/new_group/views/reorder_groups.cljs @@ -6,11 +6,11 @@ icon touchable-highlight list-item]] - [status-im.components.confirm-button :refer [confirm-button]] + [status-im.components.sticky-button :refer [sticky-button]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar]] [status-im.components.sortable-list-view :refer [sortable-list-view sortable-item]] - [status-im.components.common.common :refer [top-shaddow bottom-shaddow]] + [status-im.components.common.common :as common] [status-im.utils.listview :refer [to-datasource]] [status-im.utils.platform :refer [android?]] [status-im.new-group.styles :as st] @@ -39,7 +39,7 @@ (list-item (if (= row-id last) ^{:key "bottom-shaddow"} - [bottom-shaddow] + [common/bottom-shaddow] ^{:key row-id} [view st/order-item-separator-wrapper [view st/order-item-separator]])))) @@ -52,7 +52,7 @@ [status-bar] [toolbar-view] [view st/reorder-list-container - [top-shaddow] + [common/top-shaddow] [sortable-list-view {:data groups :order order @@ -61,4 +61,4 @@ :render-row (fn [row] (sortable-item [group-item row])) :render-separator (render-separator (last order))}]] - [confirm-button (label :t/save) #(dispatch [:save-group-order])]])) + [sticky-button (label :t/save) #(dispatch [:save-group-order])]])) diff --git a/src/status_im/new_group/views/toggle_contact.cljs b/src/status_im/new_group/views/toggle_contact.cljs index da751c36b9..968ab69921 100644 --- a/src/status_im/new_group/views/toggle_contact.cljs +++ b/src/status_im/new_group/views/toggle_contact.cljs @@ -1,12 +1,6 @@ (ns status-im.new-group.views.toggle-contact - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.components.react :refer [view icon touchable-highlight]] - [status-im.contacts.views.contact-inner :refer [contact-inner-view]] - [status-im.new-group.styles :as st] - [status-im.contacts.styles :as cst] - [status-im.components.styles :refer [color-light-blue color-gray5]] - [status-im.utils.platform :refer [platform-specific]])) + (:require [re-frame.core :refer [dispatch]] + [status-im.components.contact.contact :refer [toogle-contact-view]])) (defn on-toggle [checked? whisper-identity] (let [action (if checked? :deselect-contact :select-contact)] @@ -16,23 +10,8 @@ (let [action (if checked? :deselect-participant :select-participant)] (dispatch [action whisper-identity]))) -;;TODO: maybe it's better to have only one global component contact-view (with the types: default, extended and toggle) -(defview toogle-contact-view [{:keys [whisper-identity] :as contact} selected-key on-toggle-handler] - [checked [selected-key whisper-identity]] - [touchable-highlight {:on-press #(on-toggle-handler checked whisper-identity)} - [view - [view (merge st/contact-container (when checked {:style st/selected-contact})) - [contact-inner-view (merge {:contact contact} - (when checked {:style st/selected-contact}))] - [view st/toggle-container - [view (merge st/icon-check-container - {:background-color (if checked color-light-blue color-gray5)}) - (when checked - [icon :check_on st/check-icon])]]]]]) - (defn group-toggle-contact [{:keys [whisper-identity] :as contact}] [toogle-contact-view contact :is-contact-selected? on-toggle]) (defn group-toggle-participant [{:keys [whisper-identity] :as contact}] - [toogle-contact-view contact :is-participant-selected? on-toggle-participant]) - + [toogle-contact-view contact :is-participant-selected? on-toggle-participant]) \ No newline at end of file diff --git a/src/status_im/participants/views/contact.cljs b/src/status_im/participants/views/contact.cljs index 1b3829b835..6c09db37e8 100644 --- a/src/status_im/participants/views/contact.cljs +++ b/src/status_im/participants/views/contact.cljs @@ -2,7 +2,7 @@ (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] [status-im.components.react :refer [view]] - [status-im.contacts.views.contact-inner :refer [contact-inner-view]] + [status-im.components.contact.contact :refer [contact-inner-view]] [status-im.components.item-checkbox :refer [item-checkbox]] [status-im.participants.styles :as st])) diff --git a/src/status_im/profile/edit/screen.cljs b/src/status_im/profile/edit/screen.cljs index 921fc0d3c1..7af773ffd4 100644 --- a/src/status_im/profile/edit/screen.cljs +++ b/src/status_im/profile/edit/screen.cljs @@ -9,7 +9,7 @@ [status-im.components.text-field.view :refer [text-field]] [status-im.i18n :refer [label]] [status-im.profile.screen :refer [colorize-status-hashtags]] - [status-im.components.confirm-button :refer [confirm-button]] + [status-im.components.sticky-button :refer [sticky-button]] [status-im.components.chat-icon.screen :refer [my-profile-icon]] [status-im.components.context-menu :refer [context-menu]] [status-im.profile.validations :as v] @@ -104,6 +104,6 @@ [edit-profile-status changed-account] [status-prompt changed-account]] (when (and profile-edit-data-changed? profile-edit-data-valid?) - [confirm-button (label :t/save) #(do + [sticky-button (label :t/save) #(do (dispatch [:check-status-change (:status changed-account)]) (dispatch [:account-update changed-account]))])])) From 7eeb0cded32fc735a4e4f32be4b8ed33183fcfea Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Mon, 3 Apr 2017 10:19:34 +0300 Subject: [PATCH 25/48] resized etherplay icon --- images/contacts/etherplay.png | Bin 8382 -> 23836 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/contacts/etherplay.png b/images/contacts/etherplay.png index 144637428aeef9d759e8991aaea8a02ed6ad2ac0..aecdbc8b0b9c64c9dac02e9cdf3161802abcff40 100644 GIT binary patch literal 23836 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 S;T1$zK=!SYRM{KDfd2uNV$To& From ae000ec118214c0ef13d992ff22f3c6ceca7387d Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Mon, 3 Apr 2017 11:30:24 +0300 Subject: [PATCH 26/48] fixes https://github.com/status-im/status-react/issues/964 --- src/status_im/profile/screen.cljs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/status_im/profile/screen.cljs b/src/status_im/profile/screen.cljs index 824cb01851..d443d20217 100644 --- a/src/status_im/profile/screen.cljs +++ b/src/status_im/profile/screen.cljs @@ -64,7 +64,7 @@ [text {:style st/profile-activity-status-text} (online-text last-online)]])]]) -(defn profile-actions [{:keys [pending? whisper-identity]} chat-id] +(defn profile-actions [{:keys [pending? whisper-identity dapp?]} chat-id] [view actions-list (if pending? [action-button (label :t/add-to-contacts) @@ -76,10 +76,12 @@ [action-button (label :t/start-conversation) :chats_blue #(message-user whisper-identity)] - [action-separator] - [action-button (label :t/send-transaction) - :arrow_right_blue - #(dispatch [:open-chat-with-the-send-transaction chat-id])]]) + (when-not dapp? + [view + [action-separator] + [action-button (label :t/send-transaction) + :arrow_right_blue + #(dispatch [:open-chat-with-the-send-transaction chat-id])]])]) (defn profile-info-item [{:keys [label value options text-mode empty-value?]}] [view st/profile-setting-item From b1adf7aa68f62b1aef97f241202a05c45c9ec499 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Mon, 3 Apr 2017 13:56:26 +0300 Subject: [PATCH 27/48] fixes https://github.com/status-im/status-react/issues/961 --- src/status_im/chat/views/message.cljs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/status_im/chat/views/message.cljs b/src/status_im/chat/views/message.cljs index 4daefe5a15..349f5afe8a 100644 --- a/src/status_im/chat/views/message.cljs +++ b/src/status_im/chat/views/message.cljs @@ -307,15 +307,25 @@ photo-path)} :style st/photo}]]) +(defview my-photo [from] + [account [:get-current-account]] + (let [{:keys [photo-path]} account] + [view st/photo-view + [image {:source {:uri (if (str/blank? photo-path) + (identicon from) + photo-path)} + :style st/photo}]])) + (defn message-body - [{:keys [last-outgoing? message-type same-author from index] :as message} content] + [{:keys [last-outgoing? message-type same-author from index outgoing] :as message} content] (let [delivery-status :seen-by-everyone] [view st/group-message-wrapper [view (st/message-body message) [view st/message-author - (when (and (or (= index 1) (not same-author)) - (not= from "me")) - [member-photo from])] + (when (or (= index 1) (not same-author)) + (if outgoing + [my-photo from] + [member-photo from]))] [view (st/group-message-view message) content (when last-outgoing? From abf0128a1af93f56a5f8ac61736a2b60661e5af6 Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Tue, 28 Mar 2017 15:23:58 -0300 Subject: [PATCH 28/48] transaction screens UI refresh --- .../drawable-hdpi/icon_arrow_left_white.png | Bin 0 -> 307 bytes .../res/drawable-hdpi/icon_close_white.png | Bin 253 -> 300 bytes .../main/res/drawable-hdpi/icon_ok_white.png | Bin 0 -> 421 bytes .../drawable-mdpi/icon_arrow_left_white.png | Bin 0 -> 226 bytes .../res/drawable-mdpi/icon_close_white.png | Bin 201 -> 251 bytes .../main/res/drawable-mdpi/icon_ok_white.png | Bin 0 -> 421 bytes .../drawable-xhdpi/icon_arrow_left_white.png | Bin 0 -> 383 bytes .../res/drawable-xhdpi/icon_close_white.png | Bin 329 -> 384 bytes .../main/res/drawable-xhdpi/icon_ok_white.png | Bin 0 -> 934 bytes .../drawable-xxhdpi/icon_arrow_left_white.png | Bin 0 -> 549 bytes .../res/drawable-xxhdpi/icon_close_white.png | Bin 401 -> 603 bytes .../res/drawable-xxhdpi/icon_ok_white.png | Bin 0 -> 1585 bytes .../icon_arrow_left_white.png | Bin 0 -> 767 bytes .../res/drawable-xxxhdpi/icon_close_white.png | Bin 546 -> 886 bytes .../res/drawable-xxxhdpi/icon_ok_white.png | Bin 0 -> 1585 bytes .../Contents.json | 21 +++ .../icon_arrow_left_white.png | Bin 0 -> 767 bytes .../icon_close_white.png | Bin 401 -> 384 bytes .../icon_ok_white.imageset/Contents.json | 23 ++++ .../icon_ok_white.imageset/iconOkBig.png | Bin 0 -> 421 bytes .../icon_ok_white.imageset/iconOkBig@2x.png | Bin 0 -> 934 bytes .../icon_ok_white.imageset/iconOkBig@3x.png | Bin 0 -> 1585 bytes src/status_im/android/core.cljs | 8 +- src/status_im/chat/handlers/send_message.cljs | 2 +- src/status_im/components/common/common.cljs | 4 +- src/status_im/components/styles.cljs | 7 + .../components/text_field/styles.cljs | 3 +- src/status_im/components/text_field/view.cljs | 93 ++++++------- .../components/toolbar_new/actions.cljs | 4 + .../components/toolbar_new/view.cljs | 4 +- src/status_im/ios/core.cljs | 8 +- src/status_im/transactions/handlers.cljs | 38 ++++-- src/status_im/transactions/screen.cljs | 62 --------- .../screens/confirmation-success.cljs | 25 ++++ .../screens/pending-transactions.cljs | 69 ++++++++++ .../screens/transaction-details.cljs | 70 ++++++++++ src/status_im/transactions/styles.cljs | 105 -------------- .../transactions/styles/list_item.cljs | 52 +++++++ .../transactions/styles/password_form.cljs | 30 ++++ .../transactions/styles/screens.cljs | 129 ++++++++++++++++++ .../transactions/views/list_item.cljs | 39 ++++++ .../transactions/views/password_form.cljs | 29 ++++ .../transactions/views/transaction_page.cljs | 50 ------- src/status_im/translations/en.cljs | 12 ++ 44 files changed, 604 insertions(+), 283 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/icon_arrow_left_white.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_ok_white.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_arrow_left_white.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_ok_white.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_arrow_left_white.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_ok_white.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_arrow_left_white.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_ok_white.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_arrow_left_white.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_ok_white.png create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_left_white.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_left_white.imageset/icon_arrow_left_white.png create mode 100644 ios/StatusIm/Images.xcassets/icon_ok_white.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_ok_white.imageset/iconOkBig.png create mode 100644 ios/StatusIm/Images.xcassets/icon_ok_white.imageset/iconOkBig@2x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_ok_white.imageset/iconOkBig@3x.png delete mode 100644 src/status_im/transactions/screen.cljs create mode 100644 src/status_im/transactions/screens/confirmation-success.cljs create mode 100644 src/status_im/transactions/screens/pending-transactions.cljs create mode 100644 src/status_im/transactions/screens/transaction-details.cljs delete mode 100644 src/status_im/transactions/styles.cljs create mode 100644 src/status_im/transactions/styles/list_item.cljs create mode 100644 src/status_im/transactions/styles/password_form.cljs create mode 100644 src/status_im/transactions/styles/screens.cljs create mode 100644 src/status_im/transactions/views/list_item.cljs create mode 100644 src/status_im/transactions/views/password_form.cljs delete mode 100644 src/status_im/transactions/views/transaction_page.cljs diff --git a/android/app/src/main/res/drawable-hdpi/icon_arrow_left_white.png b/android/app/src/main/res/drawable-hdpi/icon_arrow_left_white.png new file mode 100644 index 0000000000000000000000000000000000000000..d9a494ffb9dca08daccd394c7ae6097df4bb39c0 GIT binary patch literal 307 zcmV-30nGl1P)Px#?MXyIR9Fe^l`#(iF&Kug5(}fzCg)$^@YDPdW{Xv9ViJSFZenL(uBVA6H(Yw( zpepix$(w7hZ`=2trnxNBQUXdq2`GU-CSa`{paWW=X3|e3K!F~}*ECrm5)`N$=0d-f zBv3_|EARRm=38Wp1T|rX_|~Xh@^5ILOZ`yOGI%t`%tI#e7=cdc6E&&Zv{7exkKcs8 zkj+uLhYW5^dSp4?E$Sj)OBy@h5j@?I?FBxWh4adhyW+l{G{&;okz54OP$IS!q}*?$ zBbpq`R1s|k1|%Oc%$NbB7>k44ofy`glX(f`Jo9vM42j@; z8`j8q*nsEtx8(mXm91Bar(TL!&=avO^Z20+2LrNh22Gig7O8crv1oye2Ky(zE!V=H z^xc`T{RK-gTemjhVt%DJ1v?M zG_;yaJ4F?oL=I~7mG}y-ikhWyS)rq!U1G!a#xnl;w%bRf7HKRx{-I_j^LmYj$}g&c z7c>pOYajVr(^k;VXXv+cN|eG0w`fe8_03Jc3U=`ibM|?m!bcBYkqJ2j^f7~{tDnm{r-UW|z&d*D literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|#^NA%Cx&(BWL^R}+dW+zLo5W> zhA{FqC~%b2-Y9>fUlsFygSGfMO{Uz9fqMPIeo9xPjQ_OF|Dep;8&T0{Y_`0-F?=(( z|MVUSi;YR{EJIPQ$ME6bBvdJZvNYuTos>U=E0 zFm%8E%!wJ^Nz0eZ3IFK`-dZ+c)0s8D1f_+h35(xWNNkImwmMF5L3bhJ-h$=39lzZ6 zKV7M`?V4?hig!c$*;^754<0*nsP^lmuLr*|eDpp3@9~0VfSd4!HbK=MJQlptJehDYE z)YR{ri|x)?e%O)O!~ubRv8`GaweZ{u+f~cw&oE$g$PTeE)7v-u15Z}qf~e%r_FEZF z_sYiH*!JsJ%g+4Dbs9JIAG8HB>6k0dSz7C9X05(4edn~fo44qnOna{KP3QWi;%VPh zZ@!sxWZu)LGQTW&Hun{|vB@v%a<8kumTBVCu-Dr$V~g#R?fadNZEnB%<9sp4@9!mF z*Ko}gIakWi_?d0N?-fj)wUi77bEMEa#}Dm=#D(xOwns z%Na2}wv=xLLMM_Q>}%BFdnbG%>0y+EUw3;ob0up+@s8~_AM@w@bu>wr`Eya$pCdwV zj`(+`O*K0hiWo0MU)XiOky|01!Ddm}ipKx*jCn6GfKW=_1HO6frdOs!2rdSOJA literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_arrow_left_white.png b/android/app/src/main/res/drawable-mdpi/icon_arrow_left_white.png new file mode 100644 index 0000000000000000000000000000000000000000..5344b610f38563632515cd789e7ea370fe484333 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|=6Jd|hIsHM zCrGd^R&>}d@Zkh4pZq&4&fA-x&s*dTVLJzkMyVrxs$FH!LOk@yfRuW}- z$FPxSnHHC8L))dhLIH6P7F@VHPx#wMj%lR7ef&Q^5^`Fc2fCE5JTX!E!9nC145O3;;uBC4LbGP{&k$mP!^e-NkwruXhaoA>@{_nSQkdMF z3kpNthIP1AuAkJwY@hcj^IAGS2}Y-9EZ0RO%o)`_uK)i-$|%KUrwbFlVwOB5@HTMN zm=Eohn79P4cg}6G4%iCg4)`1W)yA^2E(u(azz07;HLq{{LEQiV002ovPDHLkV1mSd BW_Sd4!HbK=MJQlptJehDYE z)YR{ri|x)?e%O)O!~ubRv8`GaweZ{u+f~cw&oE$g$PTeE)7v-u15Z}qf~e%r_FEZF z_sYiH*!JsJ%g+4Dbs9JIAG8HB>6k0dSz7C9X05(4edn~fo44qnOna{KP3QWi;%VPh zZ@!sxWZu)LGQTW&Hun{|vB@v%a<8kumTBVCu-Dr$V~g#R?fadNZEnB%<9sp4@9!mF z*Ko}gIakWi_?d0N?-fj)wUi77bEMEa#}Dm=#D(xOwns z%Na2}wv=xLLMM_Q>}%BFdnbG%>0y+EUw3;ob0up+@s8~_AM@w@bu>wr`Eya$pCdwV zj`(+`O*K0hiWo0MU)XiOky|01!Ddm}ipKx*jCn6GfKW=_1HO6frdOs!2rdSOJA literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_arrow_left_white.png b/android/app/src/main/res/drawable-xhdpi/icon_arrow_left_white.png new file mode 100644 index 0000000000000000000000000000000000000000..182a421947d2d988f50463e8fe94771cb33c8f93 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^T|LRJ&s9Fj??Vno@^j(s?Wbs z<0xa@jCzIpntvFB&hTg6Q)8U;pE>q;3csUVt@P6GtzUVpG=8q}zF#;e`&!ats~P2r z(S?VO@g^5XN_}kV*8To)-)9}W6yH!k6F2|G*Oq))b~)s-CSP`JPxXp*U%Kueh&=gH zr&i?sg0+5=19jI`F?6n9Bc;8V_j5*5v78eBhmGZ*)RH`kyq4T?xxY+x@_UCx@_%?O z9vx(<(qfHGjeV0^Aza?0WV0eR=Q!uPgk7w@3)2oIFGKd8#{=&N%$yTFJ&KGaK|#&n M>FVdQ&MBb@07;>iKmY&$ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_close_white.png b/android/app/src/main/res/drawable-xhdpi/icon_close_white.png index 5c8005f904a4aaadbf49206285f7f7aedeae3984..dcdf4125035082654f49b45791fc1d206d804a54 100644 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^T=#-##<_C7(^TJl>@9-moiTVeX!fPbJUhZJaSJSvuH6T(;e7 z{n}fQ}iM&ides#nvN11#2{zggO%| zovipLxJx&6vKc1ys72YUu49Xc_ST#?bqUk0lH}Bnft6go4?dRfSQou2V;jc`_wqfZ z1)P6$cQ>y49C~NF?1sXVdP`=o?O41x`GDE?$Ny(B#B$!7Cw@I>PPXqM2BTSFeF1ye z&n)IWSkbKHFi}EZd}%&oX6Moe=UfmdKI;Vst0BPfz-v9sr literal 329 zcmV-P0k-~$P)Px$14%?dR7efQRzVJfFbqR`TwlNu9?!&{F?BX5Q(HA5DVi3^bUpcSX)P6M`7y7ETI1o=I2YMdiC z5|*oR8Qgl*Mxts0&I0(mkC=qTWfUHhVe!I5Yn|8Cd%}0EMkl?QtN)W}rc{f|-=Nu; zxHwY)Xsf1!OZ*{1e_4&{*#X1VMYnj6d!wOXJFd8iA%6ccwZx@WPmbhPYlIldJxsy` zu-qJXV%6_?a>+%4w&A$nP{U+qo7|wwh(C7vxQ;Ee-Spj+w-ZB^D^R{C$EN>_&lY}2 bu<-N&>}@IStlO{$00000NkvXXu0mjf6AO+w diff --git a/android/app/src/main/res/drawable-xhdpi/icon_ok_white.png b/android/app/src/main/res/drawable-xhdpi/icon_ok_white.png new file mode 100644 index 0000000000000000000000000000000000000000..9ee251d97693f1f96ede5f1d2b9d48e98d72cb1b GIT binary patch literal 934 zcmeAS@N?(olHy`uVBq!ia0vp^1t8491|*L?_~H$u7>k44ofy`glX=O&z?|Ue;uuoF z_;#*s-xUV|w{k}%^#^RH1vxBP885PFD;e!z>Iha~ViFKCRBYmQ*d}zH!Aaoo^`7V? zo&Q_kYL#z~_coRLUlMw~`qLRUW9#&E9u5ZvCV>V976k@IqM2n54+<=7f@(tlgwzDa zyj$@0Q}mP-v%9u;t^2s=51;lshht59%446+O5VS9Z?s`kQS{^)hLsmzhrapbR&%H< zn#plq*ax?d1-GXL*v@n~G*|rHfe%7e6JuI9%~*tk z|2k z69;7NllmJx`$+5wZl=QloBh?ec&4ZRFIr`K?I-)`!0_*jXVpo)@sYXdb>-K0b$zYS z&#vBgw(hy4s-!PC)AdRn{(@;Qr^#l2D$tPJiwv*TQp(x)^J&$&rJ z{z^5mnEl&ap6E_6EPoXxG|~L}0j|%}yj<>a2~ArzLtC)Y`{a6y`nDt1vy8t8=UCMm zefqcKcbAU2x9S~D`SU*t7o}IQSH^`2tMX-A&vTtOeNRNXYv+mXfW6zbJzVB(-%_@h zRcPY%ww+i1@pPWJ?G+Y(m!>*gI_3q5Pr{8;)z`o!(1OA)m*cL%k||H$p1Zgt>% zUmxR{hkIP^2JZ=v(YDi&d$K|A8lfcq&HI6Vab%OX09(>CV8&zcboFyt=akR{0A*x` AVgLXD literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_arrow_left_white.png b/android/app/src/main/res/drawable-xxhdpi/icon_arrow_left_white.png new file mode 100644 index 0000000000000000000000000000000000000000..ac7ad9ee16dbabec3269814fc01f3151079f7e56 GIT binary patch literal 549 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-D%z?|Zs9hEy=V zy}8kg*-_xw$2m(|7p%xn%uH9_mX!EjJ0db_wv&L+L9d{n4Aa6YnY0C21aoxWxHwKw zn0H@{-O;Rk^64iXv;Q9w$jdL!dp=$Dw(2^6WJ^D>% zO0IUG#Of~VqXoaO9bKmDd}witz+ue=dg&{_v@R1DF8Fe0UsCds&EoD~mfw%vSllJM zW&S>wB~HqI=0>J}^_0(5{t}wVb+B`RNbCa7OgH%OikzL1SP*+*Rc3x zsy&nQJL#hnmH5Ta={~7Bx9QDk%lA)SwrpPWqk3CV_~YCK>hpZ!CKj{luDWjF`jeU8 z#_Nks_uERH6Nbmvx$F5aDDP*rd{*)K#8b|aXB!ok%P>FP`QgOVzq;2hF5=S``?lz} zylC>Pd;cyTad(ZrpR&DlvQOzeJ9F!&^XLBD`)<8|so>^$GAf6yS%f^;7!M1SL8!-m zQN~NW$~zb}Wy+p^&!7L{n)HOe%XgKIozj}Ht~c|NTv*c;zulh_L` literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_close_white.png b/android/app/src/main/res/drawable-xxhdpi/icon_close_white.png index 32e84becb684c21a652a8362e1f01918fa280ca9..6f6b57979f1ec012e75a520743c8a533060b4e2c 100644 GIT binary patch literal 603 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-HD>U=sCoaSW+o zd^^iA@34Y^>*G~H>#yk)&$_cF)bGLXlIv4HFYhwH@qjUnVQ0Nci0I)n|M{H)AD?b@ zWKwa!iDEf)P8YdWFF2b~zNI{0G3arqcb3;%|M#<8f4WLUNyNYSq2aY+hRV*1OWY*F zkAB(aydWSfUq41+VE|8GM#YxW^()u{Hyuq*ILleO;>48~N;#b%D&w#1qQPm76NE{FUeJeB8$~{{X{&3!jfH3Uyy= z7&6$FM9jEX7x?7Gqs(ugnx5{ru2W*zf3be{vX|zcYUL`4jCXS`aCRLnyHuec&{@GD_fT|?;lq~Ir|)|Px$OG!jQR9Fesm|+gWAPj|x35lM2{`5*7XUT3c-&08#0)w_B*rZOBzW0e8$#DC= zd*mItA~)m%d3A$>9$znd(tAOAhZn-6@x%wWQB2fE(j$$9K%~pX5GWXxV92l%h)Y%q zQz)3!V92l$h&@va6DSy*!I0rWAU0R-|Kx-aDkzAwz|iA!Gj$YnH@a9`Tv)jk)tYL7 z2+mB)LdZfR`fZMl-r9seJ*BBVK%@hSu%ssSt&V#PdgfM5&%W$18oHMqI2)lbtr)6} z^#BtFuxe@a9FaYY0%{zL07?XN2}XZ;74(s4m6{eu023PA9!ddY57h|6RbbXazfw?d z*?ZnbJ#(9SB%LHNkkq8U*|A1gQ)>8Dhk-@(J`Wd|cSL)FFWmy97>k44ofy`glX=O&!1~(L#WAFU z@$FpuY>`BPc3W*-7i;T{n?yvkrT>d$@@O9APe^@i{(-xrDIrxc;ugoWm0N^$SfmBt zxU6O2Hk>L^-|e|$PW8!q@6Np2^WKL0@Y{Xct*t+wnLIW4k*wt*HbxEy1}1?91{MVd zdNP-(Y}mWE*7sw~N6(MWAEOHW3v*8G+EHG_)Z5T?yvx38+uOxr`l`oWeg_LosOX(D zJ2y;kP3^^xCpEL4%=6^**s-qY-L79Mnp(HyW;^g(N_+0_k5&Kf?Xh6_oZbaz%hKd- zUi``YP0?UV1538u#Qh;_c+VdFDqx^`;l#=ppBg=uZ_WGvSMa>>l@gcA$)4uj>d(9P zu)Ms}>!7?m>BQvCm2*B__sJ9XnsdYBobJ<|lO&YaRtp$R`Mk@$_KA-VgQYOPebws| zlC@5qubs~wIoyBGs>p4Az@uLij6Z%@yuEMEMfE8=?4J18{CTlfIsFT#>NOt>>{}$hlGBHqIU}u)TJ1o^q2|0x~beSr&{Ai zryGOiZFQsU_4mRqIl(Nz&V{hDUt57$-P`E##opa1KuUwP~S-;;ay%*i?;X8F6% z`@=cSZB`t&=6qW4zIIcbdfExglpjn#wixEOzI{01cj~S%pNYjU4zPaw%T@Gl-l@r7 z1U{Uoe{*cI}UQ&S!plU$XaPZRU50vlnfu4*r-9QkXe^Nm8n+y8pS< zN!*`gStsc+Z%MfuaIWUR)0UQ(mr_+?yOw?BeUfwZ(e92VcYi3QoBQddE51A!G4XSP z-QqpnOWw|yxOwhrmDL`*f+{7qEE^02hff&-mEBN#U8FKd|yG&Jc9N5~5gpz9aR z6c6v(yyQgW96?6zGN8T8=XTwg)B{rD%Mr6<;*t}R6~~TFHwy@QqI0i-N$Q2BW|5e| z?JTb;OSX&jmc*JpS(EmO)l|v&x@dcCu5yu>$>mpGQx}+v#Ea(Mw$`1ue%;G1=~-8A z%vP~kx-U;#PwSkPoyI+ld1uo$->*t-red-ASm+10!u)!fnZh$%fOPmdKI;Vst E05?LJ4FCWD literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_arrow_left_white.png b/android/app/src/main/res/drawable-xxxhdpi/icon_arrow_left_white.png new file mode 100644 index 0000000000000000000000000000000000000000..3fccc8e8f039afc0f222f05653b04e41225b18ca GIT binary patch literal 767 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>VA|>F;uuoF z`1aOWFBwOXwuf@OjGId)H-rn6WI6~i{oFZ$h4z0x|N zHQ~{Fw@n@nvim1Va#$trvM%+z?z5M*J@fXf;L!6MrP8aqn%WqcI20O)CwRHG+ zbTZrW3C}M$)i1pfTyndQFYWV{g1D^rq?*sj+k;?o(OfMwGGS%svl&U&s`onileV-OWAQ z*o^NpMjhEA_R-TYYp+D}AMsO`i|>B8s_@w!Y5!%wR@oh~|a7rKE`pYFOcp*pgzdeeAALTAR~lELPSJH^=2~=ePQ3a7@DYX+foeaB^W2-~BZ+f^EWMG!HRP pPJKJ6z{i<^kww6P6hfmb+akNk_(9>0SHKj_;OXk;vd$@?2>=OSKG^^O literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_close_white.png b/android/app/src/main/res/drawable-xxxhdpi/icon_close_white.png index 68dbc7fb364667409f872de8f9ca3b08c2fa1715..6493a26160726308e1c77516cb6bba822b848709 100644 GIT binary patch literal 886 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>U^eh{aSW+o zd^_iKuC$>*+ggzc&DEW;P5qh&N|&(7$G9sT*dD`cF0f?66OkjLC;s0!eOk%8NW-oy z{5}KA+Na5B`{wVSqS_H2F2SO}z{ugiz$DPXKm>DxIa7Na=Ul(#)jxl&Dq8!=`{~C5 zi$9^ZcSL3%{o?zyyX)u|=Z&@Dd-;Q#+^6pRd#&~MMad{0t@>vNUw$nt$qD_VJ@NN{ z6>+`2ulf^}X5@=@C!Tz>?(R0t&C8d*S@zo5Wx{)r8t(TiP5=6@mCdND-goTHW~uqS z9&3WnZaaB>^D~qChTcczq-S5f=FD)rAo!Xu3wuqsrTVv!yyV+cKWy#F-C=p{OW_iR zA~|bCzwVtsWiPnOra$s^iE!qLP0+WL6{nOS$^(QpVH&mQh4($t3$E*oi)CHHof$}Y3&;DeF@|J z-J4pj+*|Z)-Mbk~2fiQT|Et}>@P}dZ7CWFR)1Bt`YYQYAf2giewR|4==~sxsiWHy5 z*>m|XzSfnMla;=(T)uo=?T7?pO3V4sE<>Rs9`{!ZB=a&{6F4kj zIAzCkbuV9gt%9x%{qr?6U$Re?$>y?OW5@dF=Z5!+J-2h#w!|B~C~uTkuyU#3Opdy0 zyH9xAX7QwNtBzUEJ^R7<+RC)sPhR^K&w4*&X;Oc0to!V+=r=2x)@j%KsXX?(@h^~d z+7=<(RcFqc?R+@@a0HK**y%gFWUd`7G?nL0xqtlXnf%%~XJXSUByIb0?qU3scs63k T)H!#68HvHu)z4*}Q$iB}dUt~$ literal 546 zcmV+-0^R+IP)Px$+(|@1RA>d|n!#>^Fc3teenoD4ivKme<-a0DJyyNb8CoPn!K}TrI9690g@C>L z#$XExUoMDo9Iwy~dO%O;4h_8a3PF}%CbE%{tk;Q+2haz!j!&FOtqqU?BFj3+eC6oB zudgirf8n^93D$9Tzly?&946SkMjil9-#wnH^EDtf zeX8KBohpE&i-46g+pf?AnjeN~1h}{9;Jg3G*ZpVK?mu*M5>W8vp)FFWmy97>k44ofy`glX=O&!1~(L#WAFU z@$FpuY>`BPc3W*-7i;T{n?yvkrT>d$@@O9APe^@i{(-xrDIrxc;ugoWm0N^$SfmBt zxU6O2Hk>L^-|e|$PW8!q@6Np2^WKL0@Y{Xct*t+wnLIW4k*wt*HbxEy1}1?91{MVd zdNP-(Y}mWE*7sw~N6(MWAEOHW3v*8G+EHG_)Z5T?yvx38+uOxr`l`oWeg_LosOX(D zJ2y;kP3^^xCpEL4%=6^**s-qY-L79Mnp(HyW;^g(N_+0_k5&Kf?Xh6_oZbaz%hKd- zUi``YP0?UV1538u#Qh;_c+VdFDqx^`;l#=ppBg=uZ_WGvSMa>>l@gcA$)4uj>d(9P zu)Ms}>!7?m>BQvCm2*B__sJ9XnsdYBobJ<|lO&YaRtp$R`Mk@$_KA-VgQYOPebws| zlC@5qubs~wIoyBGs>p4Az@uLij6Z%@yuEMEMfE8=?4J18{CTlfIsFT#>NOt>>{}$hlGBHqIU}u)TJ1o^q2|0x~beSr&{Ai zryGOiZFQsU_4mRqIl(Nz&V{hDUt57$-P`E##opa1KuUwP~S-;;ay%*i?;X8F6% z`@=cSZB`t&=6qW4zIIcbdfExglpjn#wixEOzI{01cj~S%pNYjU4zPaw%T@Gl-l@r7 z1U{Uoe{*cI}UQ&S!plU$XaPZRU50vlnfu4*r-9QkXe^Nm8n+y8pS< zN!*`gStsc+Z%MfuaIWUR)0UQ(mr_+?yOw?BeUfwZ(e92VcYi3QoBQddE51A!G4XSP z-QqpnOWw|yxOwhrmDL`*f+{7qEE^02hff&-mEBN#U8FKd|yG&Jc9N5~5gpz9aR z6c6v(yyQgW96?6zGN8T8=XTwg)B{rD%Mr6<;*t}R6~~TFHwy@QqI0i-N$Q2BW|5e| z?JTb;OSX&jmc*JpS(EmO)l|v&x@dcCu5yu>$>mpGQx}+v#Ea(Mw$`1ue%;G1=~-8A z%vP~kx-U;#PwSkPoyI+ld1uo$->*t-red-ASm+10!u)!fnZh$%fOPmdKI;Vst E05?LJ4FCWD literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_left_white.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_arrow_left_white.imageset/Contents.json new file mode 100644 index 0000000000..1c822daff6 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_arrow_left_white.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_arrow_left_white.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_left_white.imageset/icon_arrow_left_white.png b/ios/StatusIm/Images.xcassets/icon_arrow_left_white.imageset/icon_arrow_left_white.png new file mode 100644 index 0000000000000000000000000000000000000000..3fccc8e8f039afc0f222f05653b04e41225b18ca GIT binary patch literal 767 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>VA|>F;uuoF z`1aOWFBwOXwuf@OjGId)H-rn6WI6~i{oFZ$h4z0x|N zHQ~{Fw@n@nvim1Va#$trvM%+z?z5M*J@fXf;L!6MrP8aqn%WqcI20O)CwRHG+ zbTZrW3C}M$)i1pfTyndQFYWV{g1D^rq?*sj+k;?o(OfMwGGS%svl&U&s`onileV-OWAQ z*o^NpMjhEA_R-TYYp+D}AMsO`i|>B8s_@w!Y5!%wR@oh~|a7rKE`pYFOcp*pgzdeeAALTAR~lELPSJH^=2~=ePQ3a7@DYX+foeaB^W2-~BZ+f^EWMG!HRP pPJKJ6z{i<^kww6P6hfmb+akNk_(9>0SHKj_;OXk;vd$@?2>=OSKG^^O literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_close_white.imageset/icon_close_white.png b/ios/StatusIm/Images.xcassets/icon_close_white.imageset/icon_close_white.png index 32e84becb684c21a652a8362e1f01918fa280ca9..dcdf4125035082654f49b45791fc1d206d804a54 100644 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^T=#-##<_C7(^TJl>@9-moiTVeX!fPbJUhZJaSJSvuH6T(;e7 z{n}fQ}iM&ides#nvN11#2{zggO%| zovipLxJx&6vKc1ys72YUu49Xc_ST#?bqUk0lH}Bnft6go4?dRfSQou2V;jc`_wqfZ z1)P6$cQ>y49C~NF?1sXVdP`=o?O41x`GDE?$Ny(B#B$!7Cw@I>PPXqM2BTSFeF1ye z&n)IWSkbKHFi}EZd}%&oX6Moe=UfmdKI;Vst0BPfz-v9sr literal 401 zcmV;C0dD?@P)Px$OG!jQR9Fesm|+gWAPj|x35lM2{`5*7XUT3c-&08#0)w_B*rZOBzW0e8$#DC= zd*mItA~)m%d3A$>9$znd(tAOAhZn-6@x%wWQB2fE(j$$9K%~pX5GWXxV92l%h)Y%q zQz)3!V92l$h&@va6DSy*!I0rWAU0R-|Kx-aDkzAwz|iA!Gj$YnH@a9`Tv)jk)tYL7 z2+mB)LdZfR`fZMl-r9seJ*BBVK%@hSu%ssSt&V#PdgfM5&%W$18oHMqI2)lbtr)6} z^#BtFuxe@a9FaYY0%{zL07?XN2}XZ;74(s4m6{eu023PA9!ddY57h|6RbbXazfw?d z*?ZnbJ#(9SB%LHNkkq8U*|A1gQ)>8Dhk-@(J`Wd|cSLSd4!HbK=MJQlptJehDYE z)YR{ri|x)?e%O)O!~ubRv8`GaweZ{u+f~cw&oE$g$PTeE)7v-u15Z}qf~e%r_FEZF z_sYiH*!JsJ%g+4Dbs9JIAG8HB>6k0dSz7C9X05(4edn~fo44qnOna{KP3QWi;%VPh zZ@!sxWZu)LGQTW&Hun{|vB@v%a<8kumTBVCu-Dr$V~g#R?fadNZEnB%<9sp4@9!mF z*Ko}gIakWi_?d0N?-fj)wUi77bEMEa#}Dm=#D(xOwns z%Na2}wv=xLLMM_Q>}%BFdnbG%>0y+EUw3;ob0up+@s8~_AM@w@bu>wr`Eya$pCdwV zj`(+`O*K0hiWo0MU)XiOky|01!Ddm}ipKx*jCn6GfKW=_1HO6frdOs!2rdSOJA literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_ok_white.imageset/iconOkBig@2x.png b/ios/StatusIm/Images.xcassets/icon_ok_white.imageset/iconOkBig@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9ee251d97693f1f96ede5f1d2b9d48e98d72cb1b GIT binary patch literal 934 zcmeAS@N?(olHy`uVBq!ia0vp^1t8491|*L?_~H$u7>k44ofy`glX=O&z?|Ue;uuoF z_;#*s-xUV|w{k}%^#^RH1vxBP885PFD;e!z>Iha~ViFKCRBYmQ*d}zH!Aaoo^`7V? zo&Q_kYL#z~_coRLUlMw~`qLRUW9#&E9u5ZvCV>V976k@IqM2n54+<=7f@(tlgwzDa zyj$@0Q}mP-v%9u;t^2s=51;lshht59%446+O5VS9Z?s`kQS{^)hLsmzhrapbR&%H< zn#plq*ax?d1-GXL*v@n~G*|rHfe%7e6JuI9%~*tk z|2k z69;7NllmJx`$+5wZl=QloBh?ec&4ZRFIr`K?I-)`!0_*jXVpo)@sYXdb>-K0b$zYS z&#vBgw(hy4s-!PC)AdRn{(@;Qr^#l2D$tPJiwv*TQp(x)^J&$&rJ z{z^5mnEl&ap6E_6EPoXxG|~L}0j|%}yj<>a2~ArzLtC)Y`{a6y`nDt1vy8t8=UCMm zefqcKcbAU2x9S~D`SU*t7o}IQSH^`2tMX-A&vTtOeNRNXYv+mXfW6zbJzVB(-%_@h zRcPY%ww+i1@pPWJ?G+Y(m!>*gI_3q5Pr{8;)z`o!(1OA)m*cL%k||H$p1Zgt>% zUmxR{hkIP^2JZ=v(YDi&d$K|A8lfcq&HI6Vab%OX09(>CV8&zcboFyt=akR{0A*x` AVgLXD literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_ok_white.imageset/iconOkBig@3x.png b/ios/StatusIm/Images.xcassets/icon_ok_white.imageset/iconOkBig@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..54080186bc998b644f1525f580fda7e031278fd2 GIT binary patch literal 1585 zcmeAS@N?(olHy`uVBq!ia0vp^D?pfo4M>)FFWmy97>k44ofy`glX=O&!1~(L#WAFU z@$FpuY>`BPc3W*-7i;T{n?yvkrT>d$@@O9APe^@i{(-xrDIrxc;ugoWm0N^$SfmBt zxU6O2Hk>L^-|e|$PW8!q@6Np2^WKL0@Y{Xct*t+wnLIW4k*wt*HbxEy1}1?91{MVd zdNP-(Y}mWE*7sw~N6(MWAEOHW3v*8G+EHG_)Z5T?yvx38+uOxr`l`oWeg_LosOX(D zJ2y;kP3^^xCpEL4%=6^**s-qY-L79Mnp(HyW;^g(N_+0_k5&Kf?Xh6_oZbaz%hKd- zUi``YP0?UV1538u#Qh;_c+VdFDqx^`;l#=ppBg=uZ_WGvSMa>>l@gcA$)4uj>d(9P zu)Ms}>!7?m>BQvCm2*B__sJ9XnsdYBobJ<|lO&YaRtp$R`Mk@$_KA-VgQYOPebws| zlC@5qubs~wIoyBGs>p4Az@uLij6Z%@yuEMEMfE8=?4J18{CTlfIsFT#>NOt>>{}$hlGBHqIU}u)TJ1o^q2|0x~beSr&{Ai zryGOiZFQsU_4mRqIl(Nz&V{hDUt57$-P`E##opa1KuUwP~S-;;ay%*i?;X8F6% z`@=cSZB`t&=6qW4zIIcbdfExglpjn#wixEOzI{01cj~S%pNYjU4zPaw%T@Gl-l@r7 z1U{Uoe{*cI}UQ&S!plU$XaPZRU50vlnfu4*r-9QkXe^Nm8n+y8pS< zN!*`gStsc+Z%MfuaIWUR)0UQ(mr_+?yOw?BeUfwZ(e92VcYi3QoBQddE51A!G4XSP z-QqpnOWw|yxOwhrmDL`*f+{7qEE^02hff&-mEBN#U8FKd|yG&Jc9N5~5gpz9aR z6c6v(yyQgW96?6zGN8T8=XTwg)B{rD%Mr6<;*t}R6~~TFHwy@QqI0i-N$Q2BW|5e| z?JTb;OSX&jmc*JpS(EmO)l|v&x@dcCu5yu>$>mpGQx}+v#Ea(Mw$`1ue%;G1=~-8A z%vP~kx-U;#PwSkPoyI+ld1uo$->*t-red-ASm+10!u)!fnZh$%fOPmdKI;Vst E05?LJ4FCWD literal 0 HcmV?d00001 diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 16125f6bcd..b5f6bdf709 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -22,7 +22,9 @@ [status-im.accounts.login.screen :refer [login]] [status-im.accounts.recover.screen :refer [recover]] [status-im.accounts.screen :refer [accounts]] - [status-im.transactions.screen :refer [confirm]] + [status-im.transactions.screens.confirmation-success :refer [confirmation-success]] + [status-im.transactions.screens.pending-transactions :refer [pending-transactions]] + [status-im.transactions.screens.transaction-details :refer [transaction-details]] [status-im.chats-list.screen :refer [chats-list]] [status-im.new-chat.screen :refer [new-chat]] [status-im.new-group.screen-public :refer [new-public-group]] @@ -149,7 +151,9 @@ (let [component (case @modal-view :qr-scanner qr-scanner :qr-code-view qr-code-view - :confirm confirm + :pending-transactions pending-transactions + :transaction-details transaction-details + :confirmation-success confirmation-success :contact-list-modal contact-list-modal)] [component])]])]]))))}))) diff --git a/src/status_im/chat/handlers/send_message.cljs b/src/status_im/chat/handlers/send_message.cljs index 7599620e66..0cb5d94d53 100644 --- a/src/status_im/chat/handlers/send_message.cljs +++ b/src/status_im/chat/handlers/send_message.cljs @@ -73,7 +73,7 @@ (if (:sent-to-jail? message) ;; todo there could be other reasons for "long-running" ;; hanling of the command besides sendTransaction - (dispatch [:navigate-to-modal :confirm]) + (dispatch [:navigate-to-modal :pending-transactions]) (cond (console-command? chat-id command-name) (dispatch [:invoke-console-command-handler! params']) diff --git a/src/status_im/components/common/common.cljs b/src/status_im/components/common/common.cljs index 6b1ba9e108..26c914e44b 100644 --- a/src/status_im/components/common/common.cljs +++ b/src/status_im/components/common/common.cljs @@ -16,8 +16,8 @@ {:style st/gradient-top :colors st/gradient-top-colors}])) -(defn separator [style] - [view st/separator-wrapper +(defn separator [style wrapper-style] + [view (merge st/separator-wrapper wrapper-style) [view (merge st/separator style)]]) (defn form-spacer [] diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 972d71c7ef..15e7ac1697 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -13,12 +13,19 @@ (def color-gray6 "#212121") (def color-steel "#838b91") (def color-white "white") +(def color-white-transparent "#ffffff66") +(def color-white-transparent-2 "#fefefe21") (def color-light-blue "#628fe3") (def color-light-blue-transparent "#628fe333") (def color-light-blue2 "#eff3fc") +(def color-light-blue3 "#a0bcf0") +(def color-dark-blue-1 "#252c4a") +(def color-dark-blue-2 "#1f253f") +(def color-dark-blue-3 "#191f37") (def color-light-gray "#EEF2F5") (def color-red "red") (def color-light-red "#e86363") +(def color-light-red2 "#f47979") (def color-separator "#D6D6D6") diff --git a/src/status_im/components/text_field/styles.cljs b/src/status_im/components/text_field/styles.cljs index abe1148428..49b5ff4b53 100644 --- a/src/status_im/components/text_field/styles.cljs +++ b/src/status_im/components/text_field/styles.cljs @@ -41,4 +41,5 @@ (merge input-error-text-style {:color color :background-color :transparent - :font-size 12}))) + :font-size 12 + :line-height 20}))) diff --git a/src/status_im/components/text_field/view.cljs b/src/status_im/components/text_field/view.cljs index b7f7b45c95..cd2d9af8b9 100644 --- a/src/status_im/components/text_field/view.cljs +++ b/src/status_im/components/text_field/view.cljs @@ -115,8 +115,8 @@ max-length]} (r/state component) {:keys [wrapper-style input-style label-hidden? line-color focus-line-color focus-line-height secure-text-entry label-color error-color error label value on-focus on-blur validator - auto-focus on-change-text on-change on-end-editing editable placeholder auto-capitalize - multiline number-of-lines]} + auto-focus on-change-text on-change on-end-editing editable placeholder + placeholder-text-color auto-capitalize multiline number-of-lines]} (merge default-props (r/props component)) line-color (if error error-color line-color) focus-line-color (if error error-color focus-line-color) @@ -126,50 +126,51 @@ [view (merge st/text-field-container wrapper-style) (when-not label-hidden? [animated-text {:style (st/label label-top label-font-size label-color)} label]) - [text-input {:ref #(reset! input-ref %) - :style (merge st/text-input input-style) - :placeholder (or placeholder "") - :editable editable - :multiline multiline - :number-of-lines number-of-lines - :secure-text-entry secure-text-entry - :auto-capitalize auto-capitalize - :on-focus #(on-input-focus {:component component - :animation {:top label-top - :to-top (:label-top config) - :font-size label-font-size - :to-font-size (:label-font-small config) - :line-width line-width - :line-height line-height - :to-line-height focus-line-height} - :onFocus on-focus}) - :on-blur #(on-input-blur {:component component - :value (or current-value value) - :animation {:top label-top - :to-top (:label-bottom config) - :font-size label-font-size - :to-font-size (:label-font-large config) - :line-width line-width - :line-height line-height - :to-line-width 0 - :to-line-height 1} - :onBlur on-blur}) - :on-change-text (fn [text] - (r/set-state component {:current-value text}) - (if (or (not validator) (validator text)) - (do - (r/set-state component {:valid-value text - :temp-value nil}) - (on-change-text text)) - (r/set-state component {:temp-value valid-value - :max-length (count valid-value)}))) - :on-change #(on-change %) - :default-value value - :value temp-value - :max-length max-length - :on-submit-editing #(.blur @input-ref) - :on-end-editing (when on-end-editing on-end-editing) - :auto-focus (true? auto-focus)}] + [text-input {:ref #(reset! input-ref %) + :style (merge st/text-input input-style) + :placeholder (or placeholder "") + :placeholder-text-color placeholder-text-color + :editable editable + :multiline multiline + :number-of-lines number-of-lines + :secure-text-entry secure-text-entry + :auto-capitalize auto-capitalize + :on-focus #(on-input-focus {:component component + :animation {:top label-top + :to-top (:label-top config) + :font-size label-font-size + :to-font-size (:label-font-small config) + :line-width line-width + :line-height line-height + :to-line-height focus-line-height} + :onFocus on-focus}) + :on-blur #(on-input-blur {:component component + :value (or current-value value) + :animation {:top label-top + :to-top (:label-bottom config) + :font-size label-font-size + :to-font-size (:label-font-large config) + :line-width line-width + :line-height line-height + :to-line-width 0 + :to-line-height 1} + :onBlur on-blur}) + :on-change-text (fn [text] + (r/set-state component {:current-value text}) + (if (or (not validator) (validator text)) + (do + (r/set-state component {:valid-value text + :temp-value nil}) + (on-change-text text)) + (r/set-state component {:temp-value valid-value + :max-length (count valid-value)}))) + :on-change #(on-change %) + :default-value value + :value temp-value + :max-length max-length + :on-submit-editing #(.blur @input-ref) + :on-end-editing (when on-end-editing on-end-editing) + :auto-focus (true? auto-focus)}] [view {:style (st/underline-container line-color) :onLayout #(r/set-state component {:max-line-width (get-width %)})} [animated-view {:style (st/underline focus-line-color line-width line-height)}]] diff --git a/src/status_im/components/toolbar_new/actions.cljs b/src/status_im/components/toolbar_new/actions.cljs index 7153620901..5dd0cc6467 100644 --- a/src/status_im/components/toolbar_new/actions.cljs +++ b/src/status_im/components/toolbar_new/actions.cljs @@ -45,3 +45,7 @@ :style st/action-default} :handler handler}) +(defn close-white [handler] + {:image {:source {:uri :icon_close_white} + :style st/action-default} + :handler handler}) diff --git a/src/status_im/components/toolbar_new/view.cljs b/src/status_im/components/toolbar_new/view.cljs index 400af551aa..a7b78f4488 100644 --- a/src/status_im/components/toolbar_new/view.cljs +++ b/src/status_im/components/toolbar_new/view.cljs @@ -25,6 +25,7 @@ background-color :background-color custom-content :custom-content hide-border? :hide-border? + border-style :border-style style :style}] (let [style (merge (st/toolbar-wrapper background-color) style)] [view {:style style} @@ -66,7 +67,7 @@ custom-action)]] [sync-state-gradient-view] (when-not hide-border? - [view st/toolbar-border-container + [view (merge st/toolbar-border-container border-style) [view st/toolbar-border]])])) (def search-text-input (r/atom nil)) @@ -122,4 +123,3 @@ nav-action) :custom-content [toolbar-with-search-content opts] :actions actions}])) - diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 9e7652a71b..86c7491092 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -20,7 +20,9 @@ [status-im.accounts.login.screen :refer [login]] [status-im.accounts.recover.screen :refer [recover]] [status-im.accounts.screen :refer [accounts]] - [status-im.transactions.screen :refer [confirm]] + [status-im.transactions.screens.confirmation-success :refer [confirmation-success]] + [status-im.transactions.screens.pending-transactions :refer [pending-transactions]] + [status-im.transactions.screens.transaction-details :refer [transaction-details]] [status-im.chats-list.screen :refer [chats-list]] [status-im.new-chat.screen :refer [new-chat]] [status-im.new-group.screen-private :refer [new-group @@ -131,7 +133,9 @@ (let [component (case @modal-view :qr-scanner qr-scanner :qr-code-view qr-code-view - :confirm confirm + :pending-transactions pending-transactions + :transaction-details transaction-details + :confirmation-success confirmation-success :contact-list-modal contact-list-modal)] [component])]])]))))}))) diff --git a/src/status_im/transactions/handlers.cljs b/src/status_im/transactions/handlers.cljs index 93edf230e2..bf9f20721f 100644 --- a/src/status_im/transactions/handlers.cljs +++ b/src/status_im/transactions/handlers.cljs @@ -22,7 +22,7 @@ ;; && :navigation-replace <- on success -(defmethod nav/preload-data! :confirm +(defmethod nav/preload-data! :pending-transactions [{:keys [transactions-queue] :as db} _] (-> db (assoc :transactions transactions-queue @@ -30,6 +30,14 @@ :wrong-password? false) (assoc-in [:confirm-transactions :password] ""))) +(defmethod nav/preload-data! :transaction-details + [db [_ _ transaction]] + (-> db + (assoc :selected-transaction transaction + :wrong-password-counter 0 + :wrong-password? false) + (assoc-in [:confirm-transactions :password] ""))) + (defn on-unlock [ids password] (dispatch [:set :wrong-password? false]) @@ -47,6 +55,11 @@ (let [ids (keys transactions)] (on-unlock ids password))))) +(register-handler :accept-transaction + (u/side-effect! + (fn [{:keys [transactions]} [_ password id]] + (on-unlock (list id) password)))) + (register-handler :deny-transactions (u/side-effect! (fn [{:keys [transactions]}] @@ -56,8 +69,7 @@ (dispatch [::remove-pending-messages messages-ids]) (dispatch [::remove-transactions ids]) (doseq [id ids] - (dispatch [::discard-transaction id])) - (dispatch [:navigate-back]))))) + (dispatch [::discard-transaction id])))))) (register-handler :deny-transaction (u/side-effect! @@ -80,9 +92,6 @@ (update :transactions-queue #(apply dissoc % hashes))))) (register-handler ::remove-transaction - (after (fn [{:keys [modal]}] - (when (= :confirm modal) - (dispatch [:navigate-back])))) (fn [db [_ hash]] (-> db (update :transactions dissoc hash) @@ -119,21 +128,22 @@ (status/discard-transaction id))))) (register-handler ::transaction-queued - (after #(dispatch [:navigate-to-modal :confirm])) + (after #(dispatch [:navigate-to-modal :pending-transactions])) (fn [db [_ {:keys [id message_id args]}]] - (let [{:keys [from to value]} args] + (let [{:keys [from to value data]} args] (if (valid-hex? to) (let [transaction {:id id :from from :to to :value (.toDecimal js/Web3.prototype value) + :data data :message-id message_id}] (assoc-in db [:transactions-queue id] transaction)) db)))) (register-handler :transaction-completed (u/side-effect! - (fn [{:keys [transactions]} [_ {:keys [id response]}]] + (fn [{:keys [transactions modal]} [_ {:keys [id response]}]] (let [{:keys [hash error] :as parsed-response} (t/json->clj response) {:keys [message-id]} (transactions id)] (log/debug :parsed-response parsed-response) @@ -144,7 +154,10 @@ :message-id message-id}]) (dispatch [::check-completed-transaction! {:message-id message-id}])) - (dispatch [::remove-transaction id]))))))) + (dispatch [::remove-transaction id])) + (when (or (= modal :pending-transactions) + (= modal :transaction-details)) + (dispatch [:navigate-to-modal :confirmation-success]))))))) (register-handler ::add-transactions-hash (fn [db [_ {:keys [id hash message-id]}]] @@ -189,10 +202,15 @@ (not= discard-code error_code) (do (when message_id (dispatch [::remove-pending-message message_id])) + (dispatch [:clear-selected-transaction]) (dispatch [::remove-transaction id])) :else nil)))) +(register-handler :clear-selected-transaction + (fn [db _] + (dissoc db :selected-transaction))) + (def attempts-limit 3) (register-handler :set-wrong-password! diff --git a/src/status_im/transactions/screen.cljs b/src/status_im/transactions/screen.cljs deleted file mode 100644 index 29356384b4..0000000000 --- a/src/status_im/transactions/screen.cljs +++ /dev/null @@ -1,62 +0,0 @@ -(ns status-im.transactions.screen - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.components.react :refer [view - text - image - icon - scroll-view - touchable-highlight - touchable-opacity]] - [status-im.components.styles :refer [icon-ok - icon-close]] - [status-im.components.carousel.carousel :refer [carousel]] - [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar]] - [status-im.components.toolbar.styles :refer [toolbar-title-container]] - [status-im.components.text-field.view :refer [text-field]] - [status-im.transactions.views.transaction-page :refer [transaction-page]] - [status-im.transactions.styles :as st] - [status-im.i18n :refer [label label-pluralize]] - [clojure.string :as s])) - -(defview confirm [] - [transactions [:transactions] - {:keys [password]} [:get :confirm-transactions] - wrong-password? [:wrong-password?]] - [view st/transactions-screen - [status-bar {:type :transparent}] - [toolbar - {:style st/transactions-toolbar - :nav-action {:image {:source {:uri :icon_close_white} - :style icon-close} - :handler #(dispatch [:deny-transactions])} - :custom-content [view {:style toolbar-title-container} - [text {:style st/toolbar-title-text} - (label-pluralize (count transactions) :t/confirm-transactions)]] - :actions [{:image {:source {:uri (if-not (s/blank? password) - :icon_ok - :icon_ok_disabled_inversed)} - :style icon-ok} - :handler (when-not (s/blank? password) - #(dispatch [:accept-transactions password]))}]}] - [view st/carousel-container - [carousel {:pageStyle st/carousel-page-style - :gap 8 - :sneak 16 - :count (count transactions)} - (when transactions - (for [transaction transactions] - [transaction-page transaction]))]] - [view st/form-container - [text-field - {:editable true - :error (when wrong-password? (label :t/wrong-password)) - :error-color :#ffffff80 #_:#7099e6 - :label (label :t/password) - :secure-text-entry true - :label-color :#ffffff80 - :line-color :white - :auto-capitalize :none - :input-style st/password-style - :on-change-text #(dispatch [:set-in [:confirm-transactions :password] %])}]]]) diff --git a/src/status_im/transactions/screens/confirmation-success.cljs b/src/status_im/transactions/screens/confirmation-success.cljs new file mode 100644 index 0000000000..aaa7346191 --- /dev/null +++ b/src/status_im/transactions/screens/confirmation-success.cljs @@ -0,0 +1,25 @@ +(ns status-im.transactions.screens.confirmation-success + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :as rf] + [status-im.components.react :as rn] + [status-im.components.sticky-button :as sticky-button] + [status-im.components.status-bar :as status-bar] + [status-im.transactions.views.list-item :as transactions-list-item] + [status-im.transactions.styles.screens :as st] + [status-im.i18n :as i18n])) + +(defview confirmation-success [] + [quantity [:get :confirmed-transactions-count]] + [rn/view {:style st/success-screen} + [status-bar/status-bar {:type :transparent}] + [rn/view {:style st/success-screen-content-container} + [rn/view {:style st/success-icon-container} + [rn/image {:source {:uri :icon_ok_white} + :style st/success-icon}]] + [rn/view + [rn/text {:style st/success-text} + (i18n/label-pluralize quantity :t/transactions-confirmed)]]] + [sticky-button/sticky-button + (i18n/label :t/got-it) + #(do (rf/dispatch [:navigate-back]) + (rf/dispatch [:set :confirmed-transactions-count 0]))]]) diff --git a/src/status_im/transactions/screens/pending-transactions.cljs b/src/status_im/transactions/screens/pending-transactions.cljs new file mode 100644 index 0000000000..5380533b01 --- /dev/null +++ b/src/status_im/transactions/screens/pending-transactions.cljs @@ -0,0 +1,69 @@ +(ns status-im.transactions.screens.pending-transactions + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :as rf] + [status-im.components.common.common :as common] + [status-im.components.react :as rn] + [status-im.components.sticky-button :as sticky-button] + [status-im.components.status-bar :as status-bar] + [status-im.components.toolbar-new.actions :as act] + [status-im.components.toolbar-new.view :as toolbar] + [status-im.transactions.views.list-item :as transactions-list-item] + [status-im.transactions.views.password-form :as password-form] + [status-im.transactions.styles.screens :as st] + [status-im.utils.listview :as lw] + [status-im.utils.platform :as platform] + [status-im.i18n :as i18n])) + +(defn toolbar-view [transactions] + [toolbar/toolbar + {:background-color st/transactions-toolbar-background + :nav-action (act/close-white #(do (rf/dispatch [:deny-transactions]) + (rf/dispatch [:navigate-back]))) + :border-style st/toolbar-border + :custom-content [rn/view {:style st/toolbar-title-container} + [rn/text {:style st/toolbar-title-text + :font :toolbar-title} + (i18n/label :t/pending-transactions)] + [rn/text {:style st/toolbar-title-count + :font :toolbar-title} + (count transactions)]]}]) + +(defn render-separator-fn [transactions-count] + (fn [_ row-id _] + (when (< row-id (dec transactions-count)) + (rn/list-item + ^{:key row-id} + [common/separator {} st/transactions-list-separator])))) + +(defn render-row-fn [row _ _] + (rn/list-item + [rn/touchable-highlight {:on-press #(rf/dispatch [:navigate-to-modal :transaction-details row])} + [rn/view + [transactions-list-item/view row]]])) + +(defview pending-transactions [] + [transactions [:transactions] + {:keys [password]} [:get :confirm-transactions] + confirmed? [:get-in [:transactions-list-ui-props :confirmed?]]] + + {:component-did-update #(when-not (seq transactions) (rf/dispatch [:navigate-back])) + :component-will-unmount #(rf/dispatch [:set-in [:transactions-list-ui-props :confirmed?] false])} + + [(if platform/ios? rn/keyboard-avoiding-view rn/view) (merge {:behavior :padding} st/transactions-screen) + [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] + [toolbar-view transactions] + [rn/view {:style st/transactions-screen-content-container} + [rn/list-view {:style st/transactions-list + :dataSource (lw/to-datasource transactions) + :renderSeparator (render-separator-fn (count transactions)) + :renderRow render-row-fn}] + (when confirmed? + [password-form/view (count transactions)])] + (let [confirm-text (if confirmed? + (i18n/label :t/confirm) + (i18n/label-pluralize (count transactions) :t/confirm-transactions)) + confirm-fn (if confirmed? + #(do (rf/dispatch [:accept-transactions password]) + (rf/dispatch [:set :confirmed-transactions-count (count transactions)])) + #(rf/dispatch [:set-in [:transactions-list-ui-props :confirmed?] true]))] + [sticky-button/sticky-button confirm-text confirm-fn])]) diff --git a/src/status_im/transactions/screens/transaction-details.cljs b/src/status_im/transactions/screens/transaction-details.cljs new file mode 100644 index 0000000000..a8d7ad2a15 --- /dev/null +++ b/src/status_im/transactions/screens/transaction-details.cljs @@ -0,0 +1,70 @@ +(ns status-im.transactions.screens.transaction-details + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :as rf] + [status-im.components.react :as rn] + [status-im.components.common.common :as common] + [status-im.components.sticky-button :as sticky-button] + [status-im.components.status-bar :as status-bar] + [status-im.components.toolbar-new.actions :as act] + [status-im.components.toolbar-new.view :as toolbar] + [status-im.i18n :as i18n] + [status-im.transactions.styles.screens :as st] + [status-im.transactions.views.list-item :as transactions-list-item] + [status-im.transactions.views.password-form :as password-form] + [status-im.utils.platform :as platform])) + +(defn toolbar-view [] + [toolbar/toolbar + {:background-color st/transactions-toolbar-background + :nav-action (act/back-white #(rf/dispatch [:navigate-to-modal :pending-transactions])) + :border-style st/toolbar-border + :custom-content [rn/view {:style st/toolbar-title-container} + [rn/text {:style st/toolbar-title-text + :font :toolbar-title} + (i18n/label :t/transaction)]]}]) + +(defn detail-item [title content name?] + [rn/view {:style st/details-item} + [rn/text {:style st/details-item-title} title] + [rn/text {:style (st/details-item-content name?) + :number-of-lines 1} + content]]) + +(defn detail-data [content] + [rn/view {:style st/details-data} + [rn/text {:style st/details-data-title} (i18n/label :t/data)] + [rn/text {:style st/details-data-content} content]]) + +(defview details [{:keys [to data] :as transaction}] + [current-account [:get-current-account] + recipient [:contact-by-address to]] + (let [recipient-name (or (:name recipient) to)] + [rn/view + [detail-item (i18n/label :t/to) recipient-name true] + [detail-item (i18n/label :t/from) (:name current-account) true] + [detail-data data]])) + +(defview transaction-details [] + [{:keys [id] :as transaction} [:get :selected-transaction] + {:keys [password]} [:get :confirm-transactions] + confirmed? [:get-in [:transaction-details-ui-props :confirmed?]]] + + {:component-did-update #(when-not transaction (rf/dispatch [:navigate-to-modal :pending-transactions])) + :component-will-unmount #(rf/dispatch [:set-in [:transaction-details-ui-props :confirmed?] false])} + + [(if platform/ios? rn/keyboard-avoiding-view rn/view) (merge {:behavior :padding} st/transactions-screen) + [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] + [toolbar-view] + [rn/scroll-view st/details-screen-content-container + [transactions-list-item/view transaction #(rf/dispatch [:navigate-to-modal :pending-transactions])] + (when platform/ios? [common/separator {} st/details-separator]) + [details transaction]] + (when confirmed? [password-form/view 1]) + (let [confirm-text (if confirmed? + (i18n/label :t/confirm) + (i18n/label-pluralize 1 :t/confirm-transactions)) + confirm-fn (if confirmed? + #(do (rf/dispatch [:accept-transaction password id]) + (rf/dispatch [:set :confirmed-transactions-count 1])) + #(rf/dispatch [:set-in [:transaction-details-ui-props :confirmed?] true]))] + [sticky-button/sticky-button confirm-text confirm-fn])]) diff --git a/src/status_im/transactions/styles.cljs b/src/status_im/transactions/styles.cljs deleted file mode 100644 index cfb7ad8cf5..0000000000 --- a/src/status_im/transactions/styles.cljs +++ /dev/null @@ -1,105 +0,0 @@ -(ns status-im.transactions.styles - (:require [status-im.components.styles :refer [color-gray - color-black]])) - -(def transactions-screen - {:flex 1 - :backgroundColor "#828b92"}) - -(def transactions-toolbar - {:backgroundColor "#828b92" - :elevation 0}) - -(def toolbar-title-text - {:color :white - :fontSize 16}) - -(def carousel-page-style - {}) - -(def form-container - {:flex 1 - :paddingLeft 16}) - -(def password-style - {:color :white - :font-size 12}) - -;transaction-page - -(def transaction-page - {:flex 1 - :backgroundColor "#f3f4f4"}) - -(def title-bar - {:backgroundColor :white - :height 39 - :justifyContent :center}) - -(def title-bar-text - {:color "#838c93" - :font-size 13 - :margin-left 12 - :margin-right 30}) - -(def icon-close-container - {:position :absolute - :right 12 - :top 13}) - -(def icon-close - {:width 12 - :height 12}) - -(def transaction-info-container - {:flex 1 - :paddingTop 6}) - -(def scroll-view-container - {:flex 1}) - -(def scroll-view - {:flex 1 - :height 175}) - -(def scroll-view-content - {:paddingVertical 6}) - -(def transaction-info-row - {:flex 1 - :flexDirection :row}) - -(def transaction-info-column-title - {:flex 0.4 - :flexDirection :column - :paddingHorizontal 6}) - -(def transaction-info-column-value - {:flex 0.6 - :flexDirection :column - :paddingHorizontal 6}) - -(def transaction-info-item - {:flex 1 - :padding 6}) - -(def transaction-info-title - {:textAlign :right - :color color-gray - :fontSize 14 - :lineHeight 20}) - -(def transaction-info-value - {:color color-black - :fontSize 14 - :lineHeight 20 -}) - -(def scroll-view-item - {:flex 1 - :height 20 - :padding 6 }) - -(def carousel-container - {:min-height 215 - :flex 1}) diff --git a/src/status_im/transactions/styles/list_item.cljs b/src/status_im/transactions/styles/list_item.cljs new file mode 100644 index 0000000000..c29d298dcd --- /dev/null +++ b/src/status_im/transactions/styles/list_item.cljs @@ -0,0 +1,52 @@ +(ns status-im.transactions.styles.list-item + (:require-macros [status-im.utils.styles :refer [defstyle]]) + (:require [status-im.components.styles :as st])) + +(def item + {:padding-vertical 20 + :padding-horizontal 16 + :flex 1 + :flex-direction :row + :align-items :center}) + +(def item-photo + {:width 86 + :height 48 + :border-radius 100 + :background-color st/color-dark-blue-3 + :flex-direction :row + :align-items :center}) + +(def item-info + {:margin-left 16 + :flex 1}) + +(defstyle item-info-recipient + {:color st/color-light-blue + :font-size 15 + :flex-shrink 1 + :android {:margin-bottom 5} + :ios {:margin-bottom 4}}) + +(defstyle item-info-amount + {:color st/color-white + :android {:font-size 19} + :ios {:font-size 20}}) + +(def item-deny-btn + {:margin-left 16}) + +(def item-deny-btn-icon + {:width 24 + :height 24}) + +(def photo-size 48) + +(def photo-placeholder + {:width 48 + :height 48}) + +(def item-photo-icon + {:margin-left 4 + :width 24 + :height 24}) diff --git a/src/status_im/transactions/styles/password_form.cljs b/src/status_im/transactions/styles/password_form.cljs new file mode 100644 index 0000000000..003f151ab1 --- /dev/null +++ b/src/status_im/transactions/styles/password_form.cljs @@ -0,0 +1,30 @@ +(ns status-im.transactions.styles.password-form + (:require-macros [status-im.utils.styles :refer [defnstyle defstyle]]) + (:require [status-im.components.styles :as st])) + +(defnstyle password-container [error?] + {:margin-bottom (if error? 42 24) + :padding-left 16 + :ios {:border-top-width 1 + :border-top-color st/color-white-transparent-2}}) + +(def password-title + {:color st/color-white + :font-size 15 + :margin-top 16 + :margin-bottom 12}) + +(def password-input-wrapper + {:position :relative + :height 52 + :padding-top 0 + :padding-bottom 0 + :margin-bottom 0}) + +(defstyle password-input + {:color :white + :height 52 + :padding-left 0 + :padding-top 24 + :android {:font-size 16} + :ios {:font-size 17}}) diff --git a/src/status_im/transactions/styles/screens.cljs b/src/status_im/transactions/styles/screens.cljs new file mode 100644 index 0000000000..dd3d9437ad --- /dev/null +++ b/src/status_im/transactions/styles/screens.cljs @@ -0,0 +1,129 @@ +(ns status-im.transactions.styles.screens + (:require-macros [status-im.utils.styles :refer [defstyle]]) + (:require [status-im.components.styles :as st] + [status-im.utils.platform :as platform])) + +;; common + +(def transactions-toolbar-background (if platform/ios? + st/color-dark-blue-2 + st/color-dark-blue-1)) + +(defstyle toolbar-title-container + {:flex 1 + :flex-direction :row + :align-self :stretch + :padding-left 30 + :ios {:align-items :center + :justify-content :center + :padding-bottom 16}}) + +(def toolbar-title-text + {:color st/color-white + :font-size 17}) + +(defstyle toolbar-title-count + {:color st/color-white + :font-size 17 + :margin-left 8 + :android {:opacity 0.2} + :ios {:opacity 0.6}}) + +(defstyle toolbar-border + {:ios {:background-color st/color-white + :opacity 0.1}}) + +;; pending-transactions + +(def transactions-screen + {:flex 1 + :background-color st/color-dark-blue-2}) + +(def transactions-screen-content-container + {:flex 1 + :justify-content :space-between}) + +(defstyle transactions-list + {:flex 1 + :android {:padding-vertical 8}}) + +(def transactions-list-separator + {:margin-left 16 + :opacity 0.1}) + +;; transaction-details + +(defstyle details-screen-content-container + {:flex 1 + :android {:padding-top 8}}) + +(def details-separator + {:margin-bottom 10 + :margin-left 16 + :opacity 0.1}) + +(def details-item + {:margin-top 10 + :padding-left 16 + :padding-right 16 + :flex-direction :row}) + +(defstyle details-item-title + {:width 80 + :font-size 15 + :color st/color-white + :android {:opacity 0.2 + :margin-right 24} + :ios {:opacity 0.5 + :margin-right 8 + :text-align :right}}) + +(defn details-item-content [name?] + {:font-size 15 + :flex-shrink 1 + :color (if name? st/color-light-blue st/color-white)}) + +(defstyle details-data + {:margin-top 16 + :padding 16 + :background-color st/color-dark-blue-3 + :ios {:margin-horizontal 16}}) + +(defstyle details-data-title + {:font-size 15 + :color st/color-white + :android {:opacity 0.2} + :ios {:opacity 0.5}}) + +(def details-data-content + {:font-size 15 + :color st/color-white + :margin-top 8}) + +;; confirmation-success + +(def success-screen + {:flex 1 + :background-color st/color-dark-blue-2}) + +(def success-screen-content-container + {:flex 1 + :align-items :center + :justify-content :center}) + +(def success-icon-container + {:background-color st/color-light-blue + :border-radius 100 + :height 133 + :width 133 + :justify-content :center + :align-items :center}) + +(def success-icon + {:height 40 + :width 54}) + +(def success-text + {:font-size 17 + :color st/color-light-blue3 + :margin-top 26}) diff --git a/src/status_im/transactions/views/list_item.cljs b/src/status_im/transactions/views/list_item.cljs new file mode 100644 index 0000000000..b20f70a32e --- /dev/null +++ b/src/status_im/transactions/views/list_item.cljs @@ -0,0 +1,39 @@ +(ns status-im.transactions.views.list-item + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :as rf] + [status-im.components.chat-icon.screen :as chat-icon] + [status-im.components.react :as rn] + [status-im.i18n :as i18n] + [status-im.transactions.styles.list-item :as st])) + +(defview item-image [contact] + [rn/view {:style st/item-photo} + (if-not (empty? contact) + [chat-icon/chat-icon (:photo-path contact) {:size st/photo-size}] + [rn/view {:style st/photo-placeholder}]) + [rn/image {:source {:uri :icon_arrow_left_white} + :style st/item-photo-icon}]]) + +(defn item-info [recipient-name value] + [rn/view {:style st/item-info} + [rn/text {:style st/item-info-recipient + :number-of-lines 1} + recipient-name] + [rn/text {:style st/item-info-amount} value]]) + +(defn deny-btn [transaction-id on-deny] + [rn/touchable-highlight {:on-press #(do (rf/dispatch [:deny-transaction transaction-id]) + (when on-deny (on-deny)))} + [rn/view {:style st/item-deny-btn} + [rn/image {:source {:uri :icon_close_white} + :style st/item-deny-btn-icon}]]]) + +(defview view [{:keys [to value id] :as transaction} on-deny] + [recipient [:contact-by-address to]] + (let [eth-value (.fromWei js/Web3.prototype value "ether") + value (str (i18n/label-number eth-value) " ETH") + recipient-name (or (:name recipient) to)] + [rn/view {:style st/item} + [item-image recipient] + [item-info recipient-name value] + [deny-btn id on-deny]])) diff --git a/src/status_im/transactions/views/password_form.cljs b/src/status_im/transactions/views/password_form.cljs new file mode 100644 index 0000000000..3d6387e424 --- /dev/null +++ b/src/status_im/transactions/views/password_form.cljs @@ -0,0 +1,29 @@ +(ns status-im.transactions.views.password-form + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :as rf] + [status-im.components.react :as rn] + [status-im.components.styles :as common-st] + [status-im.components.text-field.view :as text-field] + [status-im.transactions.styles.password-form :as st] + [status-im.i18n :as i18n])) + +(defview view [transaction-quantity] + [wrong-password? [:wrong-password?]] + (let [error? wrong-password?] + [rn/view (st/password-container error?) + [rn/text {:style st/password-title} + (i18n/label-pluralize transaction-quantity :t/enter-password-transactions)] + [text-field/text-field + {:editable true + :secure-text-entry true + :label-hidden? true + :error (when error? (i18n/label :t/wrong-password)) + :error-color common-st/color-light-red2 + :placeholder (i18n/label :t/password) + :placeholder-text-color common-st/color-white-transparent + :line-color common-st/color-light-blue + :focus-line-height 2 + :wrapper-style st/password-input-wrapper + :input-style st/password-input + :auto-focus true + :on-change-text #(rf/dispatch [:set-in [:confirm-transactions :password] %])}]])) diff --git a/src/status_im/transactions/views/transaction_page.cljs b/src/status_im/transactions/views/transaction_page.cljs deleted file mode 100644 index b72158f6f3..0000000000 --- a/src/status_im/transactions/views/transaction_page.cljs +++ /dev/null @@ -1,50 +0,0 @@ -(ns status-im.transactions.views.transaction-page - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.components.react :refer [view - text - image - icon - scroll-view - touchable-highlight - touchable-opacity]] - [status-im.components.styles :refer [icon-close]] - [status-im.transactions.styles :as st] - [status-im.i18n :refer [label label-pluralize label-number]])) - -(defn title-bar [title id] - [view st/title-bar - [text {:style st/title-bar-text - :font :medium - :number-of-lines 1} - title] - [touchable-highlight {:style st/icon-close-container - :on-press #(dispatch [:deny-transaction id])} - [view [image {:source {:uri :icon_close_gray} - :style st/icon-close}]]]]) - -(defn transaction-info [index [name value]] - [view {:style st/transaction-info-item - :key index} - [view {:style st/transaction-info-row} - [view st/transaction-info-column-title - [text {:style st/transaction-info-title} name]] - [view st/transaction-info-column-value - [text {:style st/transaction-info-value} value]]]]) - -(defview transaction-page [{:keys [id from to value] :as transaction}] - [{:keys [name] :as contact} [:contact-by-address to]] - (let [eth-value (.fromWei js/Web3.prototype value "ether") - title (str (label-number eth-value) " ETH to " (or name to)) - transactions-info [[(label :t/status) (label :t/pending-confirmation)] - [(label :t/recipient) (or name to)] - [(label :t/value) (str (label-number eth-value) " ETH")]]] - [view {:style st/transaction-page - :key id} - [title-bar title id] - [view st/scroll-view-container - [scroll-view {:style st/scroll-view - :contentContainerStyle st/scroll-view-content - :showsVerticalScrollIndicator true - :scrollEnabled true} - (map-indexed transaction-info transactions-info)]]])) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index b5258992dd..13cb5507a4 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -269,15 +269,27 @@ :not-enough-eth (str "Not enough ETH on balance " "({{balance}} ETH)") ;transactions + :confirm "Confirm" :confirm-transactions {:one "Confirm transaction" :other "Confirm {{count}} transactions" :zero "No transactions"} + :transactions-confirmed {:one "Transaction confirmed" + :other "{{count}} transactions confirmed" + :zero "No transactions confirmed"} + :transaction "Transaction" + :pending-transactions "Pending transactions" + :enter-password-transactions {:one "Enter your password to confirm the transaction" + :other "Enter your password to confirm the transactions"} :status "Status" :pending-confirmation "Pending confirmation" :recipient "Recipient" :one-more-item "One more item" :fee "Fee" :value "Value" + :to "To" + :from "From" + :data "Data" + :got-it "Got it" ;:webview :web-view-error "oops, error"}) From 9987e1bd555d6c40e47209b91d3af642f9f61d31 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Wed, 5 Apr 2017 18:35:19 +0300 Subject: [PATCH 29/48] colors (+1 squashed commit) Squashed commits: [11d7921] android styles and functionality (+2 squashed commits) Squashed commits: [c93f5ab] implemented error [d6fe519] implemented text-input-with-label --- src/status_im/components/styles.cljs | 2 + .../text_input_with_label/animation.cljs | 32 ++++++++ .../text_input_with_label/styles.cljs | 70 +++++++++++++++++ .../text_input_with_label/view.cljs | 75 +++++++++++++++++++ .../contacts/views/contact_list.cljs | 1 - .../contacts/views/contact_list_modal.cljs | 1 - src/status_im/new_group/screen_private.cljs | 4 +- src/status_im/new_group/styles.cljs | 7 +- src/status_im/new_group/views/group.cljs | 29 +++---- src/status_im/profile/edit/screen.cljs | 13 +--- src/status_im/profile/styles.cljs | 15 ++-- 11 files changed, 205 insertions(+), 44 deletions(-) create mode 100644 src/status_im/components/text_input_with_label/animation.cljs create mode 100644 src/status_im/components/text_input_with_label/styles.cljs create mode 100644 src/status_im/components/text_input_with_label/view.cljs diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 15e7ac1697..e3216be35a 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -23,7 +23,9 @@ (def color-dark-blue-2 "#1f253f") (def color-dark-blue-3 "#191f37") (def color-light-gray "#EEF2F5") +(def color-light-gray2 "#ececf0") (def color-red "red") +(def color-red2 "#d84b4b") (def color-light-red "#e86363") (def color-light-red2 "#f47979") diff --git a/src/status_im/components/text_input_with_label/animation.cljs b/src/status_im/components/text_input_with_label/animation.cljs new file mode 100644 index 0000000000..d8eb17ba98 --- /dev/null +++ b/src/status_im/components/text_input_with_label/animation.cljs @@ -0,0 +1,32 @@ +(ns status-im.components.text-input-with-label.animation + (:require [status-im.components.animation :as animation] + [clojure.string :as str])) + +(def anim-duration 200) + +(defn animate-underline [underline-width to-line-width underline-height to-line-height] + (let [anim (animation/parallel [(animation/timing underline-width {:toValue to-line-width + :duration anim-duration}) + (animation/timing underline-height {:toValue to-line-height + :duration anim-duration})])] + (animation/start anim))) + +(defn text-input-on-focus [{:keys [underline-width underline-max-width* underline-height underline-max-height]}] + (animate-underline underline-width @underline-max-width* underline-height underline-max-height)) + +(defn text-input-on-blur [{:keys [underline-width underline-height]}] + (animate-underline underline-width 0 underline-height 1)) + +(defn animate-label [text {:keys [value* label-top label-font-size + label-top-top label-top-bottom label-font-size-top label-font-size-bottom]}] + (when (or (str/blank? text) (str/blank? @value*)) + (let [was-blank? (str/blank? @value*) + anim (animation/parallel [(animation/timing label-top {:toValue (if was-blank? + label-top-top + label-top-bottom) + :duration anim-duration}) + (animation/timing label-font-size {:toValue (if was-blank? + label-font-size-top + label-font-size-bottom) + :duration anim-duration})])] + (animation/start anim)))) \ No newline at end of file diff --git a/src/status_im/components/text_input_with_label/styles.cljs b/src/status_im/components/text_input_with_label/styles.cljs new file mode 100644 index 0000000000..cffa1805d0 --- /dev/null +++ b/src/status_im/components/text_input_with_label/styles.cljs @@ -0,0 +1,70 @@ +(ns status-im.components.text-input-with-label.styles + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) + (:require [status-im.utils.platform :refer [ios?]] + [status-im.components.styles :as common])) + +(defstyle text-input + {:placeholder "" + :android {:height 24 + :padding-top 0 + :padding-bottom 0 + :padding-left 0 + :margin-top 26 + :margin-bottom 4 + :font-size 16} + :ios {:height 26 + :margin-top 24 + :margin-bottom 6 + :font-size 17 + :letter-spacing -0.2}}) + +(defstyle component-container + {:padding-left 16 + :android {:min-height 76} + :ios {:min-height 78}}) + +(defnstyle label-animated-text [{:keys [label-top label-font-size]}] + {:position :absolute + :top label-top + :font-size label-font-size + :color common/color-gray4 + :ios {:letter-spacing -0.2}}) + +(defstyle description-text + {:color common/color-gray4 + :android {:margin-top 6 + :height 14 + :font-size 12} + :ios {:margin-top 4 + :height 16 + :font-size 14 + :letter-spacing -0.2}}) + +(defstyle error-text + {:color common/color-red2 + :android {:margin-top 6 + :height 14 + :font-size 12} + :ios {:margin-top 4 + :height 16 + :font-size 14 + :letter-spacing -0.2}}) + +(defn underline-blured [error] + {:background-color (if error common/color-red2 common/color-light-gray2) + :align-items :center}) + +(defn underline-focused [underline-width underline-height error] + {:height underline-height + :width underline-width + :background-color (if error common/color-red2 common/color-light-blue)}) + +(def label-top-top (if ios? 6 6)) + +(def label-top-bottom (if ios? 26 26)) + +(def label-font-size-top (if ios? 14 12)) + +(def label-font-size-bottom (if ios? 17 16)) + +(def underline-max-height (if ios? 1 2)) diff --git a/src/status_im/components/text_input_with_label/view.cljs b/src/status_im/components/text_input_with_label/view.cljs new file mode 100644 index 0000000000..21c567aab1 --- /dev/null +++ b/src/status_im/components/text_input_with_label/view.cljs @@ -0,0 +1,75 @@ +(ns status-im.components.text-input-with-label.view + (:require [reagent.core :as r] + [status-im.components.animation :as animation] + [status-im.components.text-input-with-label.animation :refer [animate-label + text-input-on-focus + text-input-on-blur]] + [status-im.components.react :refer [view + text + animated-text + animated-view + text-input]] + [status-im.components.text-input-with-label.styles :as st] + [clojure.string :as str])) + +(defn get-init-props [{:keys [default-value]}] + (let [blank? (str/blank? default-value)] + {:underline-width (animation/create-value 0) + :underline-height (animation/create-value 1) + :label-top (animation/create-value (if blank? + st/label-top-bottom + st/label-top-top)) + :label-font-size (animation/create-value (if blank? + st/label-font-size-bottom + st/label-font-size-top)) + :label-top-top st/label-top-top + :label-top-bottom st/label-top-bottom + :label-font-size-top st/label-font-size-top + :label-font-size-bottom st/label-font-size-bottom + :underline-max-height st/underline-max-height + :input-ref* (r/atom nil) + :value* (r/atom default-value) + :underline-max-width* (r/atom 0)})) + +(defn get-width [event] + (.-width (.-layout (.-nativeEvent event)))) + +(defn text-input-on-change-text [text props] + (animate-label text props) + (reset! (:value* props) text)) + +(defn text-input-handlers [{:keys [on-focus on-blur on-change-text on-submit-editing ref]} props] + {:ref #(do + (reset! (:input-ref* props) %) + (when ref (ref %))) + :on-submit-editing #(do + (.blur @(:input-ref* props)) + (when on-submit-editing (on-submit-editing))) + :on-focus #(do + (text-input-on-focus props) + (when on-focus (on-focus))) + :on-blur #(do + (text-input-on-blur props) + (when on-blur (on-blur))) + :on-change-text #(do + (text-input-on-change-text % props) + (when on-change-text (on-change-text %)))}) + +(defn text-input-with-label [options] + (let [props (get-init-props options)] + (fn [{:keys [label description error] :as options}] + [view st/component-container + [animated-text {:style (st/label-animated-text props)} label] + [text-input (merge st/text-input + (dissoc options :label :description :error) + (text-input-handlers options props))] + [view {:style (st/underline-blured error) + :on-layout #(reset! (:underline-max-width* props) (get-width %))} + [animated-view {:style (st/underline-focused + (:underline-width props) + (:underline-height props) + error)}]] + (cond error + [text {:style st/error-text} error] + description + [text {:style st/description-text} description])]))) diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index af0e02e44c..de834d0d93 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -11,7 +11,6 @@ touchable-highlight list-view list-item]] - [status-im.components.text-field.view :refer [text-field]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search toolbar]] [status-im.components.toolbar-new.actions :as act] diff --git a/src/status_im/contacts/views/contact_list_modal.cljs b/src/status_im/contacts/views/contact_list_modal.cljs index c1ceec9a8b..7915af9cb0 100644 --- a/src/status_im/contacts/views/contact_list_modal.cljs +++ b/src/status_im/contacts/views/contact_list_modal.cljs @@ -13,7 +13,6 @@ [status-im.components.action-button.action-button :refer [action-button action-separator]] [status-im.components.action-button.styles :refer [actions-list]] - [status-im.components.text-field.view :refer [text-field]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar-with-search toolbar]] [status-im.components.toolbar-new.actions :as act] diff --git a/src/status_im/new_group/screen_private.cljs b/src/status_im/new_group/screen_private.cljs index 0140c117dd..db7fb04898 100644 --- a/src/status_im/new_group/screen_private.cljs +++ b/src/status_im/new_group/screen_private.cljs @@ -59,7 +59,7 @@ st/group-container) [group-toolbar type true] [group-name-view] - [view {:flex 1} + [view st/list-view-container [add-btn #(dispatch [:navigate-to :add-contacts-toggle-list])] [group-contacts-view group] [view st/separator] @@ -83,7 +83,7 @@ st/group-container) [group-toolbar group-type false] [group-name-view] - [view {:flex 1} + [view st/list-view-container [list-view {:dataSource (to-datasource contacts) :enableEmptySections true :renderRow render-row diff --git a/src/status_im/new_group/styles.cljs b/src/status_im/new_group/styles.cljs index f3ef2edc43..6f5a391313 100644 --- a/src/status_im/new_group/styles.cljs +++ b/src/status_im/new_group/styles.cljs @@ -33,8 +33,7 @@ :android {:padding-top 16}}) (def chat-name-container - {:margin-top 21 - :margin-left 16}) + {:margin-top 10}) (def add-button-container {:margin-left 16}) @@ -221,6 +220,10 @@ :height 1 :opacity 0.5}) +(def list-view-container + {:flex 1 + :margin-top 10}) + diff --git a/src/status_im/new_group/views/group.cljs b/src/status_im/new_group/views/group.cljs index fb9b25c081..af644b3047 100644 --- a/src/status_im/new_group/views/group.cljs +++ b/src/status_im/new_group/views/group.cljs @@ -10,7 +10,7 @@ text icon touchable-highlight]] - [status-im.components.text-field.view :refer [text-field]] + [status-im.components.text-input-with-label.view :refer [text-input-with-label]] [status-im.components.styles :refer [color-blue color-gray5 color-light-blue]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar]] @@ -18,20 +18,6 @@ [status-im.new-group.styles :as st] [status-im.i18n :refer [label]])) -(defview group-name-input [] - [new-group-name [:get :new-chat-name]] - [view - [text-field - {:wrapper-style st/group-chat-name-wrapper - :line-color color-gray5 - :focus-line-color color-light-blue - :focus-line-height st/group-chat-focus-line-height - :label-hidden? true - :input-style st/group-chat-name-input - :auto-focus true - :on-change-text #(dispatch [:set :new-chat-name %]) - :value new-group-name}]]) - (defn group-toolbar [group-type edit?] [view [status-bar] @@ -42,15 +28,18 @@ (if edit? :t/chat-settings :t/new-group-chat))) :actions [{:image :blank}]}]]) -(defn group-name-view [] +(defview group-name-view [] + [new-group-name [:get :new-chat-name]] [view st/chat-name-container - [text {:style st/group-name-text} - (label :t/name)] - [group-name-input]]) + [text-input-with-label + {:auto-focus true + :label (label :t/name) + :on-change-text #(dispatch [:set :new-chat-name %]) + :default-value new-group-name}]]) (defn add-btn [on-press] [action-button (label :t/add-members) - :add_blue + :add_blue on-press]) (defn delete-btn [on-press] diff --git a/src/status_im/profile/edit/screen.cljs b/src/status_im/profile/edit/screen.cljs index 7af773ffd4..c6b3d17533 100644 --- a/src/status_im/profile/edit/screen.cljs +++ b/src/status_im/profile/edit/screen.cljs @@ -1,12 +1,12 @@ (ns status-im.profile.edit.screen (:require-macros [status-im.utils.views :refer [defview]]) (:require [status-im.profile.styles :as st] + [status-im.components.text-input-with-label.view :refer [text-input-with-label]] [status-im.components.styles :refer [color-blue color-gray5]] [re-frame.core :refer [dispatch]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar-new.view :refer [toolbar]] [status-im.components.toolbar-new.actions :as act] - [status-im.components.text-field.view :refer [text-field]] [status-im.i18n :refer [label]] [status-im.profile.screen :refer [colorize-status-hashtags]] [status-im.components.sticky-button :refer [sticky-button]] @@ -32,14 +32,9 @@ (defview profile-name-input [] [new-profile-name [:get-in [:profile-edit :name]]] [view - [text-field - {:line-color st/edit-line-color - :focus-line-color st/profile-focus-line-color - :focus-line-height st/profile-focus-line-height - :label (label :t/name) - :input-style st/profile-name-input - :on-change-text #(dispatch [:set-in [:profile-edit :name] %]) - :value new-profile-name}]]) + [text-input-with-label {:label (label :t/name) + :default-value new-profile-name + :on-change-text #(dispatch [:set-in [:profile-edit :name] %])}]]) (def profile-icon-options [{:text (label :t/image-source-gallery) :value #(dispatch [:open-image-picker])} diff --git a/src/status_im/profile/styles.cljs b/src/status_im/profile/styles.cljs index 0e3d5bb48d..53a1a850c2 100644 --- a/src/status_im/profile/styles.cljs +++ b/src/status_im/profile/styles.cljs @@ -51,18 +51,14 @@ (def edit-profile-bage {:flex-direction :row - :align-items :center :padding-left 24}) (def context-menu-custom-styles {:optionsContainer {:margin-top 78}}) -(defstyle edit-profile-name-container +(def edit-profile-name-container {:flex 1 - :ios {:padding-left 32 - :padding-top 15} - :android {:padding-top 16 - :padding-left 16}}) + :padding-top 30}) (def edit-profile-icon-container {:padding-top 25}) @@ -185,9 +181,10 @@ :padding-bottom 16 :margin-left 16 :margin-right 16 - :margin-top 24 - :ios {:padding-top 10} - :android {:padding-top 13}}) + :ios {:padding-top 10 + :margin-top 10} + :android {:padding-top 13 + :margin-top 13}}) (def add-a-status (merge profile-status-text From 2e67f5275b02307a3835f8ba1ce86271fefc9807 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Fri, 7 Apr 2017 18:29:32 +0300 Subject: [PATCH 30/48] fixes https://github.com/status-im/status-react/issues/981 --- src/status_im/components/common/common.cljs | 2 +- .../text_input_with_label/styles.cljs | 2 - .../screens/pending-transactions.cljs | 2 - .../screens/transaction-details.cljs | 6 +-- .../transactions/styles/list_item.cljs | 2 +- .../transactions/styles/password_form.cljs | 35 +++------------ .../transactions/styles/screens.cljs | 45 +++++++++++-------- .../transactions/views/list_item.cljs | 4 +- .../transactions/views/password_form.cljs | 30 +++++-------- src/status_im/translations/en.cljs | 4 +- 10 files changed, 52 insertions(+), 80 deletions(-) diff --git a/src/status_im/components/common/common.cljs b/src/status_im/components/common/common.cljs index 26c914e44b..bb39e16352 100644 --- a/src/status_im/components/common/common.cljs +++ b/src/status_im/components/common/common.cljs @@ -16,7 +16,7 @@ {:style st/gradient-top :colors st/gradient-top-colors}])) -(defn separator [style wrapper-style] +(defn separator [style & [wrapper-style]] [view (merge st/separator-wrapper wrapper-style) [view (merge st/separator style)]]) diff --git a/src/status_im/components/text_input_with_label/styles.cljs b/src/status_im/components/text_input_with_label/styles.cljs index cffa1805d0..874002017a 100644 --- a/src/status_im/components/text_input_with_label/styles.cljs +++ b/src/status_im/components/text_input_with_label/styles.cljs @@ -33,10 +33,8 @@ (defstyle description-text {:color common/color-gray4 :android {:margin-top 6 - :height 14 :font-size 12} :ios {:margin-top 4 - :height 16 :font-size 14 :letter-spacing -0.2}}) diff --git a/src/status_im/transactions/screens/pending-transactions.cljs b/src/status_im/transactions/screens/pending-transactions.cljs index 5380533b01..8eb52088c5 100644 --- a/src/status_im/transactions/screens/pending-transactions.cljs +++ b/src/status_im/transactions/screens/pending-transactions.cljs @@ -45,10 +45,8 @@ [transactions [:transactions] {:keys [password]} [:get :confirm-transactions] confirmed? [:get-in [:transactions-list-ui-props :confirmed?]]] - {:component-did-update #(when-not (seq transactions) (rf/dispatch [:navigate-back])) :component-will-unmount #(rf/dispatch [:set-in [:transactions-list-ui-props :confirmed?] false])} - [(if platform/ios? rn/keyboard-avoiding-view rn/view) (merge {:behavior :padding} st/transactions-screen) [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] [toolbar-view transactions] diff --git a/src/status_im/transactions/screens/transaction-details.cljs b/src/status_im/transactions/screens/transaction-details.cljs index a8d7ad2a15..ed019f4c92 100644 --- a/src/status_im/transactions/screens/transaction-details.cljs +++ b/src/status_im/transactions/screens/transaction-details.cljs @@ -39,7 +39,7 @@ [current-account [:get-current-account] recipient [:contact-by-address to]] (let [recipient-name (or (:name recipient) to)] - [rn/view + [rn/view st/details-container [detail-item (i18n/label :t/to) recipient-name true] [detail-item (i18n/label :t/from) (:name current-account) true] [detail-data data]])) @@ -48,16 +48,14 @@ [{:keys [id] :as transaction} [:get :selected-transaction] {:keys [password]} [:get :confirm-transactions] confirmed? [:get-in [:transaction-details-ui-props :confirmed?]]] - {:component-did-update #(when-not transaction (rf/dispatch [:navigate-to-modal :pending-transactions])) :component-will-unmount #(rf/dispatch [:set-in [:transaction-details-ui-props :confirmed?] false])} - [(if platform/ios? rn/keyboard-avoiding-view rn/view) (merge {:behavior :padding} st/transactions-screen) [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] [toolbar-view] [rn/scroll-view st/details-screen-content-container [transactions-list-item/view transaction #(rf/dispatch [:navigate-to-modal :pending-transactions])] - (when platform/ios? [common/separator {} st/details-separator]) + [common/separator st/details-separator st/details-separator-wrapper] [details transaction]] (when confirmed? [password-form/view 1]) (let [confirm-text (if confirmed? diff --git a/src/status_im/transactions/styles/list_item.cljs b/src/status_im/transactions/styles/list_item.cljs index c29d298dcd..62de0d6e10 100644 --- a/src/status_im/transactions/styles/list_item.cljs +++ b/src/status_im/transactions/styles/list_item.cljs @@ -3,7 +3,7 @@ (:require [status-im.components.styles :as st])) (def item - {:padding-vertical 20 + {:padding-vertical 19 :padding-horizontal 16 :flex 1 :flex-direction :row diff --git a/src/status_im/transactions/styles/password_form.cljs b/src/status_im/transactions/styles/password_form.cljs index 003f151ab1..a23c78715e 100644 --- a/src/status_im/transactions/styles/password_form.cljs +++ b/src/status_im/transactions/styles/password_form.cljs @@ -1,30 +1,9 @@ (ns status-im.transactions.styles.password-form - (:require-macros [status-im.utils.styles :refer [defnstyle defstyle]]) - (:require [status-im.components.styles :as st])) + (:require-macros [status-im.utils.styles :refer [defstyle]]) + (:require [status-im.components.styles :as common])) -(defnstyle password-container [error?] - {:margin-bottom (if error? 42 24) - :padding-left 16 - :ios {:border-top-width 1 - :border-top-color st/color-white-transparent-2}}) - -(def password-title - {:color st/color-white - :font-size 15 - :margin-top 16 - :margin-bottom 12}) - -(def password-input-wrapper - {:position :relative - :height 52 - :padding-top 0 - :padding-bottom 0 - :margin-bottom 0}) - -(defstyle password-input - {:color :white - :height 52 - :padding-left 0 - :padding-top 24 - :android {:font-size 16} - :ios {:font-size 17}}) +(defstyle password-container + {:android {:margin-bottom 27} + :ios {:margin-bottom 20 + :border-top-width 1 + :border-top-color common/color-white-transparent-2}}) diff --git a/src/status_im/transactions/styles/screens.cljs b/src/status_im/transactions/styles/screens.cljs index dd3d9437ad..88c2d75dd4 100644 --- a/src/status_im/transactions/styles/screens.cljs +++ b/src/status_im/transactions/styles/screens.cljs @@ -1,13 +1,13 @@ (ns status-im.transactions.styles.screens (:require-macros [status-im.utils.styles :refer [defstyle]]) - (:require [status-im.components.styles :as st] + (:require [status-im.components.styles :as common] [status-im.utils.platform :as platform])) ;; common (def transactions-toolbar-background (if platform/ios? - st/color-dark-blue-2 - st/color-dark-blue-1)) + common/color-dark-blue-2 + common/color-dark-blue-1)) (defstyle toolbar-title-container {:flex 1 @@ -19,25 +19,25 @@ :padding-bottom 16}}) (def toolbar-title-text - {:color st/color-white + {:color common/color-white :font-size 17}) (defstyle toolbar-title-count - {:color st/color-white + {:color common/color-white :font-size 17 :margin-left 8 :android {:opacity 0.2} :ios {:opacity 0.6}}) (defstyle toolbar-border - {:ios {:background-color st/color-white + {:ios {:background-color common/color-white :opacity 0.1}}) ;; pending-transactions (def transactions-screen {:flex 1 - :background-color st/color-dark-blue-2}) + :background-color common/color-dark-blue-2}) (def transactions-screen-content-container {:flex 1 @@ -57,11 +57,18 @@ {:flex 1 :android {:padding-top 8}}) +(def details-separator-wrapper + {:background-color common/color-dark-blue-2}) + (def details-separator - {:margin-bottom 10 - :margin-left 16 + {:margin-left 16 + :background-color common/color-white :opacity 0.1}) +(defstyle details-container + {:ios {:margin-top 10} + :android {:margin-top 0}}) + (def details-item {:margin-top 10 :padding-left 16 @@ -71,7 +78,7 @@ (defstyle details-item-title {:width 80 :font-size 15 - :color st/color-white + :color common/color-white :android {:opacity 0.2 :margin-right 24} :ios {:opacity 0.5 @@ -81,30 +88,30 @@ (defn details-item-content [name?] {:font-size 15 :flex-shrink 1 - :color (if name? st/color-light-blue st/color-white)}) + :color (if name? common/color-light-blue common/color-white)}) (defstyle details-data - {:margin-top 16 - :padding 16 - :background-color st/color-dark-blue-3 + {:padding 16 + :margin-top 16 + :background-color common/color-dark-blue-3 :ios {:margin-horizontal 16}}) (defstyle details-data-title {:font-size 15 - :color st/color-white + :color common/color-white :android {:opacity 0.2} :ios {:opacity 0.5}}) (def details-data-content {:font-size 15 - :color st/color-white + :color common/color-white :margin-top 8}) ;; confirmation-success (def success-screen {:flex 1 - :background-color st/color-dark-blue-2}) + :background-color common/color-dark-blue-2}) (def success-screen-content-container {:flex 1 @@ -112,7 +119,7 @@ :justify-content :center}) (def success-icon-container - {:background-color st/color-light-blue + {:background-color common/color-light-blue :border-radius 100 :height 133 :width 133 @@ -125,5 +132,5 @@ (def success-text {:font-size 17 - :color st/color-light-blue3 + :color common/color-light-blue3 :margin-top 26}) diff --git a/src/status_im/transactions/views/list_item.cljs b/src/status_im/transactions/views/list_item.cljs index b20f70a32e..da8a0784a7 100644 --- a/src/status_im/transactions/views/list_item.cljs +++ b/src/status_im/transactions/views/list_item.cljs @@ -25,8 +25,8 @@ [rn/touchable-highlight {:on-press #(do (rf/dispatch [:deny-transaction transaction-id]) (when on-deny (on-deny)))} [rn/view {:style st/item-deny-btn} - [rn/image {:source {:uri :icon_close_white} - :style st/item-deny-btn-icon}]]]) + [rn/image {:source {:uri :icon_close_white} + :style st/item-deny-btn-icon}]]]) (defview view [{:keys [to value id] :as transaction} on-deny] [recipient [:contact-by-address to]] diff --git a/src/status_im/transactions/views/password_form.cljs b/src/status_im/transactions/views/password_form.cljs index 3d6387e424..3b7573423f 100644 --- a/src/status_im/transactions/views/password_form.cljs +++ b/src/status_im/transactions/views/password_form.cljs @@ -2,28 +2,20 @@ (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :as rf] [status-im.components.react :as rn] - [status-im.components.styles :as common-st] - [status-im.components.text-field.view :as text-field] + [status-im.components.text-input-with-label.view :refer [text-input-with-label]] [status-im.transactions.styles.password-form :as st] [status-im.i18n :as i18n])) (defview view [transaction-quantity] [wrong-password? [:wrong-password?]] (let [error? wrong-password?] - [rn/view (st/password-container error?) - [rn/text {:style st/password-title} - (i18n/label-pluralize transaction-quantity :t/enter-password-transactions)] - [text-field/text-field - {:editable true - :secure-text-entry true - :label-hidden? true - :error (when error? (i18n/label :t/wrong-password)) - :error-color common-st/color-light-red2 - :placeholder (i18n/label :t/password) - :placeholder-text-color common-st/color-white-transparent - :line-color common-st/color-light-blue - :focus-line-height 2 - :wrapper-style st/password-input-wrapper - :input-style st/password-input - :auto-focus true - :on-change-text #(rf/dispatch [:set-in [:confirm-transactions :password] %])}]])) + [rn/view st/password-container + [text-input-with-label + {:label (i18n/label :t/password) + :description (i18n/label-pluralize transaction-quantity :t/enter-password-transactions) + :on-change-text #(rf/dispatch [:set-in [:confirm-transactions :password] %]) + :style {:color :white} + :auto-focus true + :secure-text-entry true + :error (when error? (i18n/label :t/wrong-password))}]])) + diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 13cb5507a4..2a363a3a74 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -278,8 +278,8 @@ :zero "No transactions confirmed"} :transaction "Transaction" :pending-transactions "Pending transactions" - :enter-password-transactions {:one "Enter your password to confirm the transaction" - :other "Enter your password to confirm the transactions"} + :enter-password-transactions {:one "Confirm transaction by entering your password" + :other "Confirm transactions by entering your password"} :status "Status" :pending-confirmation "Pending confirmation" :recipient "Recipient" From ccc3eb6397772b55b586dd663e16cb0048b8c3a8 Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Tue, 11 Apr 2017 01:30:12 -0300 Subject: [PATCH 31/48] code review for #953 --- src/status_im/components/react.cljs | 12 ++++++++++-- src/status_im/new_group/screen_private.cljs | 3 +-- .../new_group/views/chat_group_settings.cljs | 3 +-- .../new_group/views/contact_toggle_list.cljs | 11 +++-------- src/status_im/profile/edit/screen.cljs | 3 +-- src/status_im/transactions/handlers.cljs | 3 +-- .../transactions/screens/pending-transactions.cljs | 2 +- .../transactions/screens/transaction-details.cljs | 2 +- 8 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index cef7e03e7e..841e932fcf 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -3,7 +3,7 @@ [status-im.components.styles :as st] [status-im.utils.utils :as u :refer [get-react-property get-class adapt-class]] - [status-im.utils.platform :refer [platform-specific]])) + [status-im.utils.platform :refer [platform-specific ios?]])) (def react-native (js/require "react-native")) (def native-modules (.-NativeModules react-native)) @@ -30,7 +30,7 @@ (def list-view-class (get-class "ListView")) (def scroll-view (get-class "ScrollView")) (def web-view (get-class "WebView")) -(def keyboard-avoiding-view (get-class "KeyboardAvoidingView")) +(def keyboard-avoiding-view-class (get-class "KeyboardAvoidingView")) (def text-class (get-class "Text")) (def text-input-class (get-class "TextInput")) @@ -151,3 +151,11 @@ (def http-bridge (js/require "react-native-http-bridge")) + +;; KeyboardAvoidingView + +(defn keyboard-avoiding-view [props & children] + (let [view-element (if ios? + [keyboard-avoiding-view-class (merge {:behavior :padding} props)] + [view props])] + (vec (concat view-element children)))) diff --git a/src/status_im/new_group/screen_private.cljs b/src/status_im/new_group/screen_private.cljs index db7fb04898..dc60f8899b 100644 --- a/src/status_im/new_group/screen_private.cljs +++ b/src/status_im/new_group/screen_private.cljs @@ -55,8 +55,7 @@ type [:get :group-type]] (let [save-btn-enabled? (and (s/valid? ::v/name group-name) (not= group-name (:name group)))] - [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} - st/group-container) + [keyboard-avoiding-view {:style st/group-container} [group-toolbar type true] [group-name-view] [view st/list-view-container diff --git a/src/status_im/new_group/views/chat_group_settings.cljs b/src/status_im/new_group/views/chat_group_settings.cljs index 962f33ab7d..0687edecda 100644 --- a/src/status_im/new_group/views/chat_group_settings.cljs +++ b/src/status_im/new_group/views/chat_group_settings.cljs @@ -63,8 +63,7 @@ type [:get :group-type]] (let [save-btn-enabled? (and (s/valid? ::v/name new-chat-name) (not= new-chat-name chat-name))] - [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} - st/group-container) + [keyboard-avoiding-view {:style st/group-container} [view {:flex 1} [group-toolbar type true] [scroll-view diff --git a/src/status_im/new_group/views/contact_toggle_list.cljs b/src/status_im/new_group/views/contact_toggle_list.cljs index 607099cd75..9ff57dfc15 100644 --- a/src/status_im/new_group/views/contact_toggle_list.cljs +++ b/src/status_im/new_group/views/contact_toggle_list.cljs @@ -57,8 +57,7 @@ [contacts [:all-added-group-contacts-filtered] selected-contacts-count [:selected-contacts-count] group-type [:get :group-type]] - [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} - st/group-container) + [keyboard-avoiding-view {:style st/group-container} [status-bar] [toggle-list-toolbar (label (if (= group-type :contact-group) @@ -73,8 +72,7 @@ [contacts [:all-group-not-added-contacts-filtered] group [:get-contact-group] selected-contacts-count [:selected-contacts-count]] - [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} - st/group-container) + [keyboard-avoiding-view {:style st/group-container} [status-bar] [toggle-list-toolbar (:name group) selected-contacts-count] [toggle-list contacts group-toggle-contact] @@ -87,8 +85,7 @@ [contacts [:contacts-filtered :all-new-contacts] chat-name [:chat :name] selected-contacts-count [:selected-participants-count]] - [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} - st/group-container) + [keyboard-avoiding-view {:style st/group-container} [status-bar] [toggle-list-toolbar chat-name selected-contacts-count] [toggle-list contacts group-toggle-participant] @@ -96,5 +93,3 @@ [sticky-button (label :t/save) #(do (dispatch [:add-new-participants]) (dispatch [:navigate-back]))])]) - - diff --git a/src/status_im/profile/edit/screen.cljs b/src/status_im/profile/edit/screen.cljs index c6b3d17533..d628b9bbe8 100644 --- a/src/status_im/profile/edit/screen.cljs +++ b/src/status_im/profile/edit/screen.cljs @@ -90,8 +90,7 @@ profile-edit-data-changed? (or (not= (:name current-account) (:name changed-account)) (not= (:status current-account) (:status changed-account)) (not= (:photo-path current-account) (:photo-path changed-account)))] - [(if ios? keyboard-avoiding-view view) (merge {:behavior :padding} - st/profile) + [keyboard-avoiding-view {:style st/profile} [status-bar] [edit-my-profile-toolbartoolbar] [view st/edit-my-profile-form diff --git a/src/status_im/transactions/handlers.cljs b/src/status_im/transactions/handlers.cljs index bf9f20721f..064df8ca6c 100644 --- a/src/status_im/transactions/handlers.cljs +++ b/src/status_im/transactions/handlers.cljs @@ -155,8 +155,7 @@ (dispatch [::check-completed-transaction! {:message-id message-id}])) (dispatch [::remove-transaction id])) - (when (or (= modal :pending-transactions) - (= modal :transaction-details)) + (when (#{:pending-transactions :transaction-details} modal) (dispatch [:navigate-to-modal :confirmation-success]))))))) (register-handler ::add-transactions-hash diff --git a/src/status_im/transactions/screens/pending-transactions.cljs b/src/status_im/transactions/screens/pending-transactions.cljs index 8eb52088c5..1f028df30e 100644 --- a/src/status_im/transactions/screens/pending-transactions.cljs +++ b/src/status_im/transactions/screens/pending-transactions.cljs @@ -47,7 +47,7 @@ confirmed? [:get-in [:transactions-list-ui-props :confirmed?]]] {:component-did-update #(when-not (seq transactions) (rf/dispatch [:navigate-back])) :component-will-unmount #(rf/dispatch [:set-in [:transactions-list-ui-props :confirmed?] false])} - [(if platform/ios? rn/keyboard-avoiding-view rn/view) (merge {:behavior :padding} st/transactions-screen) + [rn/keyboard-avoiding-view {:style st/transactions-screen} [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] [toolbar-view transactions] [rn/view {:style st/transactions-screen-content-container} diff --git a/src/status_im/transactions/screens/transaction-details.cljs b/src/status_im/transactions/screens/transaction-details.cljs index ed019f4c92..fd3a6a212d 100644 --- a/src/status_im/transactions/screens/transaction-details.cljs +++ b/src/status_im/transactions/screens/transaction-details.cljs @@ -50,7 +50,7 @@ confirmed? [:get-in [:transaction-details-ui-props :confirmed?]]] {:component-did-update #(when-not transaction (rf/dispatch [:navigate-to-modal :pending-transactions])) :component-will-unmount #(rf/dispatch [:set-in [:transaction-details-ui-props :confirmed?] false])} - [(if platform/ios? rn/keyboard-avoiding-view rn/view) (merge {:behavior :padding} st/transactions-screen) + [rn/keyboard-avoiding-view {:style st/transactions-screen} [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] [toolbar-view] [rn/scroll-view st/details-screen-content-container From a15fb7e2a8423c052afc94685b1a8098acece43b Mon Sep 17 00:00:00 2001 From: alwx Date: Sun, 12 Mar 2017 14:20:56 +0300 Subject: [PATCH 32/48] New chat input & suggestions area; new handlers to work with the improved logic (#880) --- .re-natal | 2 +- .../main/assets/fonts/RobotoMono-Medium.ttf | Bin 0 -> 113524 bytes .../main/res/drawable-hdpi/icon_arrow_top.png | Bin 0 -> 816 bytes .../res/drawable-hdpi/icon_close_gray.png | Bin 347 -> 622 bytes .../drawable-hdpi/icon_close_light_gray.png | Bin 0 -> 464 bytes .../res/drawable-hdpi/icon_input_list.png | Bin 469 -> 423 bytes .../src/main/res/drawable-hdpi/icon_smile.png | Bin 1214 -> 1672 bytes .../main/res/drawable-mdpi/icon_arrow_top.png | Bin 0 -> 632 bytes .../res/drawable-mdpi/icon_close_gray.png | Bin 274 -> 325 bytes .../drawable-mdpi/icon_close_light_gray.png | Bin 0 -> 329 bytes .../res/drawable-mdpi/icon_input_list.png | Bin 247 -> 208 bytes .../src/main/res/drawable-mdpi/icon_smile.png | Bin 704 -> 732 bytes .../res/drawable-xhdpi/icon_arrow_top.png | Bin 0 -> 1034 bytes .../res/drawable-xhdpi/icon_close_gray.png | Bin 444 -> 811 bytes .../drawable-xhdpi/icon_close_light_gray.png | Bin 0 -> 550 bytes .../res/drawable-xhdpi/icon_input_list.png | Bin 333 -> 664 bytes .../main/res/drawable-xhdpi/icon_smile.png | Bin 1510 -> 2648 bytes .../res/drawable-xxhdpi/icon_close_gray.png | Bin 624 -> 0 bytes .../drawable-xxhdpi/icon_close_light_gray.png | Bin 0 -> 753 bytes .../res/drawable-xxhdpi/icon_input_list.png | Bin 651 -> 0 bytes .../main/res/drawable-xxhdpi/icon_smile.png | Bin 2424 -> 0 bytes .../res/drawable-xxxhdpi/icon_close_gray.png | Bin 892 -> 0 bytes .../icon_close_light_gray.png | Bin 0 -> 1108 bytes .../res/drawable-xxxhdpi/icon_input_list.png | Bin 823 -> 0 bytes .../main/res/drawable-xxxhdpi/icon_smile.png | Bin 3268 -> 0 bytes env/dev/env/android/main.cljs | 2 +- externs/externs.js | 6 + ios/RobotoMono-Medium.ttf | Bin 0 -> 113524 bytes ios/StatusIm.xcodeproj/project.pbxproj | 6 +- .../icon_arrow_top.imageset/Contents.json | 23 ++ .../icon_arrow_top.png | Bin 0 -> 632 bytes .../icon_arrow_top@2x.png | Bin 0 -> 816 bytes .../icon_arrow_top@3x.png | Bin 0 -> 1034 bytes .../icon_close_gray.imageset/Contents.json | 4 +- .../icon_close_gray.png | Bin 624 -> 0 bytes .../icon_close_gray@1x.png | Bin 0 -> 325 bytes .../icon_close_gray@2x.png | Bin 0 -> 622 bytes .../icon_close_gray@3x.png | Bin 0 -> 811 bytes .../Contents.json | 23 ++ .../icon_close_gray-1.png | Bin 0 -> 753 bytes .../icon_close_gray-2.png | Bin 0 -> 550 bytes .../icon_close_gray.png | Bin 0 -> 329 bytes .../icon_input_list.imageset/Contents.json | 2 + .../icon_input_list.png | Bin 651 -> 208 bytes .../icon_input_list@2x.png | Bin 0 -> 423 bytes .../icon_input_list@3x.png | Bin 0 -> 664 bytes .../icon_smile.imageset/Contents.json | 2 + .../icon_smile.imageset/icon_smile.png | Bin 2424 -> 732 bytes .../icon_smile.imageset/icon_smile@2x.png | Bin 0 -> 1672 bytes .../icon_smile.imageset/icon_smile@3x.png | Bin 0 -> 2648 bytes ios/StatusIm/Info.plist | 1 + resources/commands.js | 188 +++++----- resources/console.js | 207 +++++------ resources/dapp.js | 35 +- resources/status.js | 44 +-- resources/wallet.js | 35 +- src/status_im/android/platform.cljs | 3 +- src/status_im/chat/constants.cljs | 14 +- src/status_im/chat/handlers.cljs | 262 ++------------ src/status_im/chat/handlers/animation.cljs | 175 +++------- src/status_im/chat/handlers/commands.cljs | 325 ++---------------- src/status_im/chat/handlers/faucet.cljs | 11 - src/status_im/chat/handlers/input.cljs | 264 ++++++++++++++ .../chat/handlers/receive_message.cljs | 4 +- src/status_im/chat/handlers/send_message.cljs | 65 +--- .../chat/handlers/webview_bridge.cljs | 13 - src/status_im/chat/models/input.cljs | 190 ++++++++++ src/status_im/chat/models/password_input.cljs | 48 +++ src/status_im/chat/models/suggestions.cljs | 32 ++ src/status_im/chat/screen.cljs | 59 +--- src/status_im/chat/styles/animations.cljs | 28 ++ .../chat/styles/command_validation.cljs | 16 - .../chat/styles/content_suggestions.cljs | 37 -- src/status_im/chat/styles/dragdown.cljs | 12 - src/status_im/chat/styles/emoji.cljs | 22 -- src/status_im/chat/styles/input.cljs | 69 ---- src/status_im/chat/styles/input/emoji.cljs | 16 + src/status_im/chat/styles/input/input.cljs | 132 +++++++ .../chat/styles/input/result_box.cljs | 45 +++ .../chat/styles/input/suggestions.cljs | 45 +++ .../chat/styles/input/validation_message.cljs | 23 ++ .../styles/{ => message}/command_pill.cljs | 2 +- .../chat/styles/{ => message}/datemark.cljs | 6 +- .../chat/styles/{ => message}/message.cljs | 2 +- src/status_im/chat/styles/message_input.cljs | 48 --- src/status_im/chat/styles/plain_message.cljs | 58 ---- src/status_im/chat/styles/response.cljs | 87 ----- src/status_im/chat/styles/screen.cljs | 4 +- src/status_im/chat/styles/suggestions.cljs | 112 ------ src/status_im/chat/subs.cljs | 313 +++++++---------- src/status_im/chat/suggestions.cljs | 52 --- src/status_im/chat/suggestions_responder.cljs | 29 -- src/status_im/chat/utils.cljs | 12 +- src/status_im/chat/views/command.cljs | 27 -- .../chat/views/command_validation.cljs | 30 -- .../views/input/animations/expandable.cljs | 67 ++++ .../views/input/animations/responder.cljs | 28 ++ .../chat/views/{ => input}/emoji.cljs | 10 +- src/status_im/chat/views/input/input.cljs | 220 ++++++++++++ .../chat/views/input/parameter_box.cljs | 31 ++ .../chat/views/input/result_box.cljs | 37 ++ .../chat/views/input/suggestions.cljs | 75 ++++ src/status_im/chat/views/input/utils.cljs | 16 + .../chat/views/input/validation_messages.cljs | 24 ++ src/status_im/chat/views/input/web_view.cljs | 45 +++ .../chat/views/{ => message}/datemark.cljs | 4 +- .../chat/views/{ => message}/message.cljs | 16 +- .../views/{ => message}/request_message.cljs | 22 +- src/status_im/chat/views/message_input.cljs | 182 ---------- src/status_im/chat/views/new_message.cljs | 29 -- src/status_im/chat/views/plain_message.cljs | 107 ------ src/status_im/chat/views/response.cljs | 176 ---------- src/status_im/chat/views/suggestions.cljs | 130 ------- .../chats_list/views/inner_item.cljs | 4 +- src/status_im/commands/handlers/jail.cljs | 74 ++-- src/status_im/commands/handlers/loading.cljs | 1 + src/status_im/commands/utils.cljs | 29 +- src/status_im/components/list_selection.cljs | 6 +- src/status_im/components/react.cljs | 10 +- src/status_im/components/styles.cljs | 2 + src/status_im/data_store/messages.cljs | 5 + src/status_im/db.cljs | 4 - src/status_im/handlers.cljs | 4 - src/status_im/ios/platform.cljs | 3 +- src/status_im/models/commands.cljs | 77 ----- src/status_im/profile/handlers.cljs | 4 +- src/status_im/subs.cljs | 4 - src/status_im/translations/en.cljs | 2 + src/status_im/utils/js_resources.cljs | 2 +- 129 files changed, 2052 insertions(+), 2670 deletions(-) create mode 100644 android/app/src/main/assets/fonts/RobotoMono-Medium.ttf create mode 100644 android/app/src/main/res/drawable-hdpi/icon_arrow_top.png create mode 100644 android/app/src/main/res/drawable-hdpi/icon_close_light_gray.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_arrow_top.png create mode 100644 android/app/src/main/res/drawable-mdpi/icon_close_light_gray.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_arrow_top.png create mode 100644 android/app/src/main/res/drawable-xhdpi/icon_close_light_gray.png delete mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_close_gray.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_close_light_gray.png delete mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_input_list.png delete mode 100644 android/app/src/main/res/drawable-xxhdpi/icon_smile.png delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_close_gray.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_close_light_gray.png delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_input_list.png delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/icon_smile.png create mode 100644 ios/RobotoMono-Medium.ttf create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top.png create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top@2x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top@3x.png delete mode 100644 ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray@1x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray@2x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray@3x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/Contents.json create mode 100644 ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/icon_close_gray-1.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/icon_close_gray-2.png create mode 100644 ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/icon_close_gray.png create mode 100644 ios/StatusIm/Images.xcassets/icon_input_list.imageset/icon_input_list@2x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_input_list.imageset/icon_input_list@3x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_smile.imageset/icon_smile@2x.png create mode 100644 ios/StatusIm/Images.xcassets/icon_smile.imageset/icon_smile@3x.png create mode 100644 src/status_im/chat/handlers/input.cljs create mode 100644 src/status_im/chat/models/input.cljs create mode 100644 src/status_im/chat/models/password_input.cljs create mode 100644 src/status_im/chat/models/suggestions.cljs create mode 100644 src/status_im/chat/styles/animations.cljs delete mode 100644 src/status_im/chat/styles/command_validation.cljs delete mode 100644 src/status_im/chat/styles/content_suggestions.cljs delete mode 100644 src/status_im/chat/styles/dragdown.cljs delete mode 100644 src/status_im/chat/styles/emoji.cljs delete mode 100644 src/status_im/chat/styles/input.cljs create mode 100644 src/status_im/chat/styles/input/emoji.cljs create mode 100644 src/status_im/chat/styles/input/input.cljs create mode 100644 src/status_im/chat/styles/input/result_box.cljs create mode 100644 src/status_im/chat/styles/input/suggestions.cljs create mode 100644 src/status_im/chat/styles/input/validation_message.cljs rename src/status_im/chat/styles/{ => message}/command_pill.cljs (89%) rename src/status_im/chat/styles/{ => message}/datemark.cljs (59%) rename src/status_im/chat/styles/{ => message}/message.cljs (99%) delete mode 100644 src/status_im/chat/styles/message_input.cljs delete mode 100644 src/status_im/chat/styles/plain_message.cljs delete mode 100644 src/status_im/chat/styles/response.cljs delete mode 100644 src/status_im/chat/styles/suggestions.cljs delete mode 100644 src/status_im/chat/suggestions.cljs delete mode 100644 src/status_im/chat/suggestions_responder.cljs delete mode 100644 src/status_im/chat/views/command.cljs delete mode 100644 src/status_im/chat/views/command_validation.cljs create mode 100644 src/status_im/chat/views/input/animations/expandable.cljs create mode 100644 src/status_im/chat/views/input/animations/responder.cljs rename src/status_im/chat/views/{ => input}/emoji.cljs (71%) create mode 100644 src/status_im/chat/views/input/input.cljs create mode 100644 src/status_im/chat/views/input/parameter_box.cljs create mode 100644 src/status_im/chat/views/input/result_box.cljs create mode 100644 src/status_im/chat/views/input/suggestions.cljs create mode 100644 src/status_im/chat/views/input/utils.cljs create mode 100644 src/status_im/chat/views/input/validation_messages.cljs create mode 100644 src/status_im/chat/views/input/web_view.cljs rename src/status_im/chat/views/{ => message}/datemark.cljs (80%) rename src/status_im/chat/views/{ => message}/message.cljs (97%) rename src/status_im/chat/views/{ => message}/request_message.cljs (86%) delete mode 100644 src/status_im/chat/views/message_input.cljs delete mode 100644 src/status_im/chat/views/new_message.cljs delete mode 100644 src/status_im/chat/views/plain_message.cljs delete mode 100644 src/status_im/chat/views/response.cljs delete mode 100644 src/status_im/chat/views/suggestions.cljs diff --git a/.re-natal b/.re-natal index bcad9e346e..bd6b8b4b08 100644 --- a/.re-natal +++ b/.re-natal @@ -1,7 +1,7 @@ { "name": "StatusIm", "interface": "reagent", - "androidHost": "10.0.3.2", + "androidHost": "10.0.2.2", "modules": [ "react-native-contacts", "react-native-invertible-scroll-view", diff --git a/android/app/src/main/assets/fonts/RobotoMono-Medium.ttf b/android/app/src/main/assets/fonts/RobotoMono-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0bcdc740c66c52cb33ca80ff854d9a1e8ecd4003 GIT binary patch literal 113524 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

KpOE?ZR!MT73+7 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 G+W!IVeN|=v literal 0 HcmV?d00001 diff --git a/ios/StatusIm.xcodeproj/project.pbxproj b/ios/StatusIm.xcodeproj/project.pbxproj index 5889ef5053..bf5778f75e 100644 --- a/ios/StatusIm.xcodeproj/project.pbxproj +++ b/ios/StatusIm.xcodeproj/project.pbxproj @@ -56,6 +56,7 @@ A6AF670051B842249D520C7B /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7ED174A34D7D42358313368B /* Foundation.ttf */; }; AD5063BC2B2A4C52ACE0A0B4 /* libUdpSockets.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A96279092BEC4C4B93914F48 /* libUdpSockets.a */; }; AE97D4B08C9F4821B8E9C50B /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 359B076A658B4FBAB5128B03 /* Ionicons.ttf */; }; + B23B48FF1E76917B006D4535 /* RobotoMono-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */; }; B24FC7FD1DE7195700D694FF /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7FC1DE7195700D694FF /* Social.framework */; }; B24FC7FF1DE7195F00D694FF /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7FE1DE7195F00D694FF /* MessageUI.framework */; }; B2A5F45C1DEC36BB00174F4D /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A5F4381DEC36B200174F4D /* libRCTAnimation.a */; }; @@ -453,6 +454,7 @@ 9F1854E6D9654226B1FC8308 /* RCTCamera.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTCamera.xcodeproj; path = "../node_modules/react-native-camera/ios/RCTCamera.xcodeproj"; sourceTree = ""; }; A96279092BEC4C4B93914F48 /* libUdpSockets.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libUdpSockets.a; sourceTree = ""; }; ACA66A8F16CD2FE21F38738B /* Pods-StatusIm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatusIm.debug.xcconfig"; path = "Pods/Target Support Files/Pods-StatusIm/Pods-StatusIm.debug.xcconfig"; sourceTree = ""; }; + B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "RobotoMono-Medium.ttf"; sourceTree = ""; }; B24FC7F51DE7190C00D694FF /* RNShare.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNShare.xcodeproj; path = "../node_modules/react-native-share/ios/RNShare.xcodeproj"; sourceTree = ""; }; B24FC7FC1DE7195700D694FF /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; B24FC7FE1DE7195F00D694FF /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; @@ -468,8 +470,8 @@ DF1CD4C3D1254774ACCAE4E8 /* libBVLinearGradient.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libBVLinearGradient.a; sourceTree = ""; }; F090E261B9854867A728CE4F /* RealmReact.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RealmReact.xcodeproj; path = "../node_modules/realm/react-native/ios/RealmReact.xcodeproj"; sourceTree = ""; }; F3548417D8DA4362B6796A54 /* RNInstabug.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNInstabug.xcodeproj; path = "../node_modules/instabug-reactnative/ios/RNInstabug.xcodeproj"; sourceTree = ""; }; - F93B6663A59F4B26BD4DA525 /* RNNetworkInfo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNNetworkInfo.xcodeproj; path = "../node_modules/react-native-network-info/ios/RNNetworkInfo.xcodeproj"; sourceTree = ""; }; F9238D6B1E5F055900C047B9 /* SF-UI-Text-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Semibold.otf"; sourceTree = ""; }; + F93B6663A59F4B26BD4DA525 /* RNNetworkInfo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNNetworkInfo.xcodeproj; path = "../node_modules/react-native-network-info/ios/RNNetworkInfo.xcodeproj"; sourceTree = ""; }; FC1CBCFE6C906043D6CCEEE1 /* libPods-StatusImTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-StatusImTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -642,6 +644,7 @@ 54E2B86FB12D4CC49DA05C69 /* MaterialIcons.ttf */, B3B19223008342D096AA356E /* Octicons.ttf */, 2756305FAFF144C4A6B0A039 /* Zocial.ttf */, + B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */, ); name = Resources; sourceTree = ""; @@ -1477,6 +1480,7 @@ F9238D6C1E5F055900C047B9 /* SF-UI-Text-Semibold.otf in Resources */, 2028DFFC1D4275B600227DCD /* SF-UI-Display-Thin.otf in Resources */, 2028DFFB1D4275B600227DCD /* SF-UI-Display-Semibold.otf in Resources */, + B23B48FF1E76917B006D4535 /* RobotoMono-Medium.ttf in Resources */, D28AEFB4C39548EB80416889 /* Entypo.ttf in Resources */, 82E689BAF9FB43C8AC6FF1CA /* EvilIcons.ttf in Resources */, C3EE9AEA6F77464588FBAA64 /* FontAwesome.ttf in Resources */, diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/Contents.json new file mode 100644 index 0000000000..067327c77b --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_arrow_top.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon_arrow_top@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icon_arrow_top@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top.png b/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top.png new file mode 100644 index 0000000000000000000000000000000000000000..dd47f4ff17abba8f264a31395c2ce89532f5c422 GIT binary patch literal 632 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$Ysfq^kHGbExU!q>+tIX_n~ zF(p4KRj(qq0H}k3!KT6r$jnVGNmQuF&B-gas<2f8tFQvHLBje<3ScEA*|tg%z5xo( z`9-M;rg|oN21<5Z3JMA~MJZ`kK`w4k?LeNbQbtKhft9{~d3m{Bxv^e;QM$gNrKP35 zfswwEkuFe$ZgFK^Nn(X=Ua>O75STeGsl~}fnFS@8`FRQ;a}$&DOG|8(lt3220mPjp znP~`{@`|C}0(wv%B%^PrXP^%^8>rO=Bx>bfl$i>&8Dzelp$%9iiWt-$8-0-FNREN{ z6f6q#svVb&K0Mg$xO@(&M*>4~o~MgrhzDW1=#=p_wUMVsd4Cv zjJVnt)nFPifi-f1rOSrxf(z3^PG)cfSh6sf&zU81bdH!YDAGM${an^LB{Ts5T-d+( literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top@2x.png b/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..193fe2261df4db55d9faa2c81aef5895184483db GIT binary patch literal 816 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6==i2z!;es5>XQ2>tmIipR1Rc zlAn~SSCLx))WN`DQ(*;U=BAb;Dpcg=|?L9&C18K8MsJfq@+6>EalY!TNUEORhr>JS|tJfByGyE&scG!LPD=7Mybk zzqB;E|8CU*7N_l==0A<1Go*QEicDY%a^Uh{)Kp+y;!wo8Nk{tN_7A2tGxj*nWo6vc z6#wwtj<{<#jU#iL4(aZZO`5nSP`1@!7sr9yiqA^F^sVDO^pm;5{0M7zWXa(vtQ;)r zH#Q$jU#=;6Z=I{a4*q(bnMe8y&p&y4Ow&wAf#JTU}K@+IdPL)Y4y5wz6H6DYVZ7V&WZh(9PS{)F-^LWOKVrl?kIyJ z6;)*&&1dUV<~kR2@a}nQ?z$#H^{1KKjRW659QyEYbLjW8t5SUU0={2wE1k7rM%BW- zYXcs|KazTITYahU1x^>O1>qV&2VT6jYUJYlu9kjX?ayKFKb{}1S5E)^SO07K#8x%d hB@NJUY1|+DfK8p*``F%2t};+!^>p=fS?83{1OQzbD;59% literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top@3x.png b/ios/StatusIm/Images.xcassets/icon_arrow_top.imageset/icon_arrow_top@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9125df76b51a88c1820145d8f008865c7339ce36 GIT binary patch literal 1034 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$Ysfq^kHGbExU!q>+tIX_n~ zF(p4KRj(qq0H}k3!KT6r$jnVGNmQuF&B-gas<2f8tFQvHLBje<3ScEA*|tg%z5xo( z`9-M;rg|oN21<5Z3JMA~MJZ`kK`w4k?LeNbQbtKhft9{~d3m{Bxv^e;QM$gNrKP35 zfswwEkuFe$ZgFK^Nn(X=Ua>O75STeGsl~}fnFS@8`FRQ;a}$&DOG|8(lt3220mPjp znP~`{@`|C}0(wv%B%^PrXP^%^8>rO=Bx>bfl$i>&8Dzelp$%9iiWt-$8-0-FNREN{ z6f6q#svVb&K0Mg$xO@(&M=~%l8F;!lhEy=Vo%zy_$x)!iGNdN`Z{nZCqzmC6nEpPm z{cRz|GCygpQum`vo7WblOk3%vb)e+!rN6%K)ws9La$<3Dz=^b66;5vw+rs>H0pk|- zty)))?CE0dD1E`Ibxc_7QX30H%jXys<8MC&-(PMya!k>$Q=H#m32P^>^PIl>$838t z9g-FcEPu4Vu$}qZvr_$@M|(0R6j<>7?~Rt(F=xUJi6fdb%<>AFo;Dq6Q+W4p%_AxG zsNP4LW^Cgyak9AcHS)NqUqr4)4#T6o=|>$sKdn$XenmCJ*F#62#9ij#VUn2V3A zRxZ<9kmZT(;Ai z5w{|F);{s=ZvS4y2O7^m<$N&nN7Lanr(+-89%ee-ogn^tZ(;qF_knNR7YOoA)Ui5!6mbzg+>%lwowTpP)7id0EU1I!r#)S$t_uw_4&B+FfaT_Q@ccUv%S%QWNt+%a6Zbceq|lti68Z?*XHwd(<4x zz2lz1V97FPi<(D+43l4!u!;j8qxxD-A%*sa$=6soCpaJQ%x+>iq4;1)^2`PM0+(-1 zyYXzd2={`%i)q&*yo)*aPycxTdh82Z@%#GM|G&@7Tf0k)QBVLYYCOVG!{pd*B0pPx%DoI2^R9Fek*gZ?bKo|$`yNl?SFCleN94sz6b+bjJehd|hRh-009JNx=Z{Q{< z4#usMZaV4c<{&r-83c<>ynov(*EDJFB>``_8cKLMZd{bZptHj_T}tT9 z(!%UXsZ{#KvAjyF)tY#Ge%%X6Smk5*A!Uuj-K~3ibb7u*g20mpri6Izd-%kL878*bbnd7#E&`UaO_ z&cuPxmL*C7LttT;z?d_6qSP?NgN5POgbAD%N)-bGEZos6I)SRcK9igS5LhM&`sXuJ zndTY-WrZ@uVEhq~Ey@Oy2r@<4V#b1WQRpA{IzYQ9{C1?il45U}NPt@PtkF06ZbF+V zDj4)l1)-A)3jLCbDhBaNAapcE>0q=#CMaEuHb@6$fi3Mx~WSbC4 zZE_5OY!U$?7t>q=kZA%L5#2V)*#(&dMh8#Y*Ue4w72@IP2$nFtVd9vG2(910db_W$^#2h2fz)B6KRl_guONHN?10000< KMNUMnLSTZ(Ul}F< diff --git a/ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray@1x.png b/ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..0715d8b5e211e2b4eac2eeac505705564f45474d GIT binary patch literal 325 zcmV-L0lNN)P)Px#|4BqaR7ef&lQ9m0FcgN{CPu{B3+U)6@DO?dcSnO$Cy9xRyBF{joT94-&{@L- z_E(yamp(9ou?#f4_woPj-&Tn5garB~AUT2EUSBIw&ZjEcWZB{A(h3YxRGuz}@Z5mE6$ zH`yodPD@*lhRW^%ZYUQ8j7Af+LS$gTQepSa8sPd{DCbVgS?fm~SzfbFGmIgDffM)u XqPmPx%C`m*?RA>e5Si3R=K@{y?oAVnYsl+O|z(xW;KtxDcYO#vYW`01R1Oz?+C6TBS zD8*NhuW9$p?xkx=&vf_p1j?PNsoOJi@9A?+Pxm~Ol1&^C2gCt!KpYSU#DV|ofDVV`$r+?JF4#lwZ*SETh#$-LM^oMRXS5JC7FZT7ScB3kxcs(a?OiLLx zW3udOeRFrYnB#klT43Z@gb8flTFwg=K!sCWOmV^(brvHcCr`D&U_6W}w|!%{0IjzP z{L|_nSj2DSfr(qv!u4u?tM|&Lq=);Px7oS*S8BFtX9E!1IR9{e`%G=;<|eOJ`p0{h z&O*n9U;)4Z$rusk z;+~JYZS4M&2mqi<#Hh1c$OGF39`zL$N+ve1Q~*xqJhMzD0Duk=+*fk)0Jh!Xj{a0k zIs%S)z=n7~?6|-uCKKQwk5>*uJCAg75lL1d7kMm|aIwy1bnFo*Bae07F|m`4#8?8V z$isbXb&7}<;7fiep*|5&0z%2xDI!?F@Eg`#5GlLX`yo|&JGB-b@x8%psPx# literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray@3x.png b/ios/StatusIm/Images.xcassets/icon_close_gray.imageset/icon_close_gray@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..00da9eba41c9cfa18c98da121e569e4eb33f087b GIT binary patch literal 811 zcmV+`1JwM9P)Px%>)9u)RHn+3aWKqrBeOLm}#%~=HSEbKesMXW9p0(X(o zVj*=36p9lQsWTuK9J)#fWA1JgU2*8~fq>@fQNstPemxY@hF~Q&(XUvWfwpPO2_*)^ zF+h$OZLvgvI0wcVD+G%jNMb+|Fx!a;++1 zdswZOpa}mGNVfrWucXha^$jlNV!JAQjvIe}(}1{sLv})U|Q|z;uuoF z`1aODzdH^BYzgl*gw-H$!#k5@f%V&n>FU=mrtz^dVZ%5>0ru!L9j zt=@Vy_I;n0f8KWc+|T>fyXDUxd;D?olKlH-n{U23Jbyp`{k`SwpC!K6h0L8_^Rwo% z`Mn~0(*@o0um8TfdA^yj#q(wJ%kBimUhhBqH|qA}lPRyio%{dkp1etN-<=h9|DyJ< zTv}<9T0P~`j@4^_hu22i^&K)~;7R#;E9;1`UKNT?({(C zEz=@uSASc{_;A+cX+FZ94Z)>XFNG!Ft}|7LnNWB((|bvy%HhJ`E0@CDUjfC=gzZp> zR`e_kXnuBPrCE3DexFkgOE%ATJrnSL)mAG3p)5WR<7-+yHwuLnbeCMRkZ6~@5U`~5 zfFb*}mwR_ETz1bL4 zcqlTGOH(@_e$FJ1n++-!7TygT3++XgT2$O%UC_Jhs>eZ2{tLgpFs?b8^h;FQ=z?Oc z>B2J&CTuGNlQpJsPIz{}B>C&XAofiX6I^{Xr)f=i>Y$Tcp1AUE_d{Lo(=R2B=Y08} zw_<7b1V9dZ4i6^+@(14p8LrOarZ>Ku1(q%%$qUqhuyRo zVf7>83a;6le}k`OIjk$PpC%mrphYIuV`G%l{wrHw>1^X$|A5i`_1jG$KHHXKCK*UV cGK+m+fAMyIKzrjAP#R|NboFyt=akR{0B|5yRR910 literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/icon_close_gray-2.png b/ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/icon_close_gray-2.png new file mode 100644 index 0000000000000000000000000000000000000000..03a450426812d696ba5339f3714cab332a096fb6 GIT binary patch literal 550 zcmV+>0@?kEP)Px$;7LS5RA>e5SV2z1Fc9>H-pe;Q@q<19dgu)#Dtd)Cz!CnywWyWKjYHu9{D2eR zfIDRIG%Q4w(|GMvs>DXB?Ap8InThShan3Gtz#K3K%mH)2954s|uLGo&e!o~Al%I6R z%>9DsdNMv;o?LO3Dx!%zFjLl(dJ&5=n~5AfNL;;4$*Jdu>d68CrXi$>4H0c>%MuVP zVq4@fezt%%5$MNGRo`u}eyTYio@&U6y*d$q!J1q~-?qpDyE6d*3yDCxTwOZ&!=Rj9NyTY+4Bu<8=jy$b*ei1j3$5sh}JH3r=B0m{d`+Q7{+(~VjwFWfA zG_e{H$pTUcrR21UNfMAlBqui{MlAqmSR4a$c9v!lG}4|4)DJRG{5FR?T*TrI9g1+c z54pUlO)bE`J-rKH&g(%)1inlNc5JB@&~tR@2YT@XypqE$Pk$w@M9^r36w onFHp4IbaT$1LlA^U=BF<4Zs(ANm=WD=Kufz07*qoM6N<$f&gptvH$=8 literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/icon_close_gray.png b/ios/StatusIm/Images.xcassets/icon_close_light_gray.imageset/icon_close_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..4918a29a64395886c4d67cf39d32e0cca9653f26 GIT binary patch literal 329 zcmV-P0k-~$P)Px$14%?dR7ef&Q#%fVKoFhTL<)K@pe3ik#zZ>{tTYxL%fiG;du=&|tq0Jaf`XL? z*|1r6zywOB;4|~~z1g=rL}QE&^mTwGg7f8mBBogw@HRf bhIQZzMtramFYb8q00000NkvXXu0mjfd~Sr= literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_input_list.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_input_list.imageset/Contents.json index 5fcc1377bb..83b19e6893 100644 --- a/ios/StatusIm/Images.xcassets/icon_input_list.imageset/Contents.json +++ b/ios/StatusIm/Images.xcassets/icon_input_list.imageset/Contents.json @@ -7,10 +7,12 @@ }, { "idiom" : "universal", + "filename" : "icon_input_list@2x.png", "scale" : "2x" }, { "idiom" : "universal", + "filename" : "icon_input_list@3x.png", "scale" : "3x" } ], diff --git a/ios/StatusIm/Images.xcassets/icon_input_list.imageset/icon_input_list.png b/ios/StatusIm/Images.xcassets/icon_input_list.imageset/icon_input_list.png index 9e4fd528b3052cec72c432a4092e9f297d4b997f..6f58d3c7243dd863854ccdfd6c7a1559df92f370 100644 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|x;$MRLp*qs z6C_xbjaj%>M=x=lA+;~v#hfMO!+rbx@0yRyjJzT8J34#bv+yhVfB*mAFTN`(#ZFoI z@wQIc-g_sK6wHKoG2EcY}t)Nv}OP29#^rgg1Px%MM*?KR9Fe^SiLVqK@gwWcS1))f<#G0N3D=(XzyPTL2^ezg3?DwxJwZ6FI-DQ z6k19uO2rYHQ#$YMnmsld&pFH9yWC6OHoH4JyYsPcXMS%Gs1*tY@9zG2L4isG!T>0^ zMZiLTU*}Fboenflvo`!t{^^{Q9}O!>MqKpwb&b_BVm)`%4Z+)_MAZ}CU(dNvSWLC5 zlcl-2B0o3v>G@GkG-GX)UZ?rCq49og_i#kY@+r|e=++`_k_5cH;>$*Ue|$MJdufD; z%4cI{Rr;FiD#+2f9aXkPLLyz-10Qnya8dc@IVC*SZ{mkWP9OSVDLOL3AU|B_2g?cH z#2W9{&|58WDxS zYdK!YPCa}vKu_YF2e>iGIPpN@fy4ui_W&ifc!yEvM5f`il>P*O?ER1b1qdYpibAAL z!b!^JJSRB4nLilzgYuaRB9%buQzKYjB6vQ&IzN47qqyO5g402u@-E67B`Up!E ztH`U<+yGvwc7oGN2K9r}TtkbosZ=|`X##RzD#aFZ>&rs&n+i_<)jAEoo#1rCtJB;< l4dcN_Fh>z&pIia(Xk^e@_4a002ovPDHLkV1h)hEa3nE diff --git a/ios/StatusIm/Images.xcassets/icon_input_list.imageset/icon_input_list@2x.png b/ios/StatusIm/Images.xcassets/icon_input_list.imageset/icon_input_list@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efa3cdd2051037f07f98a4d4338d60fb50e83db8 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^TTo$a)AMj|fFGw>_ezYKRqvnb8 zIuirFTu#}v$@ZIcbiI2EKj#DnC`u6yxbpeMnj0p)zw_3M&3m8MU4Et9!+J%-<)gFbr?*%Z%I?l@VU3l3gY2_@%vOH$d4Q7$`7nkMkJN)a`^MuUF zzizzVrZv6p^sfs>9u^L<-zkzpn_S<-iygBrTy)sFQ0bsKA|y%#e=t3kI4aW>ad8DOU<&edaSW+o ze0%Gl-ysJ9wg)%Wx{l1~Ft?pm@$r@Li|P)4#R>tH0>N6Qbq9)nu*L12QE^3jh6Jl^ z$sNtc3Cpz8%A^D9^)IZnzFil)?QKfu2X;md2L>jA1_l-d1{CHQmNRc=Kk{CB_g;m3 zUzX3ui6-VEcSXF8UJKp&YmvwHDZW=6IL|%!I<52Dv-4-v_UPxVl}}MDwVFG1cl&WQ zNxQ^lZ-168+%N6y?-ICwi`(;Fx5v)2?Jt?h@ZWotDRWZQP%<>KlC{0_{HJ4{eTU;1 zp8fbzd1URHL41>yK^trM~usUgn`N zkK19lRyL+Mm6g7^C;l}y_fywx?Mq)zu4S9Fd#cZgm*-T~eqSoQIgRu3j2Bf#jcI?~ zcg*;bcp~QA`*&ArH&yZe{9iEp`$5-enCGWOF`Reg*6Ww@2!6LAwf*YD8M9mpEw4z| zemZhy+4e{i)A^g)PJ8}cwNSI1qfgf{#QEU~PtSETc07u{#=*Blt9(QJ%Y&stoKw;x z4^NG@ZHnRC-}OB5-3Q(59evTfPxLZv*OpUCQ@@qFJ6$dR#u{$js{}+~Qy!MT_M> bUXA`WqGFczZW+$Nq{iUs>gTe~DWM4fd(I%H literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Images.xcassets/icon_smile.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_smile.imageset/Contents.json index 322839f98e..78c4c5a6c8 100644 --- a/ios/StatusIm/Images.xcassets/icon_smile.imageset/Contents.json +++ b/ios/StatusIm/Images.xcassets/icon_smile.imageset/Contents.json @@ -7,10 +7,12 @@ }, { "idiom" : "universal", + "filename" : "icon_smile@2x.png", "scale" : "2x" }, { "idiom" : "universal", + "filename" : "icon_smile@3x.png", "scale" : "3x" } ], diff --git a/ios/StatusIm/Images.xcassets/icon_smile.imageset/icon_smile.png b/ios/StatusIm/Images.xcassets/icon_smile.imageset/icon_smile.png index 45dfb63996730514f7e4ea6e30282794413c733c..bed62a5cd5db3fcd26345b8ef23edfe887bcb34b 100644 GIT binary patch literal 732 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 literal 0 HcmV?d00001 diff --git a/ios/StatusIm/Info.plist b/ios/StatusIm/Info.plist index 28aac58eed..9b7a0db342 100644 --- a/ios/StatusIm/Info.plist +++ b/ios/StatusIm/Info.plist @@ -58,6 +58,7 @@ We need to access your photo storage to give you an ability to select photos UIAppFonts + RobotoMono-Medium.ttf SF-UI-Text-Semibold.otf SF-UI-Text-Bold.otf SF-UI-Text-Regular.otf diff --git a/resources/commands.js b/resources/commands.js index 37ee508773..811ae30d6a 100644 --- a/resources/commands.js +++ b/resources/commands.js @@ -1,11 +1,11 @@ I18n.translations = { en: { location_title: 'Location', - location_description: 'Share your location', + location_description: 'Send location', location_address: 'Address', browse_title: 'Browser', - browse_description: 'Launch the browser', + browse_description: 'Open web browser', send_title: 'Send ETH', send_description: 'Send a payment', @@ -694,13 +694,15 @@ status.command({ } ); - return status.components.view({}, [text, image]); + return {markup: status.components.view({}, [text, image])}; }, - shortPreview: function(params) { - return status.components.text( - {}, - I18n.t('location_title') + ": " + params.address - ); + shortPreview: function (params) { + return { + markup: status.components.text( + {}, + I18n.t('location_title') + ": " + params.address + ) + }; } }).param({ name: "address", @@ -708,65 +710,59 @@ status.command({ placeholder: I18n.t('location_address') }); - -function browseSuggestions(params) { - if (params.url && params.url !== "undefined" && params.url != "") { +status.command({ + name: "browse", + fullscreen: true, + title: I18n.t('browse_title'), + description: I18n.t('browse_description'), + params: [{ + name: "url", + placeholder: "URL", + type: status.types.TEXT + }], + onSend: function (params, context) { var url = params.url; if (!/^[a-zA-Z-_]+:/.test(url)) { url = 'http://' + url; } - return {webViewUrl: url}; + return { + title: "Browser", + dynamicTitle: true, + markup: status.components.bridgedWebView(url) + }; } -} - -status.command({ - name: "browse", - title: I18n.t('browse_title'), - description: I18n.t('browse_description'), - color: "#ffa500", - fullscreen: true, - suggestionsTrigger: 'on-send', - params: [{ - name: "url", - suggestions: browseSuggestions, - type: status.types.TEXT - }] }); function validateSend(params, context) { if (!context.to) { return { - errors: [ - status.components.validationMessage( - "Wrong address", - "Recipient address must be specified" - ) - ] + markup: status.components.validationMessage( + "Wrong address", + "Recipient address must be specified" + ) }; } if (!params.amount) { return { - errors: [ - status.components.validationMessage( - I18n.t('validation_title'), - I18n.t('validation_amount_specified') - ) - ] + markup: status.components.validationMessage( + I18n.t('validation_title'), + I18n.t('validation_amount_specified') + ) }; } try { var val = web3.toWei(params.amount.replace(",", "."), "ether"); - if (val <= 0) { throw new Error(); } + if (val <= 0) { + throw new Error(); + } } catch (err) { return { - errors: [ - status.components.validationMessage( - I18n.t('validation_title'), - I18n.t('validation_invalid_number') - ) - ] + markup: status.components.validationMessage( + I18n.t('validation_title'), + I18n.t('validation_invalid_number') + ) }; } @@ -776,16 +772,15 @@ function validateSend(params, context) { to: context.to, value: val }); + if (bn(val).plus(bn(estimatedGas)).greaterThan(bn(balance))) { return { - errors: [ - status.components.validationMessage( - I18n.t('validation_title'), - I18n.t('validation_insufficient_amount') - + web3.fromWei(balance, "ether") - + " ETH)" - ) - ] + markup: status.components.validationMessage( + I18n.t('validation_title'), + I18n.t('validation_insufficient_amount') + + web3.fromWei(balance, "ether") + + " ETH)" + ) }; } } @@ -800,7 +795,11 @@ function sendTransaction(params, context) { try { return web3.eth.sendTransaction(data); } catch (err) { - return {error: err}; + var error = status.components.validationMessage( + "Error", + err.message + ); + return {error: {markup: error}}; } } @@ -855,25 +854,29 @@ var send = { )] ); - return status.components.view( - { - style: { - flexDirection: "row", - justifyContent: "space-between", - marginTop: 8, - marginBottom: 8 - } - }, - [amount, currency] - ); + return { + markup: status.components.view( + { + style: { + flexDirection: "row", + justifyContent: "space-between", + marginTop: 8, + marginBottom: 8 + } + }, + [amount, currency] + ) + }; }, shortPreview: function (params, context) { - return status.components.text( - {}, - I18n.t('send_title') + ": " - + status.localizeNumber(params.amount, context.delimiter, context.separator) - + " ETH" - ); + return { + markup: status.components.text( + {}, + I18n.t('send_title') + ": " + + status.localizeNumber(params.amount, context.delimiter, context.separator) + + " ETH" + ) + }; }, handler: sendTransaction, validator: validateSend @@ -884,8 +887,8 @@ status.response(send); status.command({ name: "request", + color: "#5fc48d", title: I18n.t('request_title'), - color: "#7099e6", description: I18n.t('request_description'), params: [{ name: "amount", @@ -904,30 +907,37 @@ status.command({ }; }, preview: function (params, context) { - return I18n.t('request_requesting') - + status.localizeNumber(params.amount, context.delimiter, context.separator) - + " ETH"; + return { + markup: status.components.text( + {}, + I18n.t('request_requesting') + " " + + status.localizeNumber(params.amount, context.delimiter, context.separator) + + " ETH" + ) + }; }, shortPreview: function (params, context) { - return status.components.text( - {}, - I18n.t('request_requesting') + " " - + status.localizeNumber(params.amount, context.delimiter, context.separator) - + " ETH" - ); + return { + markup: status.components.text( + {}, + I18n.t('request_requesting') + " " + + status.localizeNumber(params.amount, context.delimiter, context.separator) + + " ETH" + ) + }; }, - validator: function(params) { + validator: function (params) { try { var val = web3.toWei(params.amount.replace(",", "."), "ether"); - if (val <= 0) { throw new Error(); } + if (val <= 0) { + throw new Error(); + } } catch (err) { return { - errors: [ - status.components.validationMessage( - I18n.t('validation_title'), - I18n.t('validation_invalid_number') - ) - ] + markup: status.components.validationMessage( + I18n.t('validation_title'), + I18n.t('validation_invalid_number') + ) }; } } diff --git a/resources/console.js b/resources/console.js index aaf356bc55..4b5fcd7d57 100644 --- a/resources/console.js +++ b/resources/console.js @@ -58,7 +58,7 @@ I18n.translations = { password_error1: 'Wagwoordbevestiging is nie dieselfde as wagwoord nie.', password_validation_title: 'Wagwoord' - }, + }, ar: { phone_title: 'أرسل رقم الهاتف', phone_description: 'ابحث عن الأصدقاء باستخدام رقمك', @@ -107,7 +107,7 @@ I18n.translations = { password_placeholder2: '请重新输入密码以确认', password_error: '密码应不少于6个字符。', password_error1: '密码确认信息与密码不匹配。', - password_validation_title: '密码' + password_validation_title: '密码' }, 'zh-yue': { @@ -268,7 +268,7 @@ I18n.translations = { phone_description: '내 번호를 사용하여 친구 찾기', phone_placeholder: '전화번호', - confirm_description: '확인 코드', + confirm_description: '확인 코드', confirm_validation_title: '확인 코드', confirm_validation_description: '잘못된 형식', @@ -414,7 +414,7 @@ I18n.translations = { password_error: 'Nenosiri lisiwe chini ya alama 6.', password_error1: 'Uthibitisho wa nenosiri haulingani na nenosiri.', password_validation_title: 'Nenosiri' - + }, sv: { phone_title: 'Skicka telefonnummer', @@ -587,7 +587,7 @@ var WEB3_UNIT = [ // because web3 doesn't provide params or docs var DOC_MAP = { console: { - log : { + log: { desc: 'Outputs a message to chat context.', args: [{ name: 'text', @@ -1198,6 +1198,7 @@ var jsBoldValueStyle = { var jsDescriptionStyle = { marginTop: 1.5, + paddingBottom: 9, fontSize: 14, fontFamily: "font", color: "#838c93de" @@ -1206,9 +1207,9 @@ var jsDescriptionStyle = { var messages = []; -console = (function(old){ +console = (function (old) { return { - log: function(text){ + log: function (text) { old.log(text); var message = { type: 'log', @@ -1242,12 +1243,11 @@ console = (function(old){ }(console)); - if (!String.prototype.startsWith) { - String.prototype.startsWith = function(searchString, position){ - position = position || 0; - return this.substr(position, searchString.length) === searchString; - }; + String.prototype.startsWith = function (searchString, position) { + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; } function matchSubString(array, string) { @@ -1314,16 +1314,16 @@ function getLastForm(code) { var form = ''; var level = 0; var index = codeLength - 1; - while(index >= 0) { + while (index >= 0) { var char = code[index]; if (level == 0 && (char == '(' || char == ',')) { break; } if (char == ')') { - level --; + level--; } if (char == '(') { - level ++; + level++; } form = char + form; index--; @@ -1337,7 +1337,7 @@ function getLastLevel(code) { var index = codeLength - 1; var nested = false; var level = 0; - while(index >= 0) { + while (index >= 0) { var char = code[index]; if (char == ')') { level--; @@ -1510,9 +1510,6 @@ function createMarkupText(text) { } function jsSuggestions(params, context) { - - console.log(context); - var suggestions = getJsSuggestions(params.code, context); var sugestionsMarkup = []; @@ -1532,7 +1529,8 @@ function jsSuggestions(params, context) { ])]); if (suggestion.pressValue) { suggestionMarkup = status.components.touchable({ - onPress: [status.events.SET_VALUE, suggestion.pressValue]}, + onPress: [status.events.SET_VALUE, suggestion.pressValue] + }, suggestionMarkup); } sugestionsMarkup.push(suggestionMarkup); @@ -1547,7 +1545,6 @@ function jsSuggestions(params, context) { } - function jsHandler(params, context) { var result = { err: null, @@ -1558,7 +1555,7 @@ function jsHandler(params, context) { try { result.data = JSON.stringify(eval(params.code)); localStorage.set(params.code); - } catch(e) { + } catch (e) { result.err = e; } @@ -1567,25 +1564,6 @@ function jsHandler(params, context) { return result; } -var phones = [ // TODO this is supposed to be regionalised - { - number: "89171111111", - description: "Number format 1" - }, - { - number: "89371111111", - description: "Number format 1" - }, - { - number: "+79171111111", - description: "Number format 2" - }, - { - number: "9171111111", - description: "Number format 3" - } -]; - function suggestionsContainerStyle(suggestionsCount) { return { marginVertical: 1, @@ -1644,7 +1622,7 @@ function phoneSuggestions(params, context) { suggestions = ph.map(function (phone) { return status.components.touchable( - {onPress: [status.events.SET_VALUE, phone.number]}, + {onPress: [status.events.SET_COMMAND_ARGUMENT, [0, phone.number]]}, status.components.view(suggestionContainerStyle, [status.components.view(suggestionSubContainerStyle, [ @@ -1660,14 +1638,6 @@ function phoneSuggestions(params, context) { ); }); - /*var view = status.components.view( - {style: {flex: 1, flexDirection: "column"}}, - [status.components.scrollView( - suggestionsContainerStyle(ph.length), - suggestions - )] - );*/ - var view = status.components.scrollView( suggestionsContainerStyle(ph.length), suggestions @@ -1680,9 +1650,9 @@ var phoneConfig = { name: "phone", registeredOnly: true, icon: "phone_white", + color: "#5bb2a2", title: I18n.t('phone_title'), description: I18n.t('phone_description'), - color: "#5bb2a2", validator: function (params) { return { validationHandler: "phone", @@ -1711,9 +1681,9 @@ var faucets = [ ]; function faucetSuggestions(params) { - var suggestions = faucets.map(function(entry) { + var suggestions = faucets.map(function (entry) { return status.components.touchable( - {onPress: [status.events.SET_VALUE, entry.url]}, + {onPress: [status.events.SET_COMMAND_ARGUMENT, [0, entry.url]]}, status.components.view( suggestionContainerStyle, [status.components.view( @@ -1754,16 +1724,20 @@ status.command({ placeholder: I18n.t('faucet_placeholder') }], preview: function (params) { - return status.components.text( - {}, - params.url - ); + return { + markup: status.components.text( + {}, + params.url + ) + }; }, shortPreview: function (params) { - return status.components.text( - {}, - I18n.t('faucet_title') + ": " + params.url - ); + return { + markup: status.components.text( + {}, + I18n.t('faucet_title') + ": " + params.url + ) + }; }, validator: function (params, context) { var f = faucets.map(function (entry) { @@ -1776,15 +1750,15 @@ status.command({ I18n.t('faucet_incorrect_description') ); - return {errors: [error]}; + return {markup: error}; } } }); function debugSuggestions(params) { - var suggestions = ["On", "Off"].map(function(entry) { + var suggestions = ["On", "Off"].map(function (entry) { return status.components.touchable( - {onPress: [status.events.SET_VALUE, entry]}, + {onPress: [status.events.SET_COMMAND_ARGUMENT, [0, entry]]}, status.components.view( suggestionContainerStyle, [status.components.view( @@ -1820,42 +1794,45 @@ status.command({ type: status.types.TEXT }], preview: function (params) { - return status.components.text( - {}, - I18n.t('debug_mode_title') + ": " + params.mode - ); + return { + markup: status.components.text( + {}, + I18n.t('debug_mode_title') + ": " + params.mode + ) + }; }, shortPreview: function (params) { - return status.components.text( - {}, - I18n.t('debug_mode_title') + ": " + params.mode - ); + return { + markup: status.components.text( + {}, + I18n.t('debug_mode_title') + ": " + params.mode + ) + }; } }); -function browseSuggestions(params) { - if (params.url && params.url !== "undefined" && params.url != "") { +status.command({ + name: "browse", + title: "Browser", + registeredOnly: true, + description: "Open web browser", + params: [{ + name: "url", + placeholder: "URL", + type: status.types.TEXT + }], + onSend: function (params, context) { var url = params.url; if (!/^[a-zA-Z-_]+:/.test(url)) { url = 'http://' + url; } - return {webViewUrl: url}; + return { + title: "Browser", + dynamicTitle: true, + markup: status.components.bridgedWebView(url) + }; } -} - -status.command({ - name: "browse", - registeredOnly: true, - color: "#ffa500", - hidden: true, - fullscreen: true, - suggestionsTrigger: 'on-send', - params: [{ - name: "url", - suggestions: browseSuggestions, - type: status.types.TEXT - }] }); @@ -1885,7 +1862,7 @@ status.response({ I18n.t('confirm_validation_description') ); - return {errors: [error]} + return {markup: error}; } } }); @@ -1901,42 +1878,26 @@ status.response({ placeholder: I18n.t('password_placeholder'), hidden: true }, { - name: "password-confirmation", + name: "password_confirmation", type: status.types.PASSWORD, - placeholder: I18n.t('password_placeholder2'), + placeholder: "Confirm", hidden: true }], validator: function (params, context) { - var errorMessages = []; - var currentParameter = context["current-parameter"]; - - if ( - currentParameter == "password" && - params.password.length < 6 - ) { - errorMessages.push(I18n.t('password_error')); + if (params["password_confirmation"] != params["password"]) { + var error = status.components.validationMessage( + I18n.t('password_validation_title'), + I18n.t('password_error1') + ); + return {markup: error}; } - - if (currentParameter == "password-confirmation" && - params.password != params["password-confirmation"]) { - errorMessages.push(I18n.t('password_error1')); + if (params.password.length < 6) { + var error = status.components.validationMessage( + I18n.t('password_validation_title'), + I18n.t('password_error') + ); + return {markup: error}; } - - if (errorMessages.length) { - var errors = []; - for (var idx in errorMessages) { - errors.push( - status.components.validationMessage( - I18n.t('password_validation_title'), - errorMessages[idx] - ) - ); - } - - return {errors: errors}; - } - - return {params: params, context: context}; }, preview: function (params, context) { var style = { @@ -1953,14 +1914,14 @@ status.response({ style.letterSpacing = 1; } - return status.components.text({style: style}, "●●●●●●●●●●"); + return {markup: status.components.text({style: style}, "●●●●●●●●●●")}; } }); -status.registerFunction("message-suggestions", function(params, context) { +status.registerFunction("message-suggestions", function (params, context) { return jsSuggestions({code: params.message}, context); }); -status.registerFunction("message-handler", function(params, context) { +status.registerFunction("message-handler", function (params, context) { return jsHandler({code: params.message}, context); }); diff --git a/resources/dapp.js b/resources/dapp.js index 00cfb3e6c4..77cf15ccbe 100644 --- a/resources/dapp.js +++ b/resources/dapp.js @@ -1,8 +1,8 @@ I18n.translations = { - en: { - browse_title: 'Browser', - browse_description: 'Launch the browser' - } + en: { + browse_title: 'Browser', + browse_description: 'Open web browser' + } }; status.command({ @@ -11,22 +11,23 @@ status.command({ description: I18n.t('browse_description'), color: "#ffa500", fullscreen: true, - suggestionsTrigger: 'on-send', params: [{ name: "url", - suggestions: function(params, context) { - var url = "dapp-url"; - - if (params.url && params.url !== "undefined" && params.url != "") { - url = params.url; - if (!/^[a-zA-Z-_]+:/.test(url)) { - url = 'http://' + url; - } - } - return {webViewUrl: url}; - }, + optional: true, type: status.types.TEXT - }] + }], + onSend: function (params, context) { + var url = params.url || params.metadata.url; + if (!/^[a-zA-Z-_]+:/.test(url)) { + url = 'http://' + url; + } + + return { + title: params.metadata.name, + dynamicTitle: true, + markup: status.components.bridgedWebView(url) + }; + } }); status.autorun("browse"); diff --git a/resources/status.js b/resources/status.js index d3577321cf..00a04e61b8 100644 --- a/resources/status.js +++ b/resources/status.js @@ -33,7 +33,7 @@ Command.prototype.create = function (com) { this.params = com.params || []; this.preview = com.preview; this["short-preview"] = com.shortPreview; - this["suggestions-trigger"] = com.suggestionsTrigger || "on-change"; + this["on-send"] = com.onSend; this.fullscreen = com.fullscreen; this.request = com.request; this.addToCatalog(); @@ -124,33 +124,17 @@ function webView(url) { }]; } +function bridgedWebView(url) { + return ['bridged-web-view', { + url: url + }]; +} + function validationMessage(titleText, descriptionText) { - var titleStyle = { - style: { - color: "white", - fontSize: 12 - } - }; - var title = status.components.text(titleStyle, titleText); - - var descriptionStyle = { - style: { - color: "white", - fontSize: 12, - opacity: 0.9 - } - }; - var description = status.components.text(descriptionStyle, descriptionText); - - return status.components.view( - { - backgroundColor: "red", - height: 61, - paddingLeft: 16, - paddingTop: 14, - }, - [title, description] - ); + return ['validation-message', { + title: titleText, + description: descriptionText + }]; } var status = { @@ -180,7 +164,8 @@ var status = { PASSWORD: 'password' }, events: { - SET_VALUE: 'set-value' + SET_VALUE: 'set-value', + SET_COMMAND_ARGUMENT: 'set-command-argument' }, components: { view: view, @@ -189,7 +174,8 @@ var status = { touchable: touchable, scrollView: scrollView, webView: webView, - validationMessage: validationMessage + validationMessage: validationMessage, + bridgedWebView: bridgedWebView } }; diff --git a/resources/wallet.js b/resources/wallet.js index 169caaa36b..45f72bd4e5 100644 --- a/resources/wallet.js +++ b/resources/wallet.js @@ -1,32 +1,21 @@ -function wallet(params, context) { - var url = 'https://status.im/dapps/wallet'; - - if (context.debug) { - url = 'http://127.0.0.1:3450'; - } - - if (params.url && params.url !== "undefined" && params.url != "") { - url = params.url; - if (!/^[a-zA-Z-_]+:/.test(url)) { - url = 'http://' + url; - } - } - - return {webViewUrl: url}; -} - status.command({ name: "browse", title: I18n.t('browse_title'), description: I18n.t('browse_description'), color: "#ffa500", fullscreen: true, - suggestionsTrigger: 'on-send', - params: [{ - name: "url", - suggestions: wallet, - type: status.types.TEXT - }] + onSend: function (params, context) { + var url = 'https://status.im/dapps/wallet'; + if (context.debug) { + url = 'http://127.0.0.1:3450'; + } + + return { + title: "Wallet", + dynamicTitle: false, + markup: status.components.bridgedWebView(url) + }; + } }); status.autorun("browse"); diff --git a/src/status_im/android/platform.cljs b/src/status_im/android/platform.cljs index 0a60fb17fd..fb400a89d3 100644 --- a/src/status_im/android/platform.cljs +++ b/src/status_im/android/platform.cljs @@ -70,7 +70,8 @@ :default {:font-family "Roboto-Regular"} :medium {:font-family "Roboto-Medium"} - :toolbar-title {:font-family "Roboto-Regular"}}) + :toolbar-title {:font-family "Roboto-Regular"} + :roboto-mono {:font-family "RobotoMono-Medium"}}) ;; Dialogs diff --git a/src/status_im/chat/constants.cljs b/src/status_im/chat/constants.cljs index e1776682c7..50f91d4072 100644 --- a/src/status_im/chat/constants.cljs +++ b/src/status_im/chat/constants.cljs @@ -1,21 +1,13 @@ (ns status-im.chat.constants) (def command-char "/") +(def spacing-char " ") +(def arg-wrapping-char "\"") +(def masking-char "*") (def input-height 56) (def max-input-height 66) -(def min-input-height 22) (def input-spacing-top 16) -(def input-spacing-bottom 18) - -(def request-info-height 61) -(def response-height-normal 211) -(def minimum-suggestion-height (+ input-height request-info-height)) -(def suggestions-header-height 22) -(def minimum-command-suggestions-height - (+ input-height suggestions-header-height)) - -(def emoji-container-height 250) (def crazy-math-message-id "crazy-math-message") (def passphrase-message-id "passphraze-message") diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index b25189a8fc..dbfe174f88 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -4,7 +4,7 @@ [status-im.models.commands :as commands] [clojure.string :as string] [status-im.components.styles :refer [default-chat-color]] - [status-im.chat.suggestions :as suggestions] + [status-im.chat.models.suggestions :as suggestions] [status-im.chat.constants :as chat-consts] [status-im.protocol.core :as protocol] [status-im.data-store.chats :as chats] @@ -26,10 +26,10 @@ valid-mobile-number?]] [status-im.components.status :as status] [status-im.utils.types :refer [json->clj]] - status-im.chat.handlers.commands - [status-im.commands.utils :refer [command-prefix]] - [status-im.chat.utils :refer [console? not-console?]] + [status-im.chat.utils :refer [console? not-console? safe-trim]] [status-im.utils.gfycat.core :refer [generate-gfy]] + status-im.chat.handlers.input + status-im.chat.handlers.commands status-im.chat.handlers.animation status-im.chat.handlers.requests status-im.chat.handlers.unviewed-messages @@ -42,17 +42,19 @@ [taoensso.timbre :as log] [tailrecursion.priority-map :refer [priority-map-by]])) +(register-handler :set-layout-height + (fn [db [_ height]] + (assoc db :layout-height height))) + (register-handler :set-chat-ui-props - (fn [db [_ ui-element value]] - (assoc-in db [:chat-ui-props ui-element] value))) + (fn [{:keys [current-chat-id] :as db} [_ ui-element value chat-id]] + (let [chat-id (or chat-id current-chat-id)] + (assoc-in db [:chat-ui-props chat-id ui-element] value)))) (register-handler :toggle-chat-ui-props - (fn [{:keys [chat-ui-props] :as db} [_ ui-element]] - (assoc-in db [:chat-ui-props ui-element] (not (ui-element chat-ui-props))))) - -(register-handler :set-show-info - (fn [db [_ show-info]] - (assoc db :show-info show-info))) + (fn [{:keys [current-chat-id chat-ui-props] :as db} [_ ui-element chat-id]] + (let [chat-id (or chat-id current-chat-id)] + (update-in db [:chat-ui-props chat-id ui-element] not)))) (register-handler :show-message-details (u/side-effect! @@ -81,9 +83,20 @@ (assoc-in [:chats current-chat-id :all-loaded?] all-loaded?))))) db)))) -(defn safe-trim [s] - (when (string? s) - (string/trim s))) +(defn set-message-shown + [db chat-id message-id] + (update-in db + [:chats chat-id :messages] + (fn [messages] + (map (fn [message] + (if (= message-id (:message-id message)) + (assoc message :new? false) + message)) + messages)))) + +(register-handler :set-message-shown + (fn [db [_ {:keys [chat-id message-id]}]] + (set-message-shown db chat-id message-id))) (register-handler :cancel-command (fn [{:keys [current-chat-id] :as db} _] @@ -92,145 +105,6 @@ (assoc-in [:chats current-chat-id :command-input] {}) (update-in [:chats current-chat-id :input-text] safe-trim)))) -(register-handler :start-cancel-command - (after #(dispatch [:set-soft-input-mode :resize])) - (u/side-effect! - (fn [] - (dispatch [:animate-cancel-command]) - (dispatch [:cancel-command])))) - -(defn update-input-text - [{:keys [current-chat-id] :as db} text] - (assoc-in db [:chats current-chat-id :input-text] text)) - -(register-handler :set-message-input [] - (fn [db [_ input]] - (assoc db :message-input input))) - -(register-handler :blur-message-input - (u/side-effect! - (fn [db _] - (when-let [message-input (:message-input db)] - (.blur message-input))))) - -(defn update-text [db [_ chat-id text]] - (assoc-in db [:chats chat-id :input-text] text)) - -(defn update-command [db [_ text]] - (if-not (commands/get-chat-command db) - (let [{:keys [command]} (suggestions/check-suggestion db text)] - (if command - (commands/set-command-input db :commands command) - db)) - db)) - -(defn set-command-suggestions - [db [_ chat-id suggestions]] - (assoc-in db [:command-suggestions chat-id] suggestions)) - -(register-handler ::set-command-suggestions set-command-suggestions) - -(defn check-suggestions - [db [_ chat-id text]] - (let [suggestions (suggestions/get-suggestions db text) - {:keys [dapp?]} (get-in db [:contacts chat-id])] - (when (and dapp? (empty? suggestions)) - (if (seq text) - (dispatch [::check-dapp-suggestions chat-id text]) - (dispatch [:clear-response-suggestions chat-id]))) - (log/debug "Suggestions: " suggestions) - (assoc-in db [:command-suggestions chat-id] suggestions))) - -(defn select-suggestion! - [db [_ chat-id text]] - (let [suggestions (get-in db [:command-suggestions chat-id])] - (if (= 1 (count suggestions)) - (dispatch [:set-chat-command (ffirst suggestions)]) - (dispatch [::set-text chat-id text])))) - -(register-handler ::check-dapp-suggestions - (u/side-effect! - (fn [db [_ chat-id text]] - (let [data (get-in db [:local-storage chat-id]) - path [:functions - :message-suggestions] - params {:parameters {:message text} - :context {:data data}}] - (status/call-jail chat-id - path - params - (fn [{:keys [result] :as data}] - (let [{:keys [returned]} result] - (log/debug "Message suggestions: " returned) - (if returned - (dispatch [:suggestions-handler {:chat-id chat-id} data]) - (dispatch [:clear-response-suggestions chat-id]))))))))) - -(register-handler :set-chat-input-text - (u/side-effect! - (fn [{:keys [current-chat-id]} [_ text]] - ;; fixes https://github.com/status-im/status-react/issues/594 - ;; todo: revisit with more clever solution - (let [text' (if (= text (str chat-consts/command-char " ")) chat-consts/command-char text)] - (when (string/blank? text) - (dispatch [:set-in [:suggestions current-chat-id] nil])) - (if (console? current-chat-id) - (dispatch [::check-input-for-commands text']) - (dispatch [::check-suggestions current-chat-id text'])))))) - -(register-handler :add-to-chat-input-text - (u/side-effect! - (fn [{:keys [chats current-chat-id]} [_ text-to-add]] - (let [input-text (get-in chats [current-chat-id :input-text])] - (dispatch [:set-chat-input-text (str input-text text-to-add)]))))) - -(def possible-commands - {[:confirmation-code :responses] #(re-matches #"^[\d]{4}$" %) - [:phone :commands] valid-mobile-number?}) - -(defn check-text-for-commands [text] - (ffirst (filter (fn [[_ f]] (f text)) possible-commands))) - -(register-handler ::check-input-for-commands - (u/side-effect! - (fn [_ [_ text]] - (if-let [[_ type :as command] (check-text-for-commands text)] - (let [text' (if (= :commands type) - (str command-prefix text) - text)] - (dispatch [::set-command-with-content command text'])) - (dispatch [::check-suggestions console-chat-id text]))))) - -(register-handler ::set-command-with-content - (u/side-effect! - (fn [_ [_ [command type] text]] - (dispatch [:set-chat-command command type]) - (dispatch [:set-chat-command-content text])))) - -(register-handler :set-message-input-view-height - (fn [{:keys [current-chat-id] :as db} [_ height]] - (assoc-in db [:chats current-chat-id :message-input-height] height))) - -(register-handler ::check-suggestions - [(after select-suggestion!) - (after #(dispatch [:animate-command-suggestions]))] - check-suggestions) - -(register-handler ::set-text update-text) - -(defn set-message-shown - [db chat-id message-id] - (update-in db [:chats chat-id :messages] (fn [messages] - (map (fn [message] - (if (= message-id (:message-id message)) - (assoc message :new? false) - message)) - messages)))) - -(register-handler :set-message-shown - (fn [db [_ {:keys [chat-id message-id]}]] - (set-message-shown db chat-id message-id))) - (defn init-console-chat ([{:keys [chats current-account-id] :as db} existing-account?] (let [new-chat sign-up-service/console-chat] @@ -303,7 +177,7 @@ (doseq [{:keys [content] :as message} messages] (when (and (:command content) (not (:content content))) - (dispatch [:request-command-preview (assoc message :chat-id current-chat-id)]))) + (dispatch [:request-command-data (assoc message :chat-id current-chat-id)]))) (assoc db :messages messages)))) (defn init-chat @@ -359,15 +233,10 @@ (let [chat-id (or id current-chat-id) messages (get-in db [:chats chat-id :messages]) command? (= :command (get-in db [:edit-mode chat-id])) - db' (-> db - (assoc :current-chat-id chat-id) - (update-in [:animations :to-response-height chat-id] - #(if command? % 0))) + db' (assoc db :current-chat-id chat-id) commands-loaded? (if js/goog.DEBUG false (get-in db [:chats chat-id :commands-loaded]))] - (when (= current-chat-id wallet-chat-id) - (dispatch [:cancel-command])) (dispatch [:load-requests! chat-id]) ;; todo rewrite this. temporary fix for https://github.com/status-im/status-react/issues/607 #_(dispatch [:load-commands! chat-id]) @@ -472,26 +341,10 @@ (chats/save chat) (update-in db [:chats chat-id] merge chat)))) -(register-handler :switch-command-suggestions! - (u/side-effect! - (fn [db] - (let [text (if (suggestions/typing-command? db) "" chat-consts/command-char)] - (dispatch [:set-chat-input-text text]))))) - (defn remove-chat [db [_ chat-id]] (update db :chats dissoc chat-id)) -; todo do we really need this message? -(defn leaving-message! - [{:keys [current-chat-id]} _] - (messages/save - current-chat-id - {:from "system" - :message-id (random/id) - :content "You left this chat" - :content-type text-content-type})) - (defn delete-messages! [{:keys [current-chat-id]} [_ chat-id]] (let [id (or chat-id current-chat-id)] @@ -529,39 +382,10 @@ (register-handler :remove-chat (-> remove-chat - ;((after leaving-message!)) ((after delete-messages!)) ((after remove-pending-messages!)) ((after delete-chat!)))) -(defn edit-mode-handler [mode] - (fn [{:keys [current-chat-id] :as db} _] - (assoc-in db [:edit-mode current-chat-id] mode))) - -(register-handler :command-edit-mode - (after #(dispatch [:clear-validation-errors])) - (edit-mode-handler :command)) - -(register-handler :text-edit-mode - (after #(dispatch [:set-chat-input-text ""])) - (edit-mode-handler :text)) - -(register-handler :set-layout-height - [(after - (fn [{:keys [current-chat-id] :as db}] - (let [suggestions (get-in db [:has-suggestions? current-chat-id]) - mode (get-in db [:edit-mode current-chat-id])] - (when (and (= :command mode) suggestions) - (dispatch [:fix-response-height nil nil true]))))) - (after - (fn [{:keys [current-chat-id] :as db}] - (let [suggestions (get-in db [:command-suggestions current-chat-id]) - mode (get-in db [:edit-mode current-chat-id])] - (when (and (not= :command mode) (seq suggestions)) - (dispatch [:fix-commands-suggestions-height nil nil true])))))] - (fn [db [_ h]] - (assoc db :layout-height h))) - (defn send-seen! [{:keys [web3 current-public-key chats]} [_ {:keys [from chat-id message-id]}]] @@ -573,6 +397,7 @@ :to from :group-id (when group-chat chat-id) :message-id message-id}}))))) + (register-handler :send-seen! [(after (fn [_ [_ {:keys [message-id]}]] (messages/update {:message-id message-id @@ -613,34 +438,15 @@ (let [{:keys [clock-value]} (messages/get-by-id message-id)] (send-clock-value! db to message-id clock-value))))) -(register-handler :set-web-view-url - (fn [{:keys [current-chat-id] :as db} [_ url]] - (assoc-in db [:web-view-url current-chat-id] url))) - -(register-handler :set-web-view-extra-js - (fn [{:keys [current-chat-id] :as db} [_ extra-js]] - (assoc-in db [:web-view-extra-js current-chat-id] extra-js))) - -(register-handler :set-soft-input-mode - (after - (fn [{:keys [current-chat-id]} [_ mode chat-id]] - (when (or (nil? chat-id) (= current-chat-id chat-id)) - (status/set-soft-input-mode (if (= :pan mode) - status/adjust-pan - status/adjust-resize))))) - (fn [db [_ chat-id mode]] - (assoc-in db [:kb-mode chat-id] mode))) - (register-handler :check-autorun (u/side-effect! - (fn [{:keys [current-chat-id] :as db}] + (fn [{:keys [current-chat-id contacts] :as db}] (let [autorun (get-in db [:chats current-chat-id :autorun])] (when autorun (am/go - ;;todo: find another way to make it work... + (dispatch [:select-chat-input-command {:name autorun}]) (a/ db + (assoc-in [:chat-animations current-chat-id key :height] value) + (update-in [:chat-animations current-chat-id key :changes-counter] inc)))) -(defn animation-handler - ([name handler] (animation-handler name nil handler)) - ([name middleware handler] - (register-handler name [(path :animations) middleware] handler))) +(handlers/register-handler + :hide-expandable + (handlers/side-effect! + (fn [_ [_ key]] + (dispatch [:set-expandable-height key 1])))) -(register-handler :animate-cancel-command - (after #(dispatch [:text-edit-mode])) - (fn [{:keys [current-chat-id] :as db} _] - (assoc-in db [:animations :to-response-height current-chat-id] input-height))) +(handlers/register-handler + :choose-predefined-expandable-height + (handlers/side-effect! + (fn [{:keys [current-chat-id chat-ui-props layout-height] :as db} [_ key preset]] + (if (= preset :max) + (dispatch [:set-expandable-height key :max]) + (let [input-height (get-in chat-ui-props [current-chat-id :input-height]) + chat-input-margin (if platform/ios? + (get db :keyboard-height) + 0) + bottom (+ input-height chat-input-margin) + height (case preset + :min input-utils/min-height + (input-utils/default-container-area-height bottom layout-height))] + (dispatch [:set-expandable-height key height])))))) -(def response-height (+ input-height response-height-normal)) +(handlers/register-handler + :fix-expandable-height + (handlers/side-effect! + (fn [{:keys [current-chat-id chats chat-ui-props layout-height] :as db} [_ vy current key]] + (let [input-height (get-in chat-ui-props [current-chat-id :input-height]) + chat-input-margin (if platform/ios? + (get db :keyboard-height) + 0) + bottom (+ input-height chat-input-margin) -(register-handler :animate-command-suggestions - (fn [{chat-id :current-chat-id :as db} _] - (let [suggestions? (seq (get-in db [:command-suggestions chat-id])) - current (get-in db [:animations :command-suggestions-height chat-id]) - height (if suggestions? middle-height input-height) - changed? (if (and suggestions? - (not (nil? current)) - (not= input-height current)) - identity inc)] - (-> db - (assoc-in [:animations :command-suggestions-height chat-id] height) - (update-in [:animations :commands-height-changed] changed?))))) + min-height input-utils/min-height + max-height (input-utils/max-container-area-height bottom layout-height) + default-height (input-utils/default-container-area-height bottom layout-height) + possible-values [min-height default-height max-height] -(defn get-minimum-height - [{:keys [current-chat-id] :as db}] - (let [path [:chats current-chat-id :command-input :command :type] - type (get-in db path) - command? (= :command type) - response? (not command?) - errors (get-in db [:validation-errors current-chat-id]) - validation-errors? (seq errors) - suggestion? (get-in db [:has-suggestions? current-chat-id]) - custom-errors (get-in db [:custom-validation-errors current-chat-id]) - custom-errors? (seq custom-errors) - validation-errors? (or validation-errors? custom-errors?)] - (cond-> 0 - validation-errors? (+ request-info-height) - response? (+ minimum-suggestion-height) - command? (+ input-height) - (and suggestion? command?) (+ suggestions-header-height) - ;custom-errors? (+ suggestions-header-height) - (and command? validation-errors?) (+ suggestions-header-height)))) + moving-down? (pos? vy) + closest-index (->> possible-values + (map-indexed vector) + (sort-by (fn [[i v]] (Math/abs (- v current)))) + (ffirst)) + height (cond (and moving-down? (not= closest-index 0)) + (get possible-values (dec closest-index)) -(register-handler :animate-show-response - ;[(after #(dispatch [:command-edit-mode]))] - (fn [{:keys [current-chat-id] :as db}] - (let [suggestions? (get-in db [:has-suggestions? current-chat-id]) - fullscreen? (get-in db [:chats current-chat-id :command-input :command :fullscreen]) - max-height (get-in db [:layout-height]) - height (if suggestions? - (if fullscreen? - max-height - middle-height) - (get-minimum-height db))] - (assoc-in db [:animations :to-response-height current-chat-id] height)))) + (and (not moving-down?) (not= closest-index 2)) + (get possible-values (inc closest-index)) -(defn fix-height - [height-key height-signal-key suggestions-key minimum] - (fn [{:keys [current-chat-id] :as db} [_ vy current no-animation]] - (let [input-margin (subscribe [:input-margin]) - max-height (- (get-in db [:layout-height]) - (get-in platform-specific [:component-styles :status-bar :default :height]) - @input-margin) - moving-down? (pos? vy) - moving-up? (not moving-down?) - under-middle-position? (<= current middle-height) - over-middle-position? (not under-middle-position?) - suggestions (get-in db [suggestions-key current-chat-id]) - old-fixed (get-in db [:animations height-key current-chat-id]) + moving-down? + min-height - new-fixed (cond (not suggestions) - (minimum db) + (not moving-down?) + max-height)] + (dispatch [:set-expandable-height key height]))))) - (and (nil? vy) (nil? current) - (> old-fixed middle-height)) - max-height - - (and (nil? vy) (nil? current) - (< old-fixed middle-height)) - (minimum db) - - (and under-middle-position? moving-up?) - middle-height - - (and over-middle-position? moving-down?) - middle-height - - (and over-middle-position? moving-up?) - max-height - - (and under-middle-position? moving-down?) - (minimum db))] - (-> db - (assoc-in [:animations height-key current-chat-id] new-fixed) - (update-in [:animations height-signal-key] inc) - (assoc-in [:animate? current-chat-id] (not no-animation)))))) - -(defn commands-min-height - [{:keys [current-chat-id] :as db}] - (let [suggestions (get-in db [:command-suggestions current-chat-id])] - (if (seq suggestions) - minimum-command-suggestions-height - input-height))) - -(register-handler :fix-commands-suggestions-height - (fix-height :command-suggestions-height - :commands-height-changed - :command-suggestions - commands-min-height)) - -(register-handler :fix-response-height - (fix-height :to-response-height - :response-height-changed - :has-suggestions? - get-minimum-height)) diff --git a/src/status_im/chat/handlers/commands.cljs b/src/status_im/chat/handlers/commands.cljs index 83aecff7c9..f638d59c72 100644 --- a/src/status_im/chat/handlers/commands.cljs +++ b/src/status_im/chat/handlers/commands.cljs @@ -1,315 +1,36 @@ (ns status-im.chat.handlers.commands (:require [re-frame.core :refer [enrich after dispatch]] - [status-im.utils.handlers :refer [register-handler] :as u] - [status-im.components.react :as react-comp] + [status-im.utils.handlers :as handlers] [status-im.components.status :as status] - [status-im.models.commands :as commands] - [status-im.chat.utils :refer [console? not-console?]] - [clojure.string :as str] + [status-im.chat.constants :as const] [status-im.commands.utils :as cu] - [status-im.utils.phone-number :as pn] [status-im.i18n :as i18n] - [status-im.utils.datetime :as time] - [status-im.utils.random :as random] [status-im.utils.platform :as platform] [taoensso.timbre :as log])) -(defn content-by-command - [{:keys [type]} content] - (if (and (= :command type) content) - (subs content (count cu/command-prefix)) - content)) - -(defn command-dependent-context-params - [{:keys [name] :as command}] - (case name - "phone" {:suggestions (pn/get-examples)} - {})) - -(defn invoke-suggestions-handler! - [{:keys [current-chat-id canceled-command] :as db} _] - (when-not canceled-command - (let [{:keys [command content params]} (get-in db [:chats current-chat-id :command-input]) - data (get-in db [:local-storage current-chat-id]) - {:keys [name type]} command - path [(if (= :command type) :commands :responses) - name - :params - 0 - :suggestions] - params {:parameters (or params {}) - :context (merge {:data data} - (command-dependent-context-params command))}] - (status/call-jail current-chat-id - path - params - #(dispatch [:suggestions-handler {:command command - :content content - :chat-id current-chat-id} %]))))) - -(defn cancel-command! - [{:keys [canceled-command]}] - (when canceled-command - (dispatch [:start-cancel-command]))) - -(defn current-command - [{:keys [current-chat-id] :as db} k] - (get-in db [:chats current-chat-id :command-input :command k])) - -(register-handler :set-chat-command-content - [(after (fn [db] - (let [trigger (keyword (current-command db :suggestions-trigger))] - (when (= :on-change trigger) - (invoke-suggestions-handler! db nil))))) - (after cancel-command!) - (after #(dispatch [:clear-validation-errors]))] - (fn [{:keys [current-chat-id] :as db} [_ content]] - (let [starts-as-command? (str/starts-with? content cu/command-prefix) - command? (= :command (current-command db :type)) - {:keys [parameter-idx command]} (commands/get-command-input db) - parameter-name (-> command :params (get parameter-idx) :name)] - (as-> db db - (commands/set-chat-command-content db content) - (commands/set-command-parameter db parameter-name content) - (assoc-in db [:chats current-chat-id :input-text] nil) - (assoc db :canceled-command (and command? (not starts-as-command?))))))) - -(register-handler :fill-chat-command-content - (u/side-effect! - (fn [db [_ content]] - (let [command? (= :command (current-command db :type))] - (dispatch - [:set-chat-command-content - (if command? - (str cu/command-prefix content) - content)]))))) - -(defn command-input - ([{:keys [current-chat-id] :as db}] - (command-input db current-chat-id)) - ([db chat-id] - (get-in db [:chats chat-id :command-input]))) - -(register-handler ::validate! - (u/side-effect! - (fn [_ [_ command-input {:keys [chat-id handler]} {:keys [error result]}]] - ;; todo handle error - (when-not error - (let [{:keys [errors validationHandler parameters]} (:returned result)] - (cond errors - (do - (dispatch [:set-chat-ui-props :sending-disabled? false]) - (dispatch [::add-validation-errors chat-id errors])) - - validationHandler - (do - (dispatch [:set-chat-ui-props :sending-disabled? false]) - (dispatch [::validation-handler! - command-input - chat-id - validationHandler - parameters])) - - :else (if handler - (handler) - (dispatch [::finish-command-staging command-input chat-id])))))))) - -(register-handler :validate-command - (u/side-effect! - (fn [{:keys [current-chat-id current-account-id] :as db} [_ command-input command]] - (let [command-input (or command-input (commands/get-command-input db)) - command (or command (commands/get-chat-command db))] - (dispatch [::start-command-validation! {:command-input command-input - :command command - :chat-id current-chat-id - :address current-account-id}]))))) - -(register-handler ::finish-command-staging - [(after #(dispatch [:start-cancel-command]))] - (u/side-effect! - (fn [db [_ command-input chat-id :as parameters]] - (let [db (assoc-in db [:chats chat-id :input-text] nil) - {:keys [command to-message-id params]} (or command-input (command-input db)) - message-id (random/id) - command-info {:command command - :params params - :to-message to-message-id - :created-at (time/now-ms) - :id message-id - :chat-id chat-id} - request-data {:message-id message-id - :chat-id chat-id - :content {:command (:name command) - :params params - :type (:type command)} - :on-requested #(dispatch [:send-chat-message command-info])}] - (dispatch [:set-in [:command->chat (:id command-info)] chat-id]) - (dispatch [:request-command-preview request-data]))))) - -(defn set-chat-command - [{:keys [current-chat-id] :as db} [_ command-key type]] - (-> db - (commands/set-command-input (or type :commands) command-key) - (assoc-in [:chats current-chat-id :command-input :content] cu/command-prefix) - (assoc :disable-input true) - (assoc :just-set-command? true))) - -(register-handler :set-chat-command - [(after invoke-suggestions-handler!) - (after #(dispatch [:set-soft-input-mode :resize])) - (after #(dispatch [:command-edit-mode]))] - set-chat-command) - -(defn set-response-command [db [_ to-message-id command-key params]] - (-> db - (commands/set-command-input :responses to-message-id command-key params) - (assoc :canceled-command false))) - -(register-handler ::set-response-chat-command - [(after invoke-suggestions-handler!) - (after #(dispatch [:command-edit-mode])) - (after #(dispatch [:set-chat-input-text ""]))] - set-response-command) - -(register-handler :set-response-chat-command - (u/side-effect! - (fn [{:keys [current-chat-id] :as db} - [_ to-message-id command-key params]] - (when (get-in db [:chats current-chat-id :responses command-key]) - (dispatch [::set-response-chat-command to-message-id command-key params]))))) - -(register-handler ::add-validation-errors - (after #(dispatch [:fix-response-height])) - (fn [db [_ chat-id errors]] - (assoc-in db [:custom-validation-errors chat-id] - (map cu/generate-hiccup errors)))) - -(register-handler :clear-validation-errors - (fn [db] - (dissoc db :validation-errors :custom-validation-errors))) - -(defn dispatch-error! - [chat-id title description] - (letfn [(wrap-params [p] (if (seqable? p) p [p]))] - (dispatch [::set-validation-error - chat-id - {:title (apply i18n/label (wrap-params title)) - :description (apply i18n/label (wrap-params description))}]))) - -(def validation-handlers - {:phone (fn [command-input chat-id [number]] - (if (pn/valid-mobile-number? number) - (dispatch [::finish-command-staging command-input chat-id]) - (dispatch-error! chat-id :t/phone-number :t/invalid-phone)))}) - -(defn validator [name] - (validation-handlers (keyword name))) - -(register-handler ::validation-handler! - (u/side-effect! - (fn [_ [_ command-input chat-id name params]] - (when-let [handler (validator name)] - (handler command-input chat-id params))))) - -(register-handler ::set-validation-error - (after #(dispatch [:fix-response-height])) - (fn [db [_ chat-id error]] - (assoc-in db [:validation-errors chat-id] [error]))) - -(register-handler :invoke-commands-suggestions! - (u/side-effect! - invoke-suggestions-handler!)) - -(register-handler :send-command! - (u/side-effect! - (fn [{:keys [current-chat-id current-account-id] :as db}] - (let [{:keys [params] :as command} (commands/get-chat-command db) - {:keys [parameter-idx]} (commands/get-command-input db) - - last-parameter? (= (inc parameter-idx) (count params)) - - parameters {:command command :input command-input} - - {:keys [command content]} (command-input db) - content' (content-by-command command content)] - (dispatch [:set-command-parameter - {:value content' - :parameter (params parameter-idx)}]) - (if last-parameter? - (dispatch [:check-suggestions-trigger! parameters]) - (dispatch [::start-command-validation! - {:chat-id current-chat-id - :address current-account-id - :handler #(dispatch [:next-command-parameter])}])))))) - -(register-handler ::start-command-validation! - (u/side-effect! - (fn [db [_ {:keys [command-input chat-id address] :as data}]] - (let [command-input' (or command-input (commands/get-command-input db)) - {:keys [parameter-idx params command]} command-input' - {:keys [name type]} command - current-parameter (-> command - :params - (get parameter-idx) - :name) - to (get-in db [:contacts chat-id :address]) - context {:current-parameter current-parameter - :from address - :to to} - path [(if (= :command type) :commands :responses) - name - :validator] - parameters {:context context - :parameters params}] - (status/call-jail chat-id - path - parameters - #(dispatch [::validate! command-input data %])))))) - -(register-handler :request-command-preview - (u/side-effect! - (fn [{:keys [chats]} [_ {{:keys [command params content-command type]} :content - :keys [message-id chat-id on-requested] :as message} data-type]] +(handlers/register-handler :request-command-data + (handlers/side-effect! + (fn [{:keys [chats] :as db} + [_ {{:keys [command params content-command type]} :content + :keys [message-id chat-id address on-requested] :as message} data-type]] (if-not (get-in chats [chat-id :commands-loaded]) (do (dispatch [:add-commands-loading-callback chat-id - #(dispatch [:request-command-preview message data-type])]) + #(dispatch [:request-command-data message data-type])]) (dispatch [:load-commands! chat-id])) - (let [data-type (or data-type :preview) - path [(if (= :response (keyword type)) :responses :commands) - (if content-command content-command command) - data-type] - params {:parameters params - :context (merge {:platform platform/platform} i18n/delimeters)} - callback #(do (when-let [result (get-in % [:result :returned])] - (dispatch [:set-in [:message-data data-type message-id] - (if (string? result) - result - (cu/generate-hiccup result))])) - (when on-requested (on-requested %)))] + (let [path [(if (= :response (keyword type)) :responses :commands) + (if content-command content-command command) + data-type] + to (get-in db [:contacts chat-id :address]) + params {:parameters params + :context (merge {:platform platform/platform + :from address + :to to} + i18n/delimeters)} + callback #(let [result (get-in % [:result :returned]) + result (if (:markup result) + (update result :markup cu/generate-hiccup) + result)] + (dispatch [:set-in [:message-data data-type message-id] result]) + (when on-requested (on-requested result)))] (status/call-jail chat-id path params callback)))))) - -(register-handler :set-command-parameter - (fn [db [_ {:keys [value parameter]}]] - (let [name (:name parameter)] - (commands/set-command-parameter db name value)))) - -(register-handler :next-command-parameter - (fn [db _] - (commands/next-command-parameter db))) - -(register-handler :check-suggestions-trigger! - (u/side-effect! - (fn [_ [_ {:keys [command]}]] - (let [suggestions-trigger (keyword (:suggestions-trigger command))] - (if (= :on-send suggestions-trigger) - (do - (dispatch [:invoke-commands-suggestions!]) - (react-comp/dismiss-keyboard!)) - (do - (dispatch [:set-chat-ui-props :sending-disabled? true]) - (dispatch [:validate-command]))))))) - -(defn fib-lazy - ([] (fib-lazy 0 1)) - ([x1 x2] (cons x1 (lazy-seq (fib-lazy x2 (+ x1 x2)))))) diff --git a/src/status_im/chat/handlers/faucet.cljs b/src/status_im/chat/handlers/faucet.cljs index 8e36a1192e..ee1598b72d 100644 --- a/src/status_im/chat/handlers/faucet.cljs +++ b/src/status_im/chat/handlers/faucet.cljs @@ -41,17 +41,6 @@ #(received-message (label :t/faucet-success)) #(received-message (label :t/faucet-error))))) -(defmethod open-faucet :prefill - [faucet-name current-address {:keys [prefill-js]}] - (let [prefill-js (gstring/format prefill-js current-address) - web-view-js (gstring/format - "document.addEventListener('DOMContentLoaded', function(){ %s };" - prefill-js)] - (dispatch [:set-chat-command :browse]) - (dispatch [:fill-chat-command-content faucet-name]) - (dispatch [:set-web-view-extra-js web-view-js]) - (js/setTimeout #(dispatch [:send-command!]) 500))) - (register-handler :open-faucet (u/side-effect! diff --git a/src/status_im/chat/handlers/input.cljs b/src/status_im/chat/handlers/input.cljs new file mode 100644 index 0000000000..cd69500c54 --- /dev/null +++ b/src/status_im/chat/handlers/input.cljs @@ -0,0 +1,264 @@ +(ns status-im.chat.handlers.input + (:require [re-frame.core :refer [enrich after dispatch]] + [taoensso.timbre :as log] + [status-im.chat.constants :as const] + [status-im.chat.models.input :as input-model] + [status-im.chat.models.password-input :as password-input] + [status-im.chat.models.suggestions :as suggestions] + [status-im.components.react :as react-comp] + [status-im.components.status :as status] + [status-im.utils.datetime :as time] + [status-im.utils.handlers :as handlers] + [status-im.utils.random :as random] + [status-im.i18n :as i18n] + [clojure.string :as str])) + +(handlers/register-handler + :set-chat-input-text + (fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]] + (let [chat-id (or chat-id current-chat-id) + selection (get-in chat-ui-props [chat-id :selection])] + (dispatch [:update-suggestions chat-id text]) + + (if-let [{command :command} (input-model/selected-chat-command db chat-id text)] + (let [{old-args :args} (input-model/selected-chat-command db chat-id) + text-splitted (input-model/split-command-args text) + new-args (rest text-splitted) + modifiers (input-model/add-modifiers (:params command) new-args) + addition (if (input-model/text-ends-with-space? text) + const/spacing-char) + new-params {:modified-text (str (input-model/apply-modifiers text-splitted modifiers) + addition) + :input-text (str (input-model/make-input-text modifiers + text-splitted + old-args + selection) + addition)}] + (update-in db [:chats chat-id] merge new-params)) + (update-in db [:chats chat-id] merge {:input-text text + :modified-text nil}))))) + +(handlers/register-handler + :add-to-chat-input-text + (handlers/side-effect! + (fn [{:keys [chats current-chat-id]} [_ text-to-add]] + (let [input-text (get-in chats [current-chat-id :input-text])] + (dispatch [:set-chat-input-text (str input-text text-to-add)]))))) + +(handlers/register-handler + :select-chat-input-command + (handlers/side-effect! + (fn [{:keys [current-chat-id chat-ui-props] :as db} [_ {:keys [name prefill] :as command} metadata]] + (dispatch [:set-chat-input-text (str const/command-char + name + const/spacing-char + (input-model/join-command-args prefill))]) + (dispatch [:set-chat-input-metadata metadata]) + (dispatch [:set-chat-ui-props :show-suggestions? false]) + (dispatch [:set-chat-ui-props :result-box nil]) + (dispatch [:set-chat-ui-props :validation-messages nil]) + (dispatch [:load-chat-parameter-box command 0]) + (dispatch [:chat-input-focus])))) + +(handlers/register-handler + :set-chat-input-metadata + (fn [{:keys [current-chat-id] :as db} [_ data chat-id]] + (let [chat-id (or chat-id current-chat-id)] + (assoc-in db [:chats chat-id :input-metadata] data)))) + +(handlers/register-handler + :set-command-argument + (handlers/side-effect! + (fn [{:keys [current-chat-id] :as db} [_ [index arg]]] + (let [command (-> (get-in db [:chats current-chat-id :input-text]) + (input-model/split-command-args)) + command-name (first command) + command-args (into [] (rest command)) + command-args (if (< index (count command-args)) + (assoc command-args index arg) + (conj command-args arg))] + (dispatch [:set-chat-input-text (str command-name + const/spacing-char + (input-model/join-command-args command-args) + const/spacing-char)]))))) + +(handlers/register-handler + :chat-input-focus + (handlers/side-effect! + (fn [{:keys [current-chat-id chat-ui-props] :as db}] + (when-let [ref (get-in chat-ui-props [current-chat-id :input-ref])] + (.focus ref))))) + +(handlers/register-handler + :update-suggestions + (fn [{:keys [current-chat-id] :as db} [_ chat-id text]] + (let [chat-id (or chat-id current-chat-id) + chat-text (or text (get-in db [:chats chat-id :input-text]) "") + requests (suggestions/get-request-suggestions db chat-text) + suggestions (suggestions/get-command-suggestions db chat-text) + {:keys [dapp?]} (get-in db [:contacts chat-id])] + (when (and dapp? (empty? (into requests suggestions))) + (dispatch [::check-dapp-suggestions chat-id chat-text])) + (-> db + (assoc-in [:chats chat-id :request-suggestions] requests) + (assoc-in [:chats chat-id :command-suggestions] suggestions))))) + +(handlers/register-handler + :load-chat-parameter-box + (handlers/side-effect! + (fn [{:keys [current-chat-id] :as db} [_ {:keys [name type] :as command}]] + (let [parameter-index (input-model/argument-position db current-chat-id)] + (when (and command (> parameter-index -1)) + (let [data (get-in db [:local-storage current-chat-id]) + path [(if (= :command type) :commands :responses) + name + :params + parameter-index + :suggestions] + args (-> (get-in db [:chats current-chat-id :input-text]) + (input-model/split-command-args) + (rest)) + params {:parameters {:args args} + :context (merge {:data data} + (input-model/command-dependent-context-params command))}] + (status/call-jail current-chat-id + path + params + #(dispatch [:suggestions-handler + {:chat-id current-chat-id + :command command + :parameter-index parameter-index + :result %}])))))))) + +(handlers/register-handler + ::send-message + (handlers/side-effect! + (fn [{:keys [current-public-key current-account-id] :as db} [_ command-message chat-id]] + (let [text (get-in db [:chats chat-id :input-text]) + data {:message text + :command command-message + :chat-id chat-id + :identity current-public-key + :address current-account-id}] + (dispatch [:set-chat-input-text nil chat-id]) + (dispatch [:set-chat-input-metadata nil chat-id]) + (cond + command-message + (dispatch [:check-commands-handlers! data]) + (not (str/blank? text)) + (dispatch [:prepare-message data])))))) + +(handlers/register-handler + ::proceed-command + (handlers/side-effect! + (fn [db [_ command chat-id]] + (dispatch [::request-command-data + {:command command + :chat-id chat-id + :data-type :validator + :after #(dispatch [::proceed-validation-messages command chat-id %2])}])))) + +(handlers/register-handler + ::proceed-validation-messages + (handlers/side-effect! + (fn [db [_ command chat-id {:keys [markup validationHandler parameters] :as errors}]] + (let [set-errors #(do (dispatch [:set-chat-ui-props :validation-messages %]) + (dispatch [:set-chat-ui-props :sending-in-progress? false])) + proceed #(dispatch [::request-command-data + {:command command + :chat-id chat-id + :data-type :on-send + :after (fn [_ res] + (dispatch [::send-command res command chat-id]))}])] + (cond + markup + (set-errors markup) + + validationHandler + (do (dispatch [::execute-validation-handler validationHandler parameters set-errors proceed]) + (dispatch [:set-chat-ui-props :sending-in-progress? false])) + + :default + (proceed)))))) + +(handlers/register-handler + ::execute-validation-handler + (handlers/side-effect! + (fn [_ [_ name params set-errors proceed]] + (when-let [validator (input-model/validation-handler name)] + (validator params set-errors proceed))))) + +(handlers/register-handler + ::send-command + (handlers/side-effect! + (fn [db [_ on-send {{:keys [fullscreen]} :command :as command} chat-id]] + (if on-send + (do + (when fullscreen + (dispatch [:choose-predefined-expandable-height :result-box :max])) + (dispatch [:set-chat-ui-props :result-box on-send]) + (dispatch [:set-chat-ui-props :sending-in-progress? false]) + (react-comp/dismiss-keyboard!)) + (dispatch [::request-command-data + {:command command + :chat-id chat-id + :data-type :preview + :after #(dispatch [::send-message % chat-id])}]))))) + +(handlers/register-handler + ::request-command-data + (handlers/side-effect! + (fn [{:keys [contacts] :as db} + [_ {{:keys [command metadata args] :as c} :command + :keys [message-id chat-id data-type after]}]] + (let [{:keys [dapp? dapp-url name]} (get contacts chat-id) + message-id (random/id) + metadata (merge metadata + (when dapp? + {:url (i18n/get-contact-translated chat-id :dapp-url dapp-url) + :name (i18n/get-contact-translated chat-id :name name)})) + params (input-model/args->params c) + command-message {:command command + :params params + :to-message (:to-message-id metadata) + :created-at (time/now-ms) + :id message-id + :chat-id chat-id} + request-data {:message-id message-id + :chat-id chat-id + :content {:command (:name command) + :params (assoc params :metadata metadata) + :type (:type command)} + :on-requested #(after command-message %)}] + (dispatch [:request-command-data request-data data-type]))))) + +(handlers/register-handler + :send-current-message + (handlers/side-effect! + (fn [{:keys [current-chat-id] :as db} [_ chat-id]] + (let [chat-id (or chat-id current-chat-id) + chat-command (input-model/selected-chat-command db chat-id)] + (if chat-command + (if (= :complete (input-model/command-completion chat-command)) + (dispatch [::proceed-command chat-command chat-id]) + (let [text (get-in db [:chats chat-id :input-text])] + (dispatch [:set-chat-ui-props :sending-in-progress? false]) + (when-not (input-model/text-ends-with-space? text) + (dispatch [:set-chat-input-text (str text const/spacing-char)])))) + (dispatch [::send-message nil chat-id])))))) + +(handlers/register-handler + ::check-dapp-suggestions + (handlers/side-effect! + (fn [db [_ chat-id text]] + (let [data (get-in db [:local-storage chat-id]) + path [:functions + :message-suggestions] + params {:parameters {:message text} + :context {:data data}}] + (status/call-jail chat-id + path + params + (fn [{:keys [result] :as data}] + (dispatch [:suggestions-handler {:chat-id chat-id + :result data}]))))))) \ No newline at end of file diff --git a/src/status_im/chat/handlers/receive_message.cljs b/src/status_im/chat/handlers/receive_message.cljs index a29623e644..45dbb32b46 100644 --- a/src/status_im/chat/handlers/receive_message.cljs +++ b/src/status_im/chat/handlers/receive_message.cljs @@ -50,7 +50,7 @@ (dispatch [:upsert-chat! {:chat-id chat-id' :group-chat group-chat?}]) (when (get-in message [:content :command]) - (dispatch [:request-command-preview message])) + (dispatch [:request-command-data message :preview])) (dispatch [::add-message chat-id' message']) (dispatch [::set-last-message message']) (when (= (:content-type message') content-type-command-request) @@ -93,7 +93,7 @@ (register-handler ::set-last-message (fn [{:keys [chats] :as db} [_ {:keys [chat-id] :as message}]] - (dispatch [:request-command-preview message :short-preview]) + (dispatch [:request-command-data message :short-preview]) (assoc-in db [:chats chat-id :last-message] message))) (defn commands-loaded? [db chat-id] diff --git a/src/status_im/chat/handlers/send_message.cljs b/src/status_im/chat/handlers/send_message.cljs index 0cb5d94d53..5217f7e9ae 100644 --- a/src/status_im/chat/handlers/send_message.cljs +++ b/src/status_im/chat/handlers/send_message.cljs @@ -43,54 +43,26 @@ :clock-value (inc clock-value) :show? true})) -(register-handler :send-chat-message - (u/side-effect! - (fn [{:keys [current-chat-id current-public-key current-account-id] :as db} - [_ {:keys [chat-id] :as command-message}]] - (let [text (get-in db [:chats current-chat-id :input-text]) - data {:command command-message - :message text - :chat-id (or chat-id current-chat-id) - :identity current-public-key - :address current-account-id}] - (dispatch [:clear-input current-chat-id]) - (cond - command-message - (dispatch [::check-commands-handlers! data]) - (not (s/blank? text)) - (dispatch [::prepare-message data])))))) - (defn console-command? [chat-id command-name] (and (= console-chat-id chat-id) (console/commands-names (keyword command-name)))) -(register-handler ::check-commands-handlers! +(register-handler :check-commands-handlers! (u/side-effect! (fn [_ [_ {:keys [command message chat-id] :as params}]] (let [{:keys [command] :as message} command] (let [params' (assoc params :command-message message) command-name (:name (:command message))] - (if (:sent-to-jail? message) - ;; todo there could be other reasons for "long-running" - ;; hanling of the command besides sendTransaction - (dispatch [:navigate-to-modal :pending-transactions]) - (cond - (console-command? chat-id command-name) - (dispatch [:invoke-console-command-handler! params']) + (cond + (console-command? chat-id command-name) + (dispatch [:invoke-console-command-handler! params']) - (:has-handler command) - (dispatch [::invoke-command-handlers! params']) + (:has-handler command) + (dispatch [::invoke-command-handlers! params']) - :else - (dispatch [:prepare-command! chat-id params']))))) - (dispatch [:set-chat-ui-props :sending-disabled? false]) - (when-not (s/blank? message) - (dispatch [::prepare-message params]))))) - -(register-handler :clear-input - (path :chats) - (fn [db [_ chat-id]] - (assoc-in db [chat-id :input-text] nil))) + :else + (dispatch [:prepare-command! chat-id params'])))) + (dispatch [:set-chat-ui-props :sending-in-progress? false])))) (register-handler :prepare-command! (u/side-effect! @@ -106,10 +78,10 @@ (cu/check-author-direction db chat-id))] (log/debug "Handler data: " request handler-data (dissoc params :commands :command-message)) (dispatch [:update-message-overhead! chat-id network-status]) - (dispatch [:set-chat-ui-props :sending-disabled? false]) + (dispatch [:set-chat-ui-props :sending-in-progress? false]) (dispatch [::send-command! add-to-chat-id (assoc params :command command') hidden-params]) (when (cu/console? chat-id) - (dispatch `[:console-respond-command params])) + (dispatch [:console-respond-command params])) (when (and (= "send" (get-in command-message [:command :name])) (not= add-to-chat-id wallet-chat-id)) (let [ct (if request @@ -168,9 +140,10 @@ chat-id path params - #(dispatch [:command-handler! chat-id parameters %])))))) + (fn [result] + (dispatch [:command-handler! chat-id parameters result]))))))) -(register-handler ::prepare-message +(register-handler :prepare-message (u/side-effect! (fn [{:keys [network-status] :as db} [_ {:keys [chat-id identity message] :as params}]] (let [{:keys [group-chat public?]} (get-in db [:chats chat-id]) @@ -195,7 +168,7 @@ (assoc :to chat-id :message-type :user-message)) params' (assoc params :message message'')] (dispatch [:update-message-overhead! chat-id network-status]) - (dispatch [:set-chat-ui-props :sending-disabled? false]) + (dispatch [:set-chat-ui-props :sending-in-progress? false]) (dispatch [::add-message params']) (dispatch [::save-message! params']))))) @@ -212,13 +185,6 @@ :timestamp (time/now-ms)}]) (messages/save chat-id message)))) -(register-handler :clear-response-suggestions - (fn [db [_ chat-id]] - (-> db - (update-in [:suggestions] dissoc chat-id) - (update-in [:has-suggestions?] dissoc chat-id) - (assoc-in [:animations :to-response-height chat-id] input-height)))) - (register-handler ::send-dapp-message (u/side-effect! (fn [db [_ chat-id {:keys [content]}]] @@ -227,7 +193,6 @@ :message-handler] params {:parameters {:message content} :context {:data data}}] - (dispatch [:clear-response-suggestions chat-id]) (status/call-jail chat-id path params diff --git a/src/status_im/chat/handlers/webview_bridge.cljs b/src/status_im/chat/handlers/webview_bridge.cljs index a26726a1b2..690f0eec24 100644 --- a/src/status_im/chat/handlers/webview_bridge.cljs +++ b/src/status_im/chat/handlers/webview_bridge.cljs @@ -57,23 +57,10 @@ :amount? true}])) (dispatch [:chat-with-command whisper-identity action params])))) -(register-handler ::send-command - (u/side-effect! - (fn [db [_ command-key params]] - (let [command (commands/get-response-or-command :commands db command-key) - command-input {:content (str cu/command-prefix "0") - :command command - :parameter-idx 0 - :params {"amount" (:amount params)} - :to-message-id nil}] - (dispatch [:validate-command command-input command]))))) - (defn chat-with-command [_ [_ whisper-identity command-key params]] (dispatch [:remove-contacts-click-handler]) - (dispatch [:add-chat-loaded-callback whisper-identity - #(dispatch [::send-command command-key params])]) (dispatch [:start-chat whisper-identity])) (register-handler :chat-with-command diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs new file mode 100644 index 0000000000..a9132ae16c --- /dev/null +++ b/src/status_im/chat/models/input.cljs @@ -0,0 +1,190 @@ +(ns status-im.chat.models.input + (:require [clojure.string :as str] + [status-im.components.react :as rc] + [status-im.chat.constants :as const] + [status-im.chat.models.password-input :as password-input] + [status-im.chat.views.input.validation-messages :refer [validation-message]] + [status-im.i18n :as i18n] + [status-im.utils.phone-number :as phone-number] + [taoensso.timbre :as log])) + +(defn text-ends-with-space? [text] + (= (str/last-index-of text const/spacing-char) + (dec (count text)))) + +(defn possible-chat-actions [db chat-id] + (let [{:keys [commands requests]} (get-in db [:chats chat-id]) + commands (mapv (fn [[_ command]] + (vector command :any)) + commands) + responses (mapv (fn [{:keys [message-id type]}] + (vector + (get-in db [:chats chat-id :responses type]) + message-id)) + requests)] + (into commands responses))) + +(defn split-command-args [command-text] + (let [splitted (str/split command-text const/spacing-char)] + (first + (reduce (fn [[list command-started?] arg] + (let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg)) + has-quote? (and (= quotes-count 1) + (str/index-of arg const/arg-wrapping-char)) + arg (str/replace arg #"\"" "") + new-list (if command-started? + (let [index (dec (count list))] + (update list index str const/spacing-char arg)) + (conj list arg)) + command-continues? (or (and command-started? (not has-quote?)) + (and (not command-started?) has-quote?))] + [new-list command-continues?])) + [[] false] + splitted)))) + +(defn join-command-args [args] + (->> args + (map (fn [arg] + (if (not (str/index-of arg const/spacing-char)) + arg + (str const/arg-wrapping-char arg const/arg-wrapping-char)))) + (str/join const/spacing-char))) + +(defn selected-chat-command + ([{:keys [current-chat-id] :as db} chat-id input-text] + (let [chat-id (or chat-id current-chat-id) + input-metadata (get-in db [:chats chat-id :input-metadata]) + possible-actions (possible-chat-actions db chat-id) + command-args (split-command-args input-text) + command-name (first command-args)] + (when (.startsWith (or command-name "") const/command-char) + (when-let [command (-> (filter (fn [[{:keys [name]} message-id]] + (and (= name (subs command-name 1)) + (= message-id (or (:to-message-id input-metadata) + :any)))) + possible-actions) + (ffirst))] + {:command command + :metadata input-metadata + :args (remove empty? (rest command-args))})))) + ([{:keys [current-chat-id] :as db} chat-id] + (selected-chat-command db chat-id (get-in db [:chats chat-id :input-text])))) + +(defn current-chat-argument-position + [{:keys [args] :as command} input-text] + (if command + (let [current (count args)] + (if (= (last input-text) const/spacing-char) + current + (dec current))) + -1)) + +(defn argument-position [{:keys [current-chat-id] :as db} chat-id] + (let [chat-id (or chat-id current-chat-id) + input-text (get-in db [:chats chat-id :input-text]) + chat-command (selected-chat-command db chat-id)] + (current-chat-argument-position chat-command input-text))) + +(defn command-completion + ([{:keys [current-chat-id] :as db} chat-id] + (let [chat-id (or chat-id current-chat-id) + input-text (get-in db [:chats chat-id :input-text]) + chat-command (selected-chat-command db chat-id)] + (command-completion chat-command))) + ([{:keys [args] :as chat-command}] + (let [params (get-in chat-command [:command :params]) + required-params (remove :optional params)] + (if chat-command + (cond + (or (= (count args) (count params)) + (= (count args) (count required-params))) + :complete + + (< (count args) (count required-params)) + :less-than-needed + + (> (count args) (count params)) + :more-than-needed + + :default + :no-command) + :no-command)))) + +(defn args->params [{:keys [command args]}] + (let [params (:params command)] + (->> args + (map-indexed (fn [i value] + (vector (get-in params [i :name]) value))) + (into {})))) + +(defn command-dependent-context-params + [{:keys [name] :as command}] + (case name + "phone" {:suggestions (phone-number/get-examples)} + {})) + +(defmulti validation-handler (fn [name] (keyword name))) + +(defmethod validation-handler :phone + [_] + (fn [[number] set-errors proceed] + (if (phone-number/valid-mobile-number? number) + (proceed) + (set-errors [validation-message + {:title (i18n/label :t/phone-number) + :description (i18n/label :t/invalid-phone)}])))) + +(def text-modifiers + [password-input/modifier]) + +(defn add-modifiers [params new-args] + (->> new-args + (map-indexed (fn [i arg] + {:position i + :value arg + :modifier (-> (filter + (fn [mod] + ((:execute-when mod) (get params i))) + text-modifiers) + (first))})) + (into []))) + +(defn apply-modifiers [text-splitted args] + (if-let [{:keys [position modifier]} (first args)] + (if modifier + (let [{:keys [get-modified-text]} modifier + modified-text (get-modified-text text-splitted position)] + (apply-modifiers modified-text (rest args))) + (apply-modifiers text-splitted (rest args))) + (str/join const/spacing-char text-splitted))) + +(defn- changed-arg-position [xs ys] + (let [longest (into [] (max-key count xs ys)) + shortest (into [] (if (= longest xs) ys xs))] + (->> longest + (map-indexed (fn [index x] + (if (and (> (count shortest) index) + (= (count x) (count (get shortest index)))) + nil + index))) + (remove nil?) + (first)))) + +(defn make-input-text [modifiers [command & args] old-args selection] + (let [arg-pos (changed-arg-position args old-args) + modifier (get-in modifiers [arg-pos :modifier]) + new-arg (if (and arg-pos modifier) + (let [{:keys [make-change]} modifier] + (make-change {:command-name (subs command 1) + :old-args old-args + :new-args args + :arg-pos arg-pos + :selection selection})) + (get (into [] args) arg-pos)) + new-args (if arg-pos + (assoc (into [] old-args) arg-pos (when new-arg (str/trim new-arg))) + old-args)] + (str + command + const/spacing-char + (str/join const/spacing-char new-args)))) \ No newline at end of file diff --git a/src/status_im/chat/models/password_input.cljs b/src/status_im/chat/models/password_input.cljs new file mode 100644 index 0000000000..d094d64dd5 --- /dev/null +++ b/src/status_im/chat/models/password_input.cljs @@ -0,0 +1,48 @@ +(ns status-im.chat.models.password-input + (:require [status-im.chat.constants :as const] + [clojure.string :as str] + [taoensso.timbre :as log])) + +(defn- get-modified-text [text arg-pos] + (let [hide-fn #(apply str (repeat (count %) const/masking-char)) + updated-text (update text (inc arg-pos) hide-fn)] + updated-text)) + +(defn- get-change [{:keys [command-name old-args new-args arg-pos selection]}] + (let [old-args (into [] old-args) + new-args (into [] new-args) + modification (- (count (get new-args arg-pos)) + (count (get old-args arg-pos))) + type (if (> modification 0) :added :removed) + position (-> (:start selection) + (- (inc (count command-name))) + (- (count (str/join const/spacing-char (take arg-pos old-args)))) + (- modification) + (- (if (= arg-pos 0) 0 1))) + position (if (= :added type) position (inc position)) + symbols-count (.abs js/Math modification)] + {:type type + :position position + :symbols (when (= :added type) + (subs (get new-args arg-pos) + position + (+ position symbols-count)))})) + +(defn- make-change [{:keys [command-name old-args new-args arg-pos selection] :as args}] + (let [{:keys [type position symbols] :as c} (get-change args) + make-change #(if (= type :added) + (str (if % (subs % 0 position) "") + symbols + (if % (subs % position) "")) + (str (if % (subs % 0 position) "") + (if % (subs % (+ 1 position (count symbols))) ""))) + args (if (= (count old-args) 0) + [const/spacing-char] + (into [] old-args)) + updated-args (update args arg-pos make-change)] + (make-change (get args arg-pos)))) + +(def modifier + {:execute-when :hidden + :make-change make-change + :get-modified-text get-modified-text}) \ No newline at end of file diff --git a/src/status_im/chat/models/suggestions.cljs b/src/status_im/chat/models/suggestions.cljs new file mode 100644 index 0000000000..556ef6cf9a --- /dev/null +++ b/src/status_im/chat/models/suggestions.cljs @@ -0,0 +1,32 @@ +(ns status-im.chat.models.suggestions + (:require [status-im.chat.constants :as chat-consts] + [clojure.string :as str])) + +(defn suggestion? [text] + (= (get text 0) chat-consts/command-char)) + +(defn can-be-suggested? [text] + (fn [{:keys [name]}] + (let [text' (cond + (.startsWith text chat-consts/command-char) + text + + (str/blank? text) + chat-consts/command-char + + :default + nil)] + (.startsWith (str chat-consts/command-char name) text')))) + +(defn get-request-suggestions + [{:keys [current-chat-id] :as db} text] + (let [requests (get-in db [:chats current-chat-id :requests])] + (->> requests + (map (fn [{:keys [type] :as v}] + (assoc v :name (get-in db [:chats current-chat-id :responses type :name])))) + (filter (fn [v] ((can-be-suggested? text) v)))))) + +(defn get-command-suggestions + [{:keys [current-chat-id] :as db} text] + (let [commands (get-in db [:chats current-chat-id :commands])] + (filter (fn [[_ v]] ((can-be-suggested? text) v)) commands))) \ No newline at end of file diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index d3f27a0c17..773b85c079 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -19,21 +19,19 @@ [status-im.utils.platform :refer [platform-specific]] [status-im.components.invertible-scroll-view :refer [invertible-scroll-view]] [status-im.components.toolbar.view :refer [toolbar]] - [status-im.chat.views.message :refer [chat-message]] - [status-im.chat.views.datemark :refer [chat-datemark]] - [status-im.chat.views.response :refer [response-view]] - [status-im.chat.views.new-message :refer [chat-message-input-view]] - [status-im.chat.views.actions :refer [actions-view]] - [status-im.chat.views.emoji :refer [emoji-view]] - [status-im.chat.views.bottom-info :refer [bottom-info-view]] [status-im.chat.views.toolbar-content :refer [toolbar-content-view]] - [status-im.chat.views.suggestions :refer [suggestion-container]] + [status-im.chat.views.message.message :refer [chat-message]] + [status-im.chat.views.message.datemark :refer [chat-datemark]] + [status-im.chat.views.input.input :as input] + [status-im.chat.views.actions :refer [actions-view]] + [status-im.chat.views.bottom-info :refer [bottom-info-view]] [status-im.chat.constants :as const] [status-im.i18n :refer [label label-pluralize]] [status-im.components.animation :as anim] [status-im.components.sync-state.offline :refer [offline-view]] [status-im.constants :refer [content-type-status]] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [clojure.string :as str])) (defn contacts-by-identity [contacts] (->> contacts @@ -171,48 +169,23 @@ :keyboardShouldPersistTaps true :dataSource (to-datasource-inverted messages)}])) -(defn messages-container-animation-logic - [{:keys [offset val]}] - (fn [_] - (anim/start (anim/spring val {:toValue @offset})))) - -(defview messages-container [messages] - [offset [:messages-offset] - messages-offset (anim/create-value 0) - context {:offset offset - :val messages-offset} - on-update (messages-container-animation-logic context)] - {:component-did-mount on-update - :component-did-update on-update} - [animated-view - {:style (st/messages-container messages-offset)} - messages]) - (defview chat [] [group-chat [:chat :group-chat] show-actions? [:chat-ui-props :show-actions?] show-bottom-info? [:chat-ui-props :show-bottom-info?] show-emoji? [:chat-ui-props :show-emoji?] - command? [:command?] - layout-height [:get :layout-height]] + layout-height [:get :layout-height] + input-text [:chat :input-text]] {:component-did-mount #(dispatch [:check-autorun]) :component-will-unmount #(dispatch [:set-chat-ui-props :show-emoji? false])} - [view {:style st/chat-view - :onLayout (fn [event] - (let [height (.. event -nativeEvent -layout -height)] - (when (not= height layout-height) - (dispatch [:set-layout-height height]))))} + [view {:style st/chat-view + :on-layout (fn [event] + (let [height (.. event -nativeEvent -layout -height)] + (when (not= height layout-height) + (dispatch [:set-layout-height height]))))} [chat-toolbar] - [messages-container - [messages-view group-chat]] - ;; todo uncomment this - #_(when @group-chat [typing-all]) - (when-not command? - [suggestion-container]) - [response-view] - (when show-emoji? - [emoji-view]) - [chat-message-input-view] + [messages-view group-chat] + [input/container {:text-empty? (str/blank? input-text)}] (when show-actions? [actions-view]) (when show-bottom-info? diff --git a/src/status_im/chat/styles/animations.cljs b/src/status_im/chat/styles/animations.cljs new file mode 100644 index 0000000000..152a38466c --- /dev/null +++ b/src/status_im/chat/styles/animations.cljs @@ -0,0 +1,28 @@ +(ns status-im.chat.styles.animations + (:require [status-im.components.styles :as common])) + +(def color-root-border "rgba(192, 198, 202, 0.28)") +(def header-draggable-icon "rgba(73, 84, 93, 0.23)") + +(defn expandable-container [anim-value bottom] + {:background-color common/color-white + :border-top-color color-root-border + :border-top-width 1 + :elevation 2 + :height anim-value + :left 0 + :right 0 + :bottom bottom + :position :absolute}) + +(def header-container + {:height 17 + :background-color common/color-white + :alignItems :center + :justifyContent :center}) + +(def header-icon + {:background-color header-draggable-icon + :width 24 + :border-radius 1.5 + :height 3}) \ No newline at end of file diff --git a/src/status_im/chat/styles/command_validation.cljs b/src/status_im/chat/styles/command_validation.cljs deleted file mode 100644 index 15b4cf1dfb..0000000000 --- a/src/status_im/chat/styles/command_validation.cljs +++ /dev/null @@ -1,16 +0,0 @@ -(ns status-im.chat.styles.command-validation - (:require [status-im.chat.constants :as constants])) - -(def messages-container - {:background-color :#d50000 - :height constants/request-info-height - :padding-left 16 - :padding-top 12}) - -(def title - {:color :white - :font-size 14}) - -(def description - (assoc title :opacity 0.9 - :font-size 12)) diff --git a/src/status_im/chat/styles/content_suggestions.cljs b/src/status_im/chat/styles/content_suggestions.cljs deleted file mode 100644 index 0ac59e30ed..0000000000 --- a/src/status_im/chat/styles/content_suggestions.cljs +++ /dev/null @@ -1,37 +0,0 @@ -(ns status-im.chat.styles.content-suggestions - (:require [status-im.components.styles :refer [color-white - separator-color - text1-color - text2-color]])) - -(def suggestion-height 56) - -(def suggestion-container - {:paddingLeft 16 - :backgroundColor color-white}) - -(def suggestion-sub-container - {:height suggestion-height - :borderBottomWidth 1 - :borderBottomColor separator-color}) - -(def value-text - {:marginTop 9 - :fontSize 14 - :color text1-color}) - -(def description-text - {:marginTop 1.5 - :fontSize 14 - :color text2-color}) - -(defn suggestions-container [suggestions-count] - {:flex 1 - :marginVertical 1 - :marginHorizontal 0 - :height (min 150 (* suggestion-height suggestions-count)) - :backgroundColor color-white - :borderRadius 5}) - -(def container - {:backgroundColor color-white}) diff --git a/src/status_im/chat/styles/dragdown.cljs b/src/status_im/chat/styles/dragdown.cljs deleted file mode 100644 index d4d974ac21..0000000000 --- a/src/status_im/chat/styles/dragdown.cljs +++ /dev/null @@ -1,12 +0,0 @@ -(ns status-im.chat.styles.dragdown - (:require [status-im.components.styles :refer [color-white]])) - -(def drag-down-touchable - {:height 22 - :background-color color-white - :alignItems :center - :justifyContent :center}) - -(def drag-down-icon - {:width 16 - :height 16}) diff --git a/src/status_im/chat/styles/emoji.cljs b/src/status_im/chat/styles/emoji.cljs deleted file mode 100644 index 7c7d55c0ad..0000000000 --- a/src/status_im/chat/styles/emoji.cljs +++ /dev/null @@ -1,22 +0,0 @@ -(ns status-im.chat.styles.emoji - (:require [status-im.components.styles :refer [color-white]] - [status-im.chat.constants :refer [emoji-container-height]])) - -(def container-height emoji-container-height) - -(defn container [height] - {:flexDirection :column - :position :absolute - :left 0 - :right 0 - :bottom 0 - :height (or height emoji-container-height) - :backgroundColor color-white - :elevation 5}) - -(def emoji-container - {:flex 1}) - -(def emoji-picker - {:flex 1 - :background-color color-white}) diff --git a/src/status_im/chat/styles/input.cljs b/src/status_im/chat/styles/input.cljs deleted file mode 100644 index 5db5d1b335..0000000000 --- a/src/status_im/chat/styles/input.cljs +++ /dev/null @@ -1,69 +0,0 @@ -(ns status-im.chat.styles.input - (:require [status-im.components.styles :refer [color-white - color-blue - text1-color]])) - -(def command-input-and-suggestions-container - {:flexDirection :column}) - -(def command-input-container - {:flexDirection :row - :height 56 - :backgroundColor color-white}) - -(def command-container - {:left 0 - :backgroundColor :white - :position :absolute}) - -(defn command-text-container - [{:keys [color]}] - {:flexDirection :column - :marginTop 16 - :marginBottom 16 - :marginLeft 16 - :marginRight 8 - :backgroundColor color - :height 24 - :borderRadius 50}) - -(def command-text - {:marginTop 3 - :marginHorizontal 12 - :fontSize 12 - :color color-white}) - -(def command-input - {:flex 1 - :marginLeft 8 - :marginTop -2 - :padding 0 - :fontSize 14 - :color text1-color}) - -(def send-container - {:marginTop 10 - :marginRight 10 - :width 36 - :height 36 - :borderRadius 50 - :backgroundColor color-blue}) - -(def send-icon - {:marginTop 10.5 - :marginLeft 12 - :width 15 - :height 15}) - -(def cancel-container - {:marginTop 10 - :marginRight 10 - :width 36 - :height 36}) - -(def cancel-icon - {:marginTop 10.5 - :marginLeft 12 - :width 12 - :height 12}) - diff --git a/src/status_im/chat/styles/input/emoji.cljs b/src/status_im/chat/styles/input/emoji.cljs new file mode 100644 index 0000000000..724fd4f717 --- /dev/null +++ b/src/status_im/chat/styles/input/emoji.cljs @@ -0,0 +1,16 @@ +(ns status-im.chat.styles.input.emoji + (:require [status-im.components.styles :as common])) + +(def container-height 250) + +(defn container [height] + {:flex-direction :column + :height (or height container-height) + :background-color common/color-white}) + +(def emoji-container + {:flex 1}) + +(def emoji-picker + {:flex 1 + :background-color common/color-white}) diff --git a/src/status_im/chat/styles/input/input.cljs b/src/status_im/chat/styles/input/input.cljs new file mode 100644 index 0000000000..d30b8be928 --- /dev/null +++ b/src/status_im/chat/styles/input/input.cljs @@ -0,0 +1,132 @@ +(ns status-im.chat.styles.input.input + (:require-macros [status-im.utils.styles :refer [defnstyle]]) + (:require [status-im.components.styles :as common] + [status-im.utils.platform :as platform])) + +(def color-root-border "rgba(192, 198, 202, 0.28)") +(def color-root-border-android "#e8eaeb") +(def color-input "#edf1f3") +(def color-input-helper-text "rgb(182, 189, 194)") +(def color-input-helper-placeholder "rgb(182, 189, 194)") +(def color-command "#70777d") +(def color-send "rgb(98, 143, 227)") + +(def max-input-height 66) +(def min-input-height 38) +(def input-spacing-top 5) +(def input-spacing-bottom 8) + +(defnstyle root [margin-bottom] + {:flex-direction :column + :elevation 2 + :margin-bottom margin-bottom + :border-top-width 1 + :ios {:border-top-color color-root-border} + :android {:border-top-color color-root-border-android}}) + +(defn container [container-anim-margin bottom-anim-margin] + {:background-color common/color-white + :flex-direction :column + :padding-left container-anim-margin + :padding-right container-anim-margin + :padding-top 8 + :padding-bottom bottom-anim-margin}) + +(def input-container + {:flex-direction :row + :align-items :flex-end}) + +(defnstyle input-root [content-height anim-margin] + {:align-items :flex-start + :background-color color-input + :flex-direction :row + :flex-grow 1 + :height (+ (min (max min-input-height content-height) max-input-height) 0) + :margin-top anim-margin + :padding-left 10 + :padding-right 10 + :android {:border-radius 4} + :ios {:border-radius 8}}) + +(defnstyle input-view [content-height] + {:flex 1 + :font-size 14 + :padding-top input-spacing-top + :padding-bottom input-spacing-bottom + :line-height 20 + :android {:min-height content-height}}) + +(def invisible-input-text + {:font-size 14 + :position :absolute + :left 0 + :background-color :transparent + :color :transparent}) + +(defnstyle input-helper-text [left] + {:color color-input-helper-text + :font-size 14 + :position :absolute + :text-align-vertical :center + :height min-input-height + :align-items :center + :android {:left (+ 18 left) + :top -1} + :ios {:line-height min-input-height + :left (+ 15 left)}}) + +(def input-emoji-icon + {:margin-top 7 + :height 24 + :width 24}) + +(def input-clear-container + {:width 24 + :height 24 + :margin-top 7 + :align-items :center}) + +(def input-clear-icon + {:width 24 + :height 24 + :margin-top 0}) + +(def commands-root + {:flex-direction :row + :align-items :center}) + +(def command-list-icon-container + {:width 32 + :height 32 + :padding 4}) + +(def commands-list-icon + {:height 24 + :width 24}) + +(def close-commands-list-icon + {:height 24 + :width 24}) + +(def send-message-container + {:background-color color-send + :width 38 + :height 38 + :border-radius 19 + :padding 7 + :margin-left 8}) + +(def send-message-icon + {:height 24 + :width 24}) + +(def commands + {:flex-direction :row + :margin-right 16}) + +(defn command [first?] + {:color color-command + :font-size 14 + :margin-left (if first? 10 16) + :padding-top 8 + :padding-bottom 8}) diff --git a/src/status_im/chat/styles/input/result_box.cljs b/src/status_im/chat/styles/input/result_box.cljs new file mode 100644 index 0000000000..99c1d6143d --- /dev/null +++ b/src/status_im/chat/styles/input/result_box.cljs @@ -0,0 +1,45 @@ +(ns status-im.chat.styles.input.result-box + (:require [status-im.components.styles :as common])) + +(def color-root-border "rgba(192, 198, 202, 0.5)") + +(defn root [height bottom] + {:background-color common/color-white + :border-top-color color-root-border + :border-top-width 1 + :flex-direction :column + :height height + :left 0 + :right 0 + :elevation 2 + :bottom bottom + :position :absolute}) + +(def header-container + {:background-color common/color-white + :alignItems :center + :justifyContent :center + :height 35}) + +(def header-title-container + {:margin-bottom 15 + :flex-direction :row}) + +(def header-title-text + {:color common/color-black + :flex 1 + :font-size 15 + :text-align :center + :padding-top 1 + :margin-left 72 + :margin-right 32}) + +(def header-close-container + {:width 24 + :height 24 + :margin-right 16 + :top -3}) + +(def header-close-icon + {:width 24 + :height 24}) diff --git a/src/status_im/chat/styles/input/suggestions.cljs b/src/status_im/chat/styles/input/suggestions.cljs new file mode 100644 index 0000000000..f67618e490 --- /dev/null +++ b/src/status_im/chat/styles/input/suggestions.cljs @@ -0,0 +1,45 @@ +(ns status-im.chat.styles.input.suggestions + (:require-macros [status-im.utils.styles :refer [defnstyle]]) + (:require [status-im.components.styles :as common])) + +(def color-item-title-text "rgb(147, 155, 161)") +(def color-item-suggestion-name "rgb(98, 143, 227)") +(def color-item-border "#e8eaeb") + +(defn item-title-container [top-padding?] + {:margin-left 16 + :align-items :center + :flex-direction :row + :height 44}) + +(def item-title-text + {:font-size 14 + :color color-item-title-text}) + +(defnstyle item-suggestion-container [last?] + {:flex-direction :row + :align-items :center + :height 56 + :margin-left 16 + :ios {:border-bottom-color color-item-border + :border-bottom-width (if last? 0 1)}}) + +(def item-suggestion-name + {:background-color color-item-suggestion-name + :height 28 + :flex-direction :row + :align-items :center + :border-radius 4 + :padding-left 7 + :padding-right 7}) + +(def item-suggestion-name-text + {:color common/color-white + :font-size 14}) + +(def item-suggestion-description + {:flex 1 + :font-size 14 + :margin-left 16 + :margin-right 16 + :color color-item-title-text}) \ No newline at end of file diff --git a/src/status_im/chat/styles/input/validation_message.cljs b/src/status_im/chat/styles/input/validation_message.cljs new file mode 100644 index 0000000000..5125912e05 --- /dev/null +++ b/src/status_im/chat/styles/input/validation_message.cljs @@ -0,0 +1,23 @@ +(ns status-im.chat.styles.input.validation-message + (:require [status-im.chat.constants :as constants] + [status-im.components.styles :as common])) + +(defn root [bottom] + {:flex-direction :column + :left 0 + :right 0 + :bottom bottom + :position :absolute}) + +(def message-container + {:background-color common/color-red + :padding 16}) + +(def message-title + {:color common/color-white + :font-size 12}) + +(def message-description + {:color common/color-white + :font-size 12 + :opacity 0.9}) \ No newline at end of file diff --git a/src/status_im/chat/styles/command_pill.cljs b/src/status_im/chat/styles/message/command_pill.cljs similarity index 89% rename from src/status_im/chat/styles/command_pill.cljs rename to src/status_im/chat/styles/message/command_pill.cljs index 5d6b0e9163..5043ee1323 100644 --- a/src/status_im/chat/styles/command_pill.cljs +++ b/src/status_im/chat/styles/message/command_pill.cljs @@ -1,4 +1,4 @@ -(ns status-im.chat.styles.command-pill +(ns status-im.chat.styles.message.command-pill (:require [status-im.utils.platform :as p] [status-im.components.styles :refer [color-white]])) diff --git a/src/status_im/chat/styles/datemark.cljs b/src/status_im/chat/styles/message/datemark.cljs similarity index 59% rename from src/status_im/chat/styles/datemark.cljs rename to src/status_im/chat/styles/message/datemark.cljs index eb892ea66f..cc2aabfb15 100644 --- a/src/status_im/chat/styles/datemark.cljs +++ b/src/status_im/chat/styles/message/datemark.cljs @@ -1,5 +1,5 @@ -(ns status-im.chat.styles.datemark - (:require [status-im.components.styles :as st])) +(ns status-im.chat.styles.message.datemark + (:require [status-im.components.styles :as common])) (def datemark-wrapper {:flex 1 @@ -11,5 +11,5 @@ :height 20}) (def datemark-text - {:color st/color-gray4 + {:color common/color-gray4 :font-size 15}) diff --git a/src/status_im/chat/styles/message.cljs b/src/status_im/chat/styles/message/message.cljs similarity index 99% rename from src/status_im/chat/styles/message.cljs rename to src/status_im/chat/styles/message/message.cljs index b322f187a9..227680d0ab 100644 --- a/src/status_im/chat/styles/message.cljs +++ b/src/status_im/chat/styles/message/message.cljs @@ -1,4 +1,4 @@ -(ns status-im.chat.styles.message +(ns status-im.chat.styles.message.message (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) (:require [status-im.components.styles :refer [color-white color-black diff --git a/src/status_im/chat/styles/message_input.cljs b/src/status_im/chat/styles/message_input.cljs deleted file mode 100644 index de79cacc34..0000000000 --- a/src/status_im/chat/styles/message_input.cljs +++ /dev/null @@ -1,48 +0,0 @@ -(ns status-im.chat.styles.message-input - (:require [status-im.components.styles :refer [color-white - color-blue]] - [status-im.chat.constants :refer [max-input-height - min-input-height - input-spacing-top - input-spacing-bottom]])) - -(def input-container - {:flex-direction :column}) - -(defn input-view [content-height] - {:flex-direction :row - :align-items :center - :justify-content :center - :height (+ (min (max min-input-height content-height) max-input-height) - input-spacing-top - input-spacing-bottom) - :background-color color-white}) - -(defn message-input-container [content-height] - {:height (min (max min-input-height content-height) max-input-height) - :margin-top input-spacing-top - :margin-bottom input-spacing-bottom - :flex 1 - :flex-direction "column" - :margin-right 0}) - -(def send-wrapper - {:margin-top 10 - :margin-right 10 - :width 36 - :flex 1 - :flex-direction "column" - :align-items :center - :justify-content :flex-start}) - -(def send-container - {:width 36 - :height 36 - :border-radius 18 - :background-color color-blue}) - -(def send-icon - {:margin-top 10.5 - :margin-left 12 - :width 15 - :height 15}) diff --git a/src/status_im/chat/styles/plain_message.cljs b/src/status_im/chat/styles/plain_message.cljs deleted file mode 100644 index abf2642a5f..0000000000 --- a/src/status_im/chat/styles/plain_message.cljs +++ /dev/null @@ -1,58 +0,0 @@ -(ns status-im.chat.styles.plain-message - (:require [status-im.components.styles :refer [text1-color - color-blue]] - [status-im.chat.constants :refer [max-input-height - min-input-height]])) - -(defn message-input-button-touchable [width] - {:width width - :flex 1}) - -(defn message-input-button [scale margin-top] - {:transform [{:scale scale}] - :width 24 - :height 24 - :margin-top margin-top - :margin-left 16 - :align-items :center - :justify-content :center}) - -(def list-icon - {:margin-left 4 - :margin-top 5.5 - :margin-bottom 5.5 - :margin-right 4 - :width 16 - :height 13}) - -(def requests-icon-container - {:width 12 - :height 12 - :border-radius 12 - :left -1 - :top -1 - :background-color :white - :position :absolute}) - -(def requests-icon - {:background-color color-blue - :margin 2 - :width 8 - :height 8 - :border-radius 8}) - -(def close-icon - {:width 12 - :height 12}) - -(def message-input - {:flex 1 - :padding 0 - :font-size 14 - :line-height 20 - :color text1-color - :padding-top 0}) - -(def smile-icon - {:width 20 - :height 20}) diff --git a/src/status_im/chat/styles/response.cljs b/src/status_im/chat/styles/response.cljs deleted file mode 100644 index 1e23a8e040..0000000000 --- a/src/status_im/chat/styles/response.cljs +++ /dev/null @@ -1,87 +0,0 @@ -(ns status-im.chat.styles.response - (:require [status-im.components.styles :refer [color-white - text1-color]] - [status-im.chat.constants :refer [input-height - request-info-height - response-height-normal]])) - -(def drag-container - {:height 16 - :alignItems :center - :justifyContent :center}) - -(def drag-icon - {:width 14 - :height 3}) - -(def command-icon-container - {:marginTop 1 - :marginLeft 12 - :width 32 - :height 32 - :alignItems :center - :justifyContent :center - :borderRadius 16 - :backgroundColor color-white}) - -(defn command-icon [color] - {:width 13 - :height 13 - :tint-color color}) - -(def info-container - {:flex 1 - :marginLeft 12}) - -(def command-name - {:marginTop 0 - :fontSize 12 - :color color-white}) - -(def message-info - {:marginTop 1 - :fontSize 12 - :opacity 0.69 - :color color-white}) - -(defn response-view [height input-margin] - {:flexDirection :column - :position :absolute - :elevation 4 - :left 0 - :right 0 - :bottom input-margin - :height height - :backgroundColor color-white}) - -(def input-placeholder - {:height input-height}) - -(defn request-info [color] - {:flexDirection :column - :height request-info-height - :backgroundColor color}) - -(def inner-container - {:flexDirection :row - :height 45}) - -(def cancel-container - {:marginTop 2.5 - :marginRight 16 - :width 24 - :height 24}) - -(def cancel-icon - {:marginTop 6 - :marginLeft 6 - :width 12 - :height 12}) - -(defn command-input [ml disable?] - {:flex 1 - :margin-right 16 - :margin-left (- ml 5) - :padding 0 - :font-size 14 - :color (if disable? color-white text1-color)}) diff --git a/src/status_im/chat/styles/screen.cljs b/src/status_im/chat/styles/screen.cljs index b5528dfc32..b8b761581b 100644 --- a/src/status_im/chat/styles/screen.cljs +++ b/src/status_im/chat/styles/screen.cljs @@ -16,9 +16,9 @@ (def toolbar-container {}) -(defn messages-container [bottom] +(def messages-container {:flex 1 - :padding-bottom bottom + :padding-bottom 0 :margin-bottom 0}) (def toolbar-view diff --git a/src/status_im/chat/styles/suggestions.cljs b/src/status_im/chat/styles/suggestions.cljs deleted file mode 100644 index e35294a599..0000000000 --- a/src/status_im/chat/styles/suggestions.cljs +++ /dev/null @@ -1,112 +0,0 @@ -(ns status-im.chat.styles.suggestions - (:require [status-im.components.styles :refer [color-white - color-black - color-gray - separator-color - text1-color - text2-color]])) - -(def suggestion-height 60) - -(def suggestion-highlight - {:margin-left 57}) - -(def suggestion-container - {:backgroundColor color-white}) - -(def suggestion-sub-container - {:height suggestion-height - :borderBottomWidth 1 - :borderBottomColor separator-color - :flex-direction :row}) - -(def command-description-container - {:flex 0.6}) - -(def command-label-container - {:flex 0.4 - :flex-direction :column - :align-items :flex-end - :margin-right 16}) - -(defn suggestion-background - [{:keys [color]}] - {:marginTop 10 - :height 24 - :backgroundColor color - :borderRadius 50}) - -(def suggestion-text - {:marginTop 2.5 - :marginHorizontal 12 - :fontSize 12 - :color color-white}) - -(def title-container - {:margin-left 57 - :margin-bottom 16}) - -(def title-text - {:font-size 13 - :color :#8f838c93}) - -(def value-text - {:marginTop 6 - :fontSize 14 - :color text1-color}) - -(def description-text - {:marginTop 2 - :fontSize 12 - :color text2-color}) - -(defn container [height input-margin] - {:flexDirection :column - :position :absolute - :left 0 - :right 0 - :bottom input-margin - :height height - :backgroundColor color-white - :elevation 4}) - -(def request-container - {:height 56 - :flex-direction :row}) - -(def request-icon-container - {:height 56 - :width 57 - :align-items :center - :justifyContent :center}) - -(defn request-icon-background [color] - {:height 32 - :width 32 - :border-radius 32 - :background-color color - :align-items :center - :justifyContent :center}) - -(def request-icon - {:width 12 - :height 12}) - -(def request-info-container - {:height 56 - :padding-top 10}) - -(def request-info-description - {:font-size 12 - :color color-black}) - -(def request-message-info - {:font-size 12 - :margin-top 2 - :color color-gray}) - -(def header-icon - {:background-color :#838c93 - :width 14 - :border-radius 1 - :height 3}) diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index 41cca401ff..ecb45c287d 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -1,18 +1,21 @@ (ns status-im.chat.subs (:require-macros [reagent.ratom :refer [reaction]]) (:require [re-frame.core :refer [register-sub dispatch subscribe path]] - [status-im.models.commands :as commands] [status-im.data-store.chats :as chats] - [status-im.constants :refer [response-suggesstion-resize-duration]] - [status-im.chat.constants :as c] - [status-im.chat.views.plain-message :as plain-message] - [status-im.chat.views.command :as command] - [status-im.constants :refer [content-type-status + [status-im.chat.constants :as const] + [status-im.chat.models.input :as input-model] + [status-im.chat.utils :as chat-utils] + [status-im.chat.views.input.utils :as input-utils] + [status-im.constants :refer [response-suggesstion-resize-duration + content-type-status console-chat-id]] + [status-im.models.commands :as commands] [status-im.utils.platform :refer [platform-specific ios?]] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [clojure.string :as str])) -(register-sub :chat-properties +(register-sub + :chat-properties (fn [db [_ properties]] (->> properties (map (fn [k] @@ -21,90 +24,114 @@ (reaction))])) (into {})))) + (register-sub :chat-ui-props - (fn [db [_ ui-element]] - (reaction (get-in @db [:chat-ui-props ui-element])))) + (fn [db [_ ui-element chat-id]] + (let [chat-id (or chat-id (:current-chat-id @db))] + (reaction (get-in @db [:chat-ui-props chat-id ui-element]))))) -(register-sub :chat - (fn [db [_ k]] +(register-sub + :chat-input-margin + (fn [] + (let [kb-height (subscribe [:get :keyboard-height])] + (reaction + (if ios? @kb-height 0))))) + +(register-sub + :chat + (fn [db [_ k chat-id]] (-> @db - (get-in [:chats (:current-chat-id @db) k]) + (get-in [:chats (or chat-id (:current-chat-id @db)) k]) (reaction)))) -(register-sub :get-current-chat-id +(register-sub + :get-current-chat-id (fn [db _] (reaction (:current-chat-id @db)))) -(register-sub :get-suggestions - (fn [db _] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction (get-in @db [:command-suggestions @chat-id]))))) +(register-sub + :get-chat-by-id + (fn [_ [_ chat-id]] + (reaction (chats/get-by-id chat-id)))) -(register-sub :get-commands +(register-sub + :get-commands (fn [db [_ chat-id]] (let [current-chat (or chat-id (@db :current-chat-id))] (reaction (or (get-in @db [:chats current-chat :commands]) {}))))) -(register-sub :get-chat-by-id - (fn [_ [_ chat-id]] - (reaction (chats/get-by-id chat-id)))) - -(register-sub :get-responses +(register-sub + :get-responses (fn [db [_ chat-id]] (let [current-chat (or chat-id (@db :current-chat-id))] (reaction (or (get-in @db [:chats current-chat :responses]) {}))))) -(register-sub :get-commands-and-responses +(register-sub + :possible-chat-actions (fn [db [_ chat-id]] - (reaction (->> (get-in @db [:chats chat-id]) - ((juxt :commands :responses)) - (apply merge))))) - -(register-sub :get-chat-input-text - (fn [db _] - (->> [:chats (:current-chat-id @db) :input-text] - (get-in @db) - (reaction)))) - -(register-sub :get-message-input-view-height - (fn [db _] - (reaction (get-in @db [:chats (:current-chat-id @db) :message-input-height])))) - -(register-sub :valid-plain-message? - (fn [_ _] - (let [input-message (subscribe [:get-chat-input-text])] + "Returns a vector of [command message-id] values. `message-id` can be `:any`. + Example: [[browse-command :any] [debug-command :any] [phone-command '1489161286111-58a2cd...']]" + (let [chat-id (or chat-id (@db :current-chat-id))] (reaction - (plain-message/message-valid? @input-message))))) + (input-model/possible-chat-actions @db chat-id))))) -(register-sub :valid-command? - (fn [_ [_ validator]] - (let [input (subscribe [:get-chat-command-content])] - (reaction (command/valid? @input validator))))) - -(register-sub :get-chat-command - (fn [db _] - (reaction (commands/get-chat-command @db)))) - -(register-sub :get-command-parameter - (fn [db] - (let [command (subscribe [:get-chat-command]) - chat-id (subscribe [:get-current-chat-id])] +(register-sub + :selected-chat-command + (fn [db [_ chat-id]] + (let [chat-id (or chat-id (@db :current-chat-id)) + input-text (subscribe [:chat :input-text chat-id])] (reaction - (let [parameter-index (commands/get-command-parameter-index @db @chat-id)] - (when parameter-index (nth (:params @command) parameter-index))))))) + (input-model/selected-chat-command @db chat-id @input-text))))) -(register-sub :get-chat-command-content - (fn [db _] - (reaction (commands/get-chat-command-content @db)))) +(register-sub + :current-chat-argument-position + (fn [db [_ chat-id]] + (let [chat-id (or chat-id (@db :current-chat-id)) + command (subscribe [:selected-chat-command chat-id]) + input-text (subscribe [:chat :input-text chat-id])] + (reaction + (input-model/current-chat-argument-position @command @input-text))))) -(register-sub :get-chat-command-to-message-id - (fn [db _] - (reaction (commands/get-chat-command-to-message-id @db)))) +(register-sub + :chat-parameter-box + (fn [db [_ chat-id]] + (let [chat-id (or chat-id (@db :current-chat-id)) + command (subscribe [:selected-chat-command chat-id]) + index (subscribe [:current-chat-argument-position chat-id])] + (reaction + (cond + (and @command (> @index -1)) + (let [command-name (get-in @command [:command :name])] + (get-in @db [:chats chat-id :parameter-boxes command-name @index])) -(register-sub :chat-command-request - (fn [db _] - (reaction (commands/get-chat-command-request @db)))) + (not @command) + (get-in @db [:chats chat-id :parameter-boxes :message]) + + :default + nil))))) + +(register-sub + :command-completion + (fn [db [_ chat-id]] + (reaction + (input-model/command-completion @db chat-id)))) + +(register-sub + :show-suggestions? + (fn [db [_ chat-id]] + (let [chat-id (or chat-id (@db :current-chat-id)) + show-suggestions? (subscribe [:chat-ui-props :show-suggestions? chat-id]) + input-text (subscribe [:chat :input-text chat-id]) + selected-command (subscribe [:selected-chat-command chat-id]) + requests (subscribe [:chat :request-suggestions chat-id]) + commands (subscribe [:chat :command-suggestions chat-id])] + (reaction + (and (or @show-suggestions? + (.startsWith (or @input-text "") const/command-char)) + (not (:command @selected-command)) + (or (not-empty @requests) + (not-empty @commands))))))) (register-sub :get-current-chat (fn [db _] @@ -115,66 +142,6 @@ (fn [db [_ chat-id]] (reaction (get-in @db [:chats chat-id])))) -(register-sub :get-content-suggestions - (fn [db _] - (reaction (get-in @db [:suggestions (:current-chat-id @db)])))) - -(register-sub :command? - (fn [db] - (->> (get-in @db [:edit-mode (:current-chat-id @db)]) - (= :command) - (reaction)))) - -(register-sub :command-type - (fn [] - (let [command (subscribe [:get-chat-command])] - (reaction (:type @command))))) - -(register-sub :messages-offset - (fn [] - (let [command? (subscribe [:command?]) - type (subscribe [:command-type]) - command-suggestions (subscribe [:get-content-suggestions])] - (reaction - (cond (and @command? (= @type :response)) - c/request-info-height - - (and @command? (= @type :command) (seq @command-suggestions)) - c/suggestions-header-height - - :else 0))))) - -(register-sub :command-icon-width - (fn [] - (let [width (subscribe [:get :command-icon-width]) - type (subscribe [:command-type])] - (reaction (if (= :command @type) - @width - 0))))) - -(register-sub :get-requests - (fn [db] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction (get-in @db [:chats @chat-id :requests]))))) - -(register-sub :get-requests-map - (fn [db] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction (->> (get-in @db [:chats @chat-id :requests]) - (map #(vector (:message-id %) %)) - (into {})))))) - -(register-sub :get-request - (fn [_ [_ message-id]] - (let [requests (subscribe [:get-requests-map])] - (reaction (get @requests message-id))))) - -(register-sub :get-current-request - (fn [] - (let [requests (subscribe [:get-requests-map]) - message-id (subscribe [:get-chat-command-to-message-id])] - (reaction (@requests @message-id))))) - (register-sub :get-response (fn [db [_ n]] (let [chat-id (subscribe [:get-current-chat-id])] @@ -182,77 +149,18 @@ (register-sub :is-request-answered? (fn [_ [_ message-id]] - (let [requests (subscribe [:get-requests])] + (let [requests (subscribe [:chat :requests])] (reaction (not-any? #(= message-id (:message-id %)) @requests))))) -(register-sub :validation-errors - (fn [db] - (let [current-chat-id (subscribe [:get-current-chat-id])] - (reaction (get-in @db [:validation-errors @current-chat-id]))))) - -(register-sub :custom-validation-errors - (fn [db] - (let [current-chat-id (subscribe [:get-current-chat-id])] - (reaction (get-in @db [:custom-validation-errors @current-chat-id]))))) - (register-sub :unviewed-messages-count (fn [db [_ chat-id]] (reaction (get-in @db [:unviewed-messages chat-id :count])))) -(register-sub :command-suggestions-height - (fn [db] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction - (get-in @db [:animations :command-suggestions-height @chat-id]))))) - -(register-sub :response-height - (fn [db [_ status-bar]] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction - (min (get-in @db [:animations :to-response-height @chat-id]) - (if (pos? (:layout-height @db)) - (- (:layout-height @db) - (get-in platform-specific [:component-styles :status-bar status-bar :height])) - 0)))))) - -(register-sub :web-view-url - (fn [db] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction (get-in @db [:web-view-url @chat-id]))))) - (register-sub :web-view-extra-js (fn [db] (let [chat-id (subscribe [:get-current-chat-id])] (reaction (get-in @db [:web-view-extra-js @chat-id]))))) -(register-sub :animate? - (fn [db] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction (get-in @db [:animate? @chat-id]))))) - -(register-sub :kb-mode - (fn [db] - (let [chat-id (subscribe [:get-current-chat-id])] - (reaction (get-in @db [:kb-mode @chat-id]))))) - -(register-sub :input-margin - (fn [] - (let [kb-height (subscribe [:get :keyboard-height]) - kb-max (subscribe [:get :keyboard-max-height]) - show-emoji? (subscribe [:chat-ui-props :show-emoji?])] - (reaction - (cond @show-emoji? (or @kb-max c/emoji-container-height) - ios? @kb-height - :else 0))))) - -(register-sub :max-layout-height - (fn [_ [_ status-bar]] - (let [layout-height (subscribe [:get :layout-height]) - input-margin (subscribe [:input-margin]) - status-bar-height (get-in platform-specific [:component-styles :status-bar status-bar :height])] - (reaction - (- @layout-height @input-margin status-bar-height))))) - (register-sub :all-messages-loaded? (fn [db] (let [chat-id (subscribe [:get-current-chat-id])] @@ -276,10 +184,33 @@ (reaction (get-in @db [:message-data :short-preview (:message-id @last-message)]))))) +(register-sub :get-default-container-area-height + (fn [db] + (reaction + (let [input-height (subscribe [:chat-ui-props :input-height]) + layout-height (subscribe [:get :layout-height]) + chat-input-margin (subscribe [:chat-input-margin]) + bottom (+ @input-height @chat-input-margin)] + (input-utils/default-container-area-height bottom @layout-height))))) + +(register-sub :get-max-container-area-height + (fn [db] + (reaction + (let [input-height (subscribe [:chat-ui-props :input-height]) + layout-height (subscribe [:get :layout-height]) + chat-input-margin (subscribe [:chat-input-margin]) + bottom (+ @input-height @chat-input-margin)] + (input-utils/max-container-area-height bottom @layout-height))))) + +(register-sub :chat-animations + (fn [db [_ key type]] + (let [chat-id (subscribe [:get-current-chat-id])] + (reaction (get-in @db [:chat-animations @chat-id key type]))))) + (register-sub :get-chat-last-outgoing-message (fn [db [_ chat-id]] (reaction - (->> (:messages (get-in @db [:chats chat-id])) - (filter :outgoing) - (sort-by :clock-value >) - (first))))) + (->> (:messages (get-in @db [:chats chat-id])) + (filter :outgoing) + (sort-by :clock-value >) + (first))))) diff --git a/src/status_im/chat/suggestions.cljs b/src/status_im/chat/suggestions.cljs deleted file mode 100644 index 15e5585625..0000000000 --- a/src/status_im/chat/suggestions.cljs +++ /dev/null @@ -1,52 +0,0 @@ -(ns status-im.chat.suggestions - (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.chat.constants :as chat-consts] - [status-im.models.commands :refer [get-commands - get-chat-command-request - get-chat-command-to-message-id]] - [status-im.utils.utils :refer [log http-get]] - [clojure.string :as s])) - -(defn suggestion? [text] - (= (get text 0) chat-consts/command-char)) - -(defn can-be-suggested? [text] - (fn [{:keys [name]}] - (.startsWith (str chat-consts/command-char name) text))) - -(defn get-suggestions - [{:keys [current-chat-id] :as db} text] - (let [commands (get-in db [:chats current-chat-id :commands])] - (if (suggestion? text) - (filter (fn [[_ v]] ((can-be-suggested? text) v)) commands) - []))) - -(defn get-command [db text] - (when (suggestion? text) - ;; TODO change 'commands' to 'suggestions' - (first (filter #(= (:text %) text) (get-commands db))))) - -(defn handle-command [db command-key content] - (when-let [command-handler (get-chat-command-request db)] - (let [to-message-id (get-chat-command-to-message-id db)] - (command-handler to-message-id command-key content))) - db) - -(defn get-command-handler [db command-key content] - (when-let [command-handler (get-chat-command-request db)] - (let [to-message-id (get-chat-command-to-message-id db)] - (fn [] - (command-handler to-message-id command-key content))))) - -(defn check-suggestion [db message] - (when-let [suggestion-text (when (string? message) - (re-matches (re-pattern (str "^" chat-consts/command-char "[^\\s]+\\s")) message))] - (let [suggestion-text' (s/trim suggestion-text)] - (->> (get-commands db) - (filter #(= suggestion-text' (->> % second :name (str chat-consts/command-char)))) - first)))) - -(defn typing-command? [db] - (-> db - (get-in [:chats (:current-chat-id db) :input-text]) - suggestion?)) diff --git a/src/status_im/chat/suggestions_responder.cljs b/src/status_im/chat/suggestions_responder.cljs deleted file mode 100644 index c3b844fbfc..0000000000 --- a/src/status_im/chat/suggestions_responder.cljs +++ /dev/null @@ -1,29 +0,0 @@ -(ns status-im.chat.suggestions-responder - (:require [status-im.components.drag-drop :as drag] - [status-im.components.animation :as anim] - [re-frame.core :refer [dispatch]])) - -;; todo bad name. Ideas? -(defn enough-dy [gesture] - (> (Math/abs (.-dy gesture)) 10)) - -(defn on-move [response-height layout-height] - (fn [_ gesture] - (when (enough-dy gesture) - (let [to-value (- @layout-height (.-moveY gesture))] - (anim/start - (anim/spring response-height {:toValue to-value})))))) - -(defn on-release [response-height handler-name] - (fn [_ gesture] - (when (enough-dy gesture) - (dispatch [handler-name - (.-vy gesture) - ;; todo access to "private" property - ;; better to find another way... - (.-_value response-height)])))) - -(defn pan-responder [response-height layout-height handler-name] - (drag/create-pan-responder - {:on-move (on-move response-height layout-height) - :on-release (on-release response-height handler-name)})) diff --git a/src/status_im/chat/utils.cljs b/src/status_im/chat/utils.cljs index 6440e432d4..08fbe36ab2 100644 --- a/src/status_im/chat/utils.cljs +++ b/src/status_im/chat/utils.cljs @@ -1,6 +1,7 @@ (ns status-im.chat.utils (:require [status-im.constants :refer [console-chat-id - wallet-chat-id]])) + wallet-chat-id]] + [clojure.string :as str])) (defn console? [s] (= console-chat-id s)) @@ -11,6 +12,10 @@ (defn wallet? [s] (= wallet-chat-id s)) +(defn safe-trim [s] + (when (string? s) + (str/trim s))) + (defn add-message-to-db ([db add-to-chat-id chat-id message] (add-message-to-db db add-to-chat-id chat-id message true)) ([db add-to-chat-id chat-id message new?] @@ -35,3 +40,8 @@ ([db chat-id message] (let [previous-message (first (get-in db [:chats chat-id :messages]))] (check-message previous-message message)))) + +(defn command-valid? [message validator] + (if validator + (validator message) + (pos? (count message)))) diff --git a/src/status_im/chat/views/command.cljs b/src/status_im/chat/views/command.cljs deleted file mode 100644 index 078f05c123..0000000000 --- a/src/status_im/chat/views/command.cljs +++ /dev/null @@ -1,27 +0,0 @@ -(ns status-im.chat.views.command - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.components.react :refer [view - icon - text - touchable-highlight]] - [status-im.chat.constants :as chat-consts] - [status-im.chat.styles.input :as st])) - -(defn set-input-message [message] - (dispatch [:set-chat-command-content message])) - -(defn valid? [message validator] - (if validator - (validator message) - (pos? (count message)))) - -(defview command-icon [command] - [icon-width [:get :command-icon-width]] - [view st/command-container - [view {:style (st/command-text-container command) - :onLayout (fn [event] - (let [width (.. event -nativeEvent -layout -width)] - (when (not= icon-width width) - (dispatch [:set :command-icon-width width]))))} - [text {:style st/command-text} (str chat-consts/command-char (:name command))]]]) diff --git a/src/status_im/chat/views/command_validation.cljs b/src/status_im/chat/views/command_validation.cljs deleted file mode 100644 index 8b69b69bcd..0000000000 --- a/src/status_im/chat/views/command_validation.cljs +++ /dev/null @@ -1,30 +0,0 @@ -(ns status-im.chat.views.command-validation - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [status-im.components.react :as c] - [status-im.chat.styles.command-validation :as st] - [status-im.utils.listview :as lw])) - -(defn message [{:keys [title description]}] - (c/list-item - [c/view - [c/text {:style st/title} title] - [c/text {:style st/description} description]])) - -(defn messages-list [errors] - [c/list-view {:renderRow message - :keyboardShouldPersistTaps true - :dataSource (lw/to-datasource errors) - :style st/messages-container}]) - -(defview validation-messages [] - [validation-messages [:validation-errors] - custom-errors [:custom-validation-errors] - command? [:command?]] - [c/view - (cond (seq custom-errors) - (vec (concat [c/view] custom-errors)) - - (seq validation-messages) - [messages-list validation-messages] - - :else nil)]) diff --git a/src/status_im/chat/views/input/animations/expandable.cljs b/src/status_im/chat/views/input/animations/expandable.cljs new file mode 100644 index 0000000000..53a06b4352 --- /dev/null +++ b/src/status_im/chat/views/input/animations/expandable.cljs @@ -0,0 +1,67 @@ +(ns status-im.chat.views.input.animations.expandable + (:require [reagent.core :as r] + [reagent.impl.component :as rc] + [re-frame.core :refer [dispatch subscribe]] + [status-im.components.animation :as anim] + [status-im.components.drag-drop :as drag] + [status-im.components.react :refer [view + animated-view]] + [status-im.chat.views.input.animations.responder :as resp] + [status-im.chat.views.input.utils :as input-utils] + [status-im.chat.styles.animations :as style] + [taoensso.timbre :as log])) + +(defn header [key container-height] + (let [max-container-height (subscribe [:get-max-container-area-height]) + pan-responder (resp/pan-responder container-height + max-container-height + :fix-expandable-height + key)] + (fn [_] + [view (merge (drag/pan-handlers pan-responder) + {:style style/header-container}) + [view style/header-icon]]))) + +(defn expandable-view-on-update [{:keys [anim-value to-changed-height max-height chat-input-margin height]}] + (let [to-default-height (subscribe [:get-default-container-area-height]) + layout-height (subscribe [:get :layout-height])] + (fn [_] + (let [to-change-height (if (= @to-changed-height :max) + (input-utils/max-container-area-height @chat-input-margin @layout-height) + @to-changed-height) + to-value (min (or @to-changed-height (or height @to-default-height)) + @max-height)] + (anim/start + (anim/spring anim-value {:toValue to-value + :friction 10 + :tension 60})))))) + +(defn expandable-view [{:keys [key height]} & _] + (let [anim-value (anim/create-value 0) + input-height (subscribe [:chat-ui-props :input-height]) + chat-input-margin (subscribe [:chat-input-margin]) + max-height (subscribe [:get-max-container-area-height]) + to-changed-height (subscribe [:chat-animations key :height]) + changes-counter (subscribe [:chat-animations key :changes-counter]) + on-update (expandable-view-on-update {:anim-value anim-value + :to-changed-height to-changed-height + :max-height max-height + :chat-input-margin chat-input-margin + :height height})] + (r/create-class + {:component-did-mount + on-update + :component-did-update + on-update + :component-will-unmount + (if height + #(dispatch [:set-expandable-height key height]) + #(dispatch [:choose-predefined-expandable-height key :default])) + :reagent-render + (fn [{:keys [draggable?]} & elements] + @to-changed-height @changes-counter @max-height + (let [bottom (+ @input-height @chat-input-margin)] + (into [animated-view {:style (style/expandable-container anim-value bottom)} + (when draggable? + [header key anim-value])] + elements)))}))) \ No newline at end of file diff --git a/src/status_im/chat/views/input/animations/responder.cljs b/src/status_im/chat/views/input/animations/responder.cljs new file mode 100644 index 0000000000..3a55f78730 --- /dev/null +++ b/src/status_im/chat/views/input/animations/responder.cljs @@ -0,0 +1,28 @@ +(ns status-im.chat.views.input.animations.responder + (:require [status-im.components.drag-drop :as drag] + [status-im.components.animation :as anim] + [status-im.chat.views.input.utils :as input-utils] + [re-frame.core :refer [dispatch]] + [taoensso.timbre :as log])) + +;; todo bad name. Ideas? +(defn enough-dy [gesture] + (> (Math/abs (.-dy gesture)) 10)) + +(defn on-move [response-height layout-height] + (fn [_ gesture] + (when (enough-dy gesture) + (let [to-value (- @layout-height (.-moveY gesture))] + (when (> to-value input-utils/min-height) + (anim/start + (anim/spring response-height {:toValue to-value}))))))) + +(defn on-release [response-height handler-name key] + (fn [_ gesture] + (when (enough-dy gesture) + (dispatch [handler-name (.-vy gesture) (.-_value response-height) key])))) + +(defn pan-responder [response-height layout-height handler-name key] + (drag/create-pan-responder + {:on-move (on-move response-height layout-height) + :on-release (on-release response-height handler-name key)})) diff --git a/src/status_im/chat/views/emoji.cljs b/src/status_im/chat/views/input/emoji.cljs similarity index 71% rename from src/status_im/chat/views/emoji.cljs rename to src/status_im/chat/views/input/emoji.cljs index 1388cd79b1..fc910f3a5f 100644 --- a/src/status_im/chat/views/emoji.cljs +++ b/src/status_im/chat/views/input/emoji.cljs @@ -1,17 +1,17 @@ -(ns status-im.chat.views.emoji +(ns status-im.chat.views.input.emoji (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch]] [status-im.components.react :refer [view text icon emoji-picker]] - [status-im.chat.styles.emoji :as st] + [status-im.chat.styles.input.emoji :as style] [status-im.i18n :refer [label]])) (defview emoji-view [] [keyboard-max-height [:get :keyboard-max-height]] - [view {:style (st/container keyboard-max-height)} - [view st/emoji-container - [emoji-picker {:style st/emoji-picker + [view {:style (style/container keyboard-max-height)} + [view style/emoji-container + [emoji-picker {:style style/emoji-picker :hideClearButton true :onEmojiSelected #(dispatch [:add-to-chat-input-text %])}]]]) diff --git a/src/status_im/chat/views/input/input.cljs b/src/status_im/chat/views/input/input.cljs new file mode 100644 index 0000000000..0c028f8244 --- /dev/null +++ b/src/status_im/chat/views/input/input.cljs @@ -0,0 +1,220 @@ +(ns status-im.chat.views.input.input + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [clojure.string :as str] + [reagent.core :as r] + [re-frame.core :refer [subscribe dispatch]] + [taoensso.timbre :as log] + [status-im.accessibility-ids :as id] + [status-im.components.react :refer [view + animated-view + text + scroll-view + text-input + icon + touchable-highlight + dismiss-keyboard!]] + [status-im.chat.models.input :as input-model] + [status-im.chat.views.input.emoji :as emoji] + [status-im.chat.views.input.parameter-box :as parameter-box] + [status-im.chat.views.input.result-box :as result-box] + [status-im.chat.views.input.suggestions :as suggestions] + [status-im.chat.views.input.validation-messages :as validation-messages] + [status-im.chat.styles.input.input :as style] + [status-im.chat.utils :as utils] + [status-im.chat.constants :as const] + [status-im.components.animation :as anim] + [status-im.i18n :as i18n])) + +(defn command-view [index {command-name :name :as command}] + [touchable-highlight {:on-press #(dispatch [:select-chat-input-command command nil])} + [view + [text {:style (style/command (= index 0)) + :font :roboto-mono} + (str const/command-char) command-name]]]) + +(defview commands-view [] + [commands [:chat :command-suggestions] + show-suggestions? [:show-suggestions?]] + [view style/commands-root + [view style/command-list-icon-container + [touchable-highlight {:on-press #(do (dispatch [:toggle-chat-ui-props :show-suggestions?]) + (dispatch [:set-chat-ui-props :validation-messages nil]) + (dispatch [:update-suggestions]))} + [view style/commands-list-icon + (if show-suggestions? + [icon :close_gray style/close-commands-list-icon] + [icon :input_list style/commands-list-icon])]]] + [scroll-view {:horizontal true + :showsHorizontalScrollIndicator false + :keyboardShouldPersistTaps true} + [view style/commands + (for [[index [command-key command]] (map-indexed vector commands)] + ^{:key command-key} + [command-view index command])]]]) + +(defn- invisible-input [{:keys [set-layout-width value]}] + (let [input-text (subscribe [:chat :input-text]) + modified-text (subscribe [:chat :modified-text])] + [text {:style style/invisible-input-text + :on-layout #(let [w (-> (.-nativeEvent %) + (.-layout) + (.-width))] + (set-layout-width w))} + (utils/safe-trim (or @modified-text @input-text ""))])) + +(defn- input-helper [_] + (let [input-text (subscribe [:chat :input-text])] + (fn [{:keys [command width]}] + (when-let [placeholder (cond + (= @input-text const/command-char) + (i18n/label :t/type-a-command) + + (and command (empty? (:args command))) + (get-in command [:command :params 0 :placeholder]) + + (and command + (= (count (:args command)) 1) + (input-model/text-ends-with-space? @input-text)) + (get-in command [:command :params 1 :placeholder]))] + [text {:style (style/input-helper-text width)} + placeholder])))) + +(defn- text-field [_] + (let [input-text (subscribe [:chat :input-text]) + modified-text (subscribe [:chat :modified-text]) + command (subscribe [:selected-chat-command]) + sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])] + (fn [{:keys [set-layout-height height]}] + [text-input + {:ref #(dispatch [:set-chat-ui-props :input-ref %]) + :accessibility-label id/chat-message-input + :blur-on-submit false + :multiline true + :default-value (or @modified-text @input-text "") + :editable (not @sending-in-progress?) + :on-blur #(do (dispatch [:set-chat-ui-props :input-focused? false]) + (set-layout-height 0)) + :on-change-text #(when-not (str/includes? % "\n") + (do (dispatch [:set-chat-input-text %]) + (dispatch [:load-chat-parameter-box (:command @command)]) + (when (not @command) + (dispatch [:set-chat-input-metadata nil]) + (dispatch [:set-chat-ui-props :result-box nil])) + (dispatch [:set-chat-ui-props :validation-messages nil]))) + :on-content-size-change #(let [h (-> (.-nativeEvent %) + (.-contentSize) + (.-height))] + (set-layout-height h)) + :on-selection-change #(let [s (-> (.-nativeEvent %) + (.-selection))] + ;; This will be a bit tricky: + ;; iOS calls onSelectionChange BEFORE onChangeText, while + ;; Android calls onChange text first. + ;; We need some consistency, so we call the callback with a small delay: + (js/setTimeout + (fn [] (dispatch [:set-chat-ui-props :selection {:start (.-start s) + :end (.-end s)}])) + 20)) + :on-submit-editing #(do (dispatch [:set-chat-ui-props :sending-in-progress? true]) + (dispatch [:send-current-message])) + :on-focus #(do (dispatch [:set-chat-ui-props :input-focused? true]) + (dispatch [:set-chat-ui-props :show-emoji? false])) + :style (style/input-view height) + :placeholder-text-color style/color-input-helper-placeholder}]))) + +(defn input-view [_] + (let [component (r/current-component) + set-layout-width #(r/set-state component {:width %}) + set-layout-height #(r/set-state component {:height %}) + command (subscribe [:selected-chat-command])] + (r/create-class + {:component-will-mount + (fn [] + (dispatch [:update-suggestions])) + + :reagent-render + (fn [{:keys [anim-margin]}] + (let [{:keys [width height]} (r/state component) + command @command] + [animated-view {:style (style/input-root height anim-margin)} + [text-field {:set-layout-height set-layout-height + :height height}] + [invisible-input {:set-layout-width set-layout-width}] + [input-helper {:command command + :width width}] + (if-not command + [touchable-highlight + {:on-press #(do (dispatch [:toggle-chat-ui-props :show-emoji?]) + (dismiss-keyboard!))} + [view + [icon :smile style/input-emoji-icon]]] + [touchable-highlight + {:on-press #(do (dispatch [:set-chat-input-text nil]) + (dispatch [:set-chat-input-metadata nil]) + (dispatch [:set-chat-ui-props :result-box nil]) + (dispatch [:set-chat-ui-props :validation-messages nil]))} + [view style/input-clear-container + [icon :close_gray style/input-clear-icon]]])]))}))) + +(defview input-container [{:keys [anim-margin]}] + [command-completion [:command-completion] + selected-command [:selected-chat-command] + input-text [:chat :input-text]] + [view style/input-container + [input-view {:anim-margin anim-margin}] + (when (and (not (str/blank? input-text)) + (or (not selected-command) + (some #{:complete :less-than-needed} [command-completion]))) + [touchable-highlight {:on-press #(do (dispatch [:set-chat-ui-props :sending-in-progress? true]) + (dispatch [:send-current-message]))} + [view style/send-message-container + [icon :arrow_top style/send-message-icon]]])]) + +(defn container [] + (let [margin (subscribe [:chat-input-margin]) + show-emoji? (subscribe [:chat-ui-props :show-emoji?]) + input-text (subscribe [:chat :input-text]) + anim-margin (anim/create-value 10) + container-anim-margin (anim/create-value 16) + bottom-anim-margin (anim/create-value 14)] + (r/create-class + {:component-did-mount + (fn [] + (when-not (str/blank? @input-text) + (.setValue anim-margin 0) + (.setValue container-anim-margin 8) + (.setValue bottom-anim-margin 8))) + :component-did-update + (fn [component] + (let [{:keys [text-empty?]} (reagent.core/props component)] + (let [to-anim-value (if text-empty? 10 0) + to-container-anim-value (if text-empty? 16 8) + to-bottom-anim-value (if text-empty? 14 8)] + (anim/start + (anim/timing anim-margin {:toValue to-anim-value + :duration 100})) + (anim/start + (anim/timing container-anim-margin {:toValue to-container-anim-value + :duration 100})) + (anim/start + (anim/timing bottom-anim-margin {:toValue to-bottom-anim-value + :duration 100}))))) + + :reagent-render + (fn [] + [view + [parameter-box/parameter-box-view] + [result-box/result-box-view] + [suggestions/suggestions-view] + [validation-messages/validation-messages-view] + [view {:style (style/root @margin) + :on-layout #(let [h (-> (.-nativeEvent %) + (.-layout) + (.-height))] + (dispatch [:set-chat-ui-props :input-height h]))} + [animated-view {:style (style/container container-anim-margin bottom-anim-margin)} + (when (str/blank? @input-text) + [commands-view]) + [input-container {:anim-margin anim-margin}]] + (when @show-emoji? + [emoji/emoji-view])]])}))) diff --git a/src/status_im/chat/views/input/parameter_box.cljs b/src/status_im/chat/views/input/parameter_box.cljs new file mode 100644 index 0000000000..96a87a41d6 --- /dev/null +++ b/src/status_im/chat/views/input/parameter_box.cljs @@ -0,0 +1,31 @@ +(ns status-im.chat.views.input.parameter-box + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch]] + [status-im.components.react :refer [view + scroll-view + touchable-highlight + text + icon]] + [status-im.chat.views.input.animations.expandable :refer [expandable-view]] + [status-im.chat.views.input.utils :as input-utils] + [status-im.i18n :refer [label]] + [taoensso.timbre :as log] + [clojure.string :as str])) + +(defview parameter-box-container [] + [parameter-box [:chat-parameter-box]] + (when (:hiccup parameter-box) + (:hiccup parameter-box))) + +(defview parameter-box-view [] + [chat-parameter-box [:chat-parameter-box] + show-suggestions? [:show-suggestions?] + input-text [:chat :input-text] + validation-messages [:chat-ui-props :validation-messages]] + (when (and chat-parameter-box + (not (str/blank? input-text)) + (not validation-messages) + (not show-suggestions?)) + [expandable-view {:key :parameter-box + :draggable? true} + [parameter-box-container]])) \ No newline at end of file diff --git a/src/status_im/chat/views/input/result_box.cljs b/src/status_im/chat/views/input/result_box.cljs new file mode 100644 index 0000000000..f62e876238 --- /dev/null +++ b/src/status_im/chat/views/input/result_box.cljs @@ -0,0 +1,37 @@ +(ns status-im.chat.views.input.result-box + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch]] + [status-im.components.react :refer [view + scroll-view + touchable-highlight + text + icon]] + [status-im.chat.views.input.animations.expandable :refer [expandable-view]] + [status-im.chat.styles.input.result-box :as style] + [status-im.chat.views.input.utils :as input-utils] + [status-im.i18n :refer [label]] + [taoensso.timbre :as log])) + +(defn header [title] + [view {:style style/header-container} + [view style/header-title-container + [text {:style style/header-title-text + :number-of-lines 1 + :font :medium} + title] + [touchable-highlight {:on-press #(dispatch [:set-chat-ui-props :result-box nil])} + [view style/header-close-container + [icon :close_light_gray style/header-close-icon]]]]]) + +(defview result-box-container [markup] + [view {:flex 1} + markup]) + +(defview result-box-view [] + [{:keys [markup title] :as result-box} [:chat-ui-props :result-box]] + (when result-box + [expandable-view {:key :result-box + :draggable? true} + [view {:flex 1} + [header title] + [result-box-container markup]]])) \ No newline at end of file diff --git a/src/status_im/chat/views/input/suggestions.cljs b/src/status_im/chat/views/input/suggestions.cljs new file mode 100644 index 0000000000..33f967a819 --- /dev/null +++ b/src/status_im/chat/views/input/suggestions.cljs @@ -0,0 +1,75 @@ +(ns status-im.chat.views.input.suggestions + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch]] + [status-im.components.react :refer [view + scroll-view + touchable-highlight + text + icon]] + [status-im.data-store.messages :as messages] + [status-im.chat.styles.input.suggestions :as style] + [status-im.chat.constants :as const] + [status-im.chat.views.input.animations.expandable :refer [expandable-view]] + [status-im.chat.views.input.utils :as input-utils] + [status-im.i18n :refer [label]] + [taoensso.timbre :as log])) + +(defn suggestion-item [{:keys [on-press name description last?]}] + [touchable-highlight {:on-press on-press} + [view (style/item-suggestion-container last?) + [view {:style style/item-suggestion-name} + [text {:style style/item-suggestion-name-text + :font :roboto-mono} + const/command-char name]] + [text {:style style/item-suggestion-description + :number-of-lines 2} + description]]]) + +(defview request-item [{:keys [type message-id]} last?] + [{:keys [name description] :as response} [:get-response type] + {:keys [chat-id]} [:get-current-chat]] + [suggestion-item + {:on-press #(let [{:keys [params]} (messages/get-message-content-by-id message-id) + metadata (assoc params :to-message-id message-id)] + (dispatch [:select-chat-input-command response metadata])) + :name name + :description description + :last? last?}]) + +(defview command-item [{:keys [name description] :as command} last?] + [] + [suggestion-item + {:on-press #(dispatch [:select-chat-input-command command nil]) + :name name + :description description + :last? last?}]) + +(defn item-title [top-padding? s] + [view (style/item-title-container top-padding?) + [text {:style style/item-title-text} + s]]) + +(defview suggestions-view [] + [show-suggestions? [:show-suggestions?] + requests [:chat :request-suggestions] + commands [:chat :command-suggestions]] + (when show-suggestions? + [expandable-view {:key :suggestions + :draggable? false + :height 212} + [view {:flex 1} + [scroll-view {:keyboardShouldPersistTaps true} + (when (seq requests) + [view + [item-title false (label :t/suggestions-requests)] + (for [[i {:keys [chat-id message-id] :as request}] (map-indexed vector requests)] + ^{:key [chat-id message-id]} + [request-item request (= i (dec (count requests)))])]) + (when (seq commands) + [view + [item-title (seq requests) (label :t/suggestions-commands)] + (for [[i [_ command]] (->> commands + (remove #(nil? (:title (second %)))) + (map-indexed vector))] + ^{:key i} + [command-item command (= i (dec (count commands)))])])]]])) \ No newline at end of file diff --git a/src/status_im/chat/views/input/utils.cljs b/src/status_im/chat/views/input/utils.cljs new file mode 100644 index 0000000000..fed3b170f9 --- /dev/null +++ b/src/status_im/chat/views/input/utils.cljs @@ -0,0 +1,16 @@ +(ns status-im.chat.views.input.utils + (:require [taoensso.timbre :as log] + [status-im.utils.platform :refer [platform-specific]])) + +(def min-height 17) +(def default-height 300) + +(defn default-container-area-height [bottom screen-height] + (let [status-bar-height (get-in platform-specific [:component-styles :status-bar :default :height])] + (if (> (+ bottom default-height status-bar-height) screen-height) + (- screen-height bottom status-bar-height) + default-height))) + +(defn max-container-area-height [bottom screen-height] + (let [status-bar-height (get-in platform-specific [:component-styles :status-bar :default :height])] + (- screen-height bottom status-bar-height))) \ No newline at end of file diff --git a/src/status_im/chat/views/input/validation_messages.cljs b/src/status_im/chat/views/input/validation_messages.cljs new file mode 100644 index 0000000000..a46f2bd0be --- /dev/null +++ b/src/status_im/chat/views/input/validation_messages.cljs @@ -0,0 +1,24 @@ +(ns status-im.chat.views.input.validation-messages + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [status-im.components.react :as c] + [status-im.chat.styles.input.validation-message :as style] + [status-im.utils.listview :as lw])) + +(defn validation-message [{:keys [title description]}] + [c/view style/message-container + [c/text {:style style/message-title} + title] + [c/text {:style style/message-description} + description]]) + +(defn messages-list [markup] + [c/view {:flex 1} + markup]) + +(defview validation-messages-view [] + [chat-input-margin [:chat-input-margin] + input-height [:chat-ui-props :input-height] + markup [:chat-ui-props :validation-messages]] + (when markup + [c/view (style/root (+ input-height chat-input-margin)) + [messages-list markup]])) diff --git a/src/status_im/chat/views/input/web_view.cljs b/src/status_im/chat/views/input/web_view.cljs new file mode 100644 index 0000000000..cc1fb1e156 --- /dev/null +++ b/src/status_im/chat/views/input/web_view.cljs @@ -0,0 +1,45 @@ +(ns status-im.chat.views.input.web-view + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [reagent.core :as r] + [re-frame.core :refer [dispatch]] + [status-im.components.webview-bridge :refer [webview-bridge]] + [status-im.components.react :refer [view + text]] + [status-im.i18n :refer [label]] + [status-im.utils.js-resources :as js-res] + [clojure.string :as str])) + +(defn on-navigation-change + [event {:keys [dynamicTitle] :as result-box}] + (let [{:strs [loading url title]} (js->clj event)] + (when-not (= "about:blank" url) + (when-not loading + (dispatch [:set-command-argument [0 url]])) + (when (and dynamicTitle (not (str/blank? title))) + (dispatch [:set-chat-ui-props :result-box (assoc result-box :title title)]))))) + +(defn web-view-error [] + (r/as-element + [view {:justify-content :center + :align-items :center + :flex-direction :row} + [text (label :t/web-view-error)]])) + +(defview bridged-web-view [{:keys [url]}] + [extra-js [:web-view-extra-js] + rpc-url [:get :rpc-url] + result-box [:chat-ui-props :result-box]] + (when url + [webview-bridge + {:ref #(dispatch [:set-webview-bridge %]) + :on-bridge-message #(dispatch [:webview-bridge-message %]) + :source {:uri url} + :render-error web-view-error + :java-script-enabled true + :injected-on-start-loading-java-script (str js-res/web3 + js-res/jquery + (js-res/web3-init rpc-url)) + :injected-java-script (str js-res/webview-js extra-js) + :bounces false + :on-navigation-state-change #(on-navigation-change % result-box) + :local-storage-enabled true}])) \ No newline at end of file diff --git a/src/status_im/chat/views/datemark.cljs b/src/status_im/chat/views/message/datemark.cljs similarity index 80% rename from src/status_im/chat/views/datemark.cljs rename to src/status_im/chat/views/message/datemark.cljs index 527c6d91b3..a350c8d0a1 100644 --- a/src/status_im/chat/views/datemark.cljs +++ b/src/status_im/chat/views/message/datemark.cljs @@ -1,10 +1,10 @@ -(ns status-im.chat.views.datemark +(ns status-im.chat.views.message.datemark (:require [re-frame.core :refer [subscribe dispatch]] [status-im.components.react :refer [view text]] [clojure.string :as str] [status-im.i18n :refer [label]] - [status-im.chat.styles.datemark :as st])) + [status-im.chat.styles.message.datemark :as st])) (defn chat-datemark [value] [view st/datemark-wrapper diff --git a/src/status_im/chat/views/message.cljs b/src/status_im/chat/views/message/message.cljs similarity index 97% rename from src/status_im/chat/views/message.cljs rename to src/status_im/chat/views/message/message.cljs index 349f5afe8a..e9f8a303f6 100644 --- a/src/status_im/chat/views/message.cljs +++ b/src/status_im/chat/views/message/message.cljs @@ -1,4 +1,4 @@ -(ns status-im.chat.views.message +(ns status-im.chat.views.message.message (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch]] [reagent.core :as r] @@ -15,10 +15,10 @@ [status-im.components.animation :as anim] [status-im.chat.constants :as chat-consts] [status-im.components.list-selection :refer [share browse]] - [status-im.chat.views.request-message :refer [message-content-command-request]] - [status-im.chat.styles.message :as st] - [status-im.chat.styles.command-pill :as pill-st] - [status-im.chat.views.datemark :refer [chat-datemark]] + [status-im.chat.views.message.request-message :refer [message-content-command-request]] + [status-im.chat.styles.message.message :as st] + [status-im.chat.styles.message.command-pill :as pill-st] + [status-im.chat.views.message.datemark :refer [chat-datemark]] [status-im.models.commands :refer [parse-command-message-content parse-command-request]] [status-im.resources :as res] @@ -127,7 +127,7 @@ chat-id] current-chat-id [:get-current-chat-id] contact-chat [:get-in [:chats (if outgoing to from)]] - preview [:get-in [:message-data :preview message-id]]] + preview [:get-in [:message-data :preview message-id :markup]]] (let [{:keys [command params]} (parse-command-message-content commands content) {:keys [name type] icon-path :icon} command] @@ -370,13 +370,13 @@ (defn chat-message [{:keys [outgoing message-id chat-id user-statuses from] :as message}] (let [my-identity (subscribe [:get :current-public-key]) status (subscribe [:get-in [:message-data :user-statuses message-id my-identity]]) - preview (subscribe [:get-in [:message-data :preview message-id]])] + preview (subscribe [:get-in [:message-data :preview message-id :markup]])] (r/create-class {:component-will-mount (fn [] (when (and (get-in message [:content :command]) (not @preview)) - (dispatch [:request-command-preview message]))) + (dispatch [:request-command-data message :preview]))) :component-did-mount (fn [] diff --git a/src/status_im/chat/views/request_message.cljs b/src/status_im/chat/views/message/request_message.cljs similarity index 86% rename from src/status_im/chat/views/request_message.cljs rename to src/status_im/chat/views/message/request_message.cljs index 5903c61f65..27ea5d3c89 100644 --- a/src/status_im/chat/views/request_message.cljs +++ b/src/status_im/chat/views/message/request_message.cljs @@ -1,4 +1,4 @@ -(ns status-im.chat.views.request-message +(ns status-im.chat.views.message.request-message (:require [re-frame.core :refer [subscribe dispatch]] [reagent.core :as r] [status-im.components.react :refer [view @@ -7,17 +7,19 @@ image icon touchable-highlight]] - [status-im.chat.styles.message :as st] + [status-im.chat.styles.message.message :as st] [status-im.accessibility-ids :as id] [status-im.models.commands :refer [parse-command-request]] - [status-im.components.animation :as anim])) + [status-im.components.animation :as anim] + [taoensso.timbre :as log])) (def request-message-icon-scale-delay 600) (defn set-chat-command [message-id command] (let [command-key (keyword (:name command)) - params (:set-params command)] - (dispatch [:set-response-chat-command message-id command-key params]))) + metadata (-> (:set-params command) + (assoc :to-message-id message-id))] + (dispatch [:select-chat-input-command command metadata]))) (def min-scale 1) (def max-scale 1.3) @@ -71,7 +73,7 @@ (let [commands-atom (subscribe [:get-responses]) answered? (subscribe [:is-request-answered? message-id]) status-initialized? (subscribe [:get :status-module-initialized?]) - preview (subscribe [:get-in [:message-data :preview message-id]])] + markup (subscribe [:get-in [:message-data :preview message-id :markup]])] (fn [{:keys [message-id content from incoming-group]}] (let [commands @commands-atom params (:params content) @@ -84,12 +86,12 @@ {:on-press (when (and (not @answered?) @status-initialized?) #(set-chat-command message-id command))} [view st/command-request-message-view - (if (and @preview - (not (string? @preview))) - [view @preview] + (if (and @markup + (not (string? @markup))) + [view @markup] [text {:style st/style-message-text :font :default} - (or @preview content)])]] + (or @markup content)])]] (when (:request-text command) [view st/command-request-text-view [text {:style st/style-sub-text diff --git a/src/status_im/chat/views/message_input.cljs b/src/status_im/chat/views/message_input.cljs deleted file mode 100644 index 0dac0d9170..0000000000 --- a/src/status_im/chat/views/message_input.cljs +++ /dev/null @@ -1,182 +0,0 @@ -(ns status-im.chat.views.message-input - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.components.react :refer [view - text - animated-view - icon - touchable-highlight - text-input]] - [status-im.chat.views.plain-message :as plain-message] - [status-im.chat.views.command :as command] - [status-im.chat.styles.message-input :as st] - [status-im.chat.styles.plain-message :as st-message] - [status-im.chat.styles.response :as st-response] - [status-im.accessibility-ids :as id] - [reagent.core :as r] - [clojure.string :as str] - [taoensso.timbre :as log] - [clojure.string :as s] - [status-im.commands.utils :refer [command-prefix]])) - -(defn send-button [{:keys [on-press accessibility-label]}] - [touchable-highlight {:on-press on-press - :accessibility-label accessibility-label} - [view st/send-wrapper - [view st/send-container - [icon :send st/send-icon]]]]) - -(defn plain-input-options [{:keys [set-layout-size-fn disable?]}] - {:style st-message/message-input - :on-change-text (when-not disable? plain-message/set-input-message) - :on-submit-editing plain-message/send - :on-content-size-change #(let [size (-> (.-nativeEvent %) - (.-contentSize) - (.-height))] - (set-layout-size-fn size)) - :on-focus #(do (dispatch [:set :focused true]) - (dispatch [:set-chat-ui-props :show-emoji? false])) - :on-blur #(do (dispatch [:set :focused false]) - (set-layout-size-fn 0)) - :blur-on-submit true - :multiline true - :editable (not disable?)}) - -(defn command-input-options [{:keys [icon-width disable? sending-disabled? flag]}] - {:style (st-response/command-input icon-width disable?) - :on-change-text (when-not disable? (fn [text] - ;; update flag only when the first - ;; character was added to commands input - (when (and (s/starts-with? text command-prefix) - (= (inc (count command-prefix)) (count text))) - (reset! flag true)) - (command/set-input-message text))) - :on-submit-editing (fn [] - (when-not sending-disabled? - (dispatch [:send-command!]))) - :on-focus #(dispatch [:set :focused true]) - :on-blur #(dispatch [:set :focused true]) - :blur-on-submit false}) - -(defn get-options [{:keys [type placeholder]} command-type] - (let [options (case (keyword type) - :phone {:keyboard-type "phone-pad"} - :password {:secure-text-entry true} - :number {:keyboard-type "numeric"} - nil)] - (if (= :response command-type) - (if placeholder - (assoc options :placeholder placeholder) - options) - (assoc options :placeholder "")))) - -(defn get-selection - [{:keys [focused? flag input-command command? just-set?]}] - (cond (and command? - (= input-command command-prefix) - focused? - (not just-set?)) - {:start 2 - :end 2} - - (and focused? flag) - {:start 3 - :end 3} - - :else nil)) - -(defview message-input [set-layout-size] - [input-message [:get-chat-input-text] - input-command [:get-chat-command-content] - command [:get-chat-command] - icon-width [:command-icon-width] - disable? [:get :disable-input] - active? [:chat :is-active] - command? [:command?] - parameter [:get-command-parameter] - type [:command-type] - just-set? [:get :just-set-command?] - sending-disabled? [:chat-ui-props :sending-disabled?] - state {:input (atom nil) - :focused? (atom nil) - :3-symbols-flag (r/atom false)}] - {:component-did-update (fn [] - (when just-set? - (dispatch [:set :just-set-command? false])) - (when @(:3-symbols-flag state) - (reset! (:3-symbols-flag state) false)) - (when (and command? - (not (:fullscreen command))) - (.focus @(:input state))))} - - (do - @(:3-symbols-flag state) - [text-input - (merge - (if command? - (command-input-options {:icon-width icon-width - :disable? disable? - :sendind-disabled? sending-disabled? - :flag (:3-symbols-flag state)}) - (plain-input-options {:set-layout-size-fn set-layout-size - :disable? (or disable? (not active?))})) - {:placeholder-text-color :#c0c5c9 - :onFocus #(reset! (:focused? state) true) - :onBlur #(reset! (:focused? state) false) - :auto-focus (when command? (not (:fullscreen command))) - :ref #(reset! (:input state) %) - :accessibility-label id/chat-message-input - ;; for some reason app crashes when this property is not nil and - ;; input is not focused - :selection (get-selection {:focused? @(:focused? state) - :flag @(:3-symbols-flag state) - :input-command input-command - :command? command? - :just-set? just-set?}) - :default-value (if command? - (or input-command "") - (or input-message ""))} - (when command? - (get-options parameter type)))])) - -(defn plain-message-get-initial-state [_] - {:height 0}) - -(defn plain-message-input-view [] - (let [command? (subscribe [:command?]) - command (subscribe [:get-chat-command]) - input-command (subscribe [:get-chat-command-content]) - input-message (subscribe [:get-chat-input-text]) - valid-plain-message? (subscribe [:valid-plain-message?]) - component (r/current-component) - set-layout-size #(r/set-state component {:height %}) - sending-disabled? (subscribe [:chat-ui-props :sending-disabled?])] - (r/create-class - {:get-initial-state - plain-message-get-initial-state - :component-will-update - (fn [_] - (when (or (and @command? (str/blank? @input-command)) - (and (not @command?) (not @input-message))) - (set-layout-size 0))) - :reagent-render - (fn [] - (let [{:keys [height]} (r/state component)] - [view st/input-container - [view (st/input-view height) - [plain-message/commands-button height #(set-layout-size 0)] - [view (st/message-input-container height) - [message-input set-layout-size]] - [plain-message/smile-button height] - (when (or (and @command? (not (str/blank? @input-command))) - @valid-plain-message?) - (let [on-press (if @command? - #(dispatch [:send-command!]) - plain-message/send)] - [send-button {:on-press (fn [e] - (when-not @sending-disabled? - (dispatch [:set-chat-ui-props :show-emoji? false]) - (on-press e))) - :accessibility-label id/chat-send-button}])) - (when (and @command? (= :command (:type @command))) - [command/command-icon @command])]]))}))) diff --git a/src/status_im/chat/views/new_message.cljs b/src/status_im/chat/views/new_message.cljs deleted file mode 100644 index 4eee8c014f..0000000000 --- a/src/status_im/chat/views/new_message.cljs +++ /dev/null @@ -1,29 +0,0 @@ -(ns status-im.chat.views.new-message - (:require-macros [status-im.utils.views :refer [defview]]) - (:require - [re-frame.core :refer [dispatch subscribe]] - [status-im.components.react :refer [view - scroll-view]] - [status-im.chat.views.message-input :refer [plain-message-input-view]] - [status-im.chat.constants :refer [input-height]] - [status-im.utils.platform :refer [platform-specific]] - [status-im.chat.styles.message :as st])) - -(defn get-height [event] - (.-height (.-layout (.-nativeEvent event)))) - -(defview chat-message-input-view [] - [margin [:input-margin] - command? [:command?] - response-height [:response-height] - suggestions [:get-suggestions] - message-input-height [:get-message-input-view-height]] - (let [on-top? (or (and (seq suggestions) (not command?)) - (not= response-height input-height)) - style (get-in platform-specific [:component-styles :chat :new-message])] - [view {:style (merge (st/new-message-container margin on-top?) style) - :on-layout (fn [event] - (let [height (get-height event)] - (when (not= height message-input-height) - (dispatch [:set-message-input-view-height height]))))} - [plain-message-input-view]])) diff --git a/src/status_im/chat/views/plain_message.cljs b/src/status_im/chat/views/plain_message.cljs deleted file mode 100644 index d8f9628786..0000000000 --- a/src/status_im/chat/views/plain_message.cljs +++ /dev/null @@ -1,107 +0,0 @@ -(ns status-im.chat.views.plain-message - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [reagent.core :as r] - [status-im.components.react :refer [view - animated-view - icon - text - touchable-highlight - dismiss-keyboard!]] - [status-im.components.animation :as anim] - [status-im.chat.styles.plain-message :as st] - [status-im.chat.constants :as chat-consts] - [status-im.constants :refer [response-input-hiding-duration]])) - -(defn set-input-message [message] - (dispatch [:set-chat-input-text message])) - -(defn send [] - (dispatch [:send-chat-message])) - -(defn message-valid? [ message] - (and (pos? (count message)) - (not= chat-consts/command-char message))) - -(defn button-animation-logic [{:keys [command? val]}] - (fn [_] - (let [to-scale (if @command? 0 1)] - (anim/start (anim/spring val {:toValue to-scale - :tension 30}))))) - -(defn list-container [min] - (fn [{:keys [command? width]}] - (let [n-width (if @command? min 56) - delay (if @command? 100 0)] - (anim/start (anim/timing width {:toValue n-width - :duration response-input-hiding-duration - :delay delay}) - #(dispatch [:set :disable-input false]))))) - -(defn commands-button [_ _] - (let [command? (subscribe [:command?]) - requests (subscribe [:get-requests]) - suggestions (subscribe [:get-suggestions]) - buttons-scale (anim/create-value (if @command? 1 0)) - container-width (anim/create-value (if @command? 20 56)) - context {:command? command? - :val buttons-scale - :width container-width} - on-update (fn [_] - ((button-animation-logic context)) - ((list-container 20) context))] - (r/create-class - {:component-did-mount - on-update - :component-did-update - on-update - :reagent-render - (fn [height on-press] - [touchable-highlight {:on-press #(do (dispatch [:set-chat-ui-props :show-emoji? false]) - (dispatch [:switch-command-suggestions!]) - (on-press)) - :disabled @command?} - [animated-view {:style (st/message-input-button-touchable container-width)} - (when-not @command? - [animated-view {:style (st/message-input-button - buttons-scale - (if (seq @suggestions) 16 17))} - (if (seq @suggestions) - [icon :close_gray st/close-icon] - [icon :input_list st/list-icon]) - (when (and (seq @requests) - (not (seq @suggestions))) - [view st/requests-icon-container - [view st/requests-icon]])])]])}))) - -(defn smile-animation-logic [{:keys [command? val width]}] - (fn [_] - (let [to-scale (if @command? 0 1)] - (when-not @command? (anim/set-value width 56)) - (anim/start (anim/spring val {:toValue to-scale - :tension 30}) - (fn [e] - (when (and @command? (.-finished e)) - (anim/set-value width 0.1))))))) - -(defn smile-button [_] - (let [command? (subscribe [:command?]) - buttons-scale (anim/create-value (if @command? 1 0)) - container-width (anim/create-value (if @command? 0.1 56)) - context {:command? command? - :val buttons-scale - :width container-width} - on-update (smile-animation-logic context)] - (r/create-class - {:component-did-mount - on-update - :component-did-update - on-update - :reagent-render - (fn [] - [touchable-highlight {:on-press #(do (dispatch [:toggle-chat-ui-props :show-emoji?]) - (dismiss-keyboard!)) - :disabled @command?} - [animated-view {:style (st/message-input-button-touchable container-width)} - [animated-view {:style (st/message-input-button buttons-scale 16)} - [icon :smile st/smile-icon]]]])}))) diff --git a/src/status_im/chat/views/response.cljs b/src/status_im/chat/views/response.cljs deleted file mode 100644 index 6a8a89c843..0000000000 --- a/src/status_im/chat/views/response.cljs +++ /dev/null @@ -1,176 +0,0 @@ -(ns status-im.chat.views.response - (:require-macros [reagent.ratom :refer [reaction]] - [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [reagent.core :as r] - [status-im.components.react :refer [view - animated-view - icon - image - text - touchable-highlight - web-view - scroll-view]] - [status-im.components.drag-drop :as drag] - [status-im.chat.styles.response :as st] - [status-im.chat.styles.dragdown :as ddst] - [status-im.components.animation :as anim] - [status-im.chat.suggestions-responder :as resp] - [status-im.chat.constants :as c] - [status-im.chat.views.command-validation :as cv] - [status-im.utils.platform :refer [ios?]] - [status-im.components.webview-bridge :refer [webview-bridge]] - [status-im.i18n :refer [label]] - [status-im.accessibility-ids :as id] - [status-im.utils.datetime :as dt] - [status-im.utils.name :refer [shortened-name]] - [status-im.utils.js-resources :as js-res] - [status-im.commands.utils :as cu] - [taoensso.timbre :as log] - [clojure.string :as s])) - -(defn drag-icon [] - [view st/drag-container - [icon :drag_white st/drag-icon]]) - -(defn command-icon [{icon-path :icon - color :color}] - [view st/command-icon-container - (when icon-path - [icon icon-path (st/command-icon color)])]) - -(defn request-info-text [name chat-id added] - (let [name' (shortened-name (or name chat-id) 20)] - (str "By " name' ", " - (dt/format-date "MMM" added) - " " - (dt/get-ordinal-date added) - " at " - (dt/format-date "HH:mm" added)))) - -(defview info-container - [command] - [{:keys [name chat-id]} [:get-current-chat] - {:keys [added]} [:get-current-request]] - [view st/info-container - [text {:style st/command-name} - (str (:description command) " " (label :t/request))] - (when added - [text {:style st/message-info} (request-info-text name chat-id added)])]) - -(defn request-info [response-height] - (let [layout-height (subscribe [:max-layout-height :default]) - pan-responder (resp/pan-responder response-height - layout-height - :fix-response-height) - command (subscribe [:get-chat-command])] - (fn [_] - (if (= :response (:type @command)) - [view (merge (drag/pan-handlers pan-responder) - {:style (st/request-info (:color @command))}) - [drag-icon] - [view st/inner-container - [command-icon @command] - [info-container @command] - [touchable-highlight {:on-press #(dispatch [:start-cancel-command]) - :accessibility-label id/chat-cancel-response-button} - [view st/cancel-container - [icon :close_white st/cancel-icon]]]]] - [view (merge (drag/pan-handlers pan-responder) - {:style ddst/drag-down-touchable}) - [icon :drag_down ddst/drag-down-icon]])))) - -(defn container-animation-logic [{:keys [to-value val animate?]}] - (when-let [to-value @to-value] - (let [max-layout-height (subscribe [:max-layout-height :default]) - to-value (min to-value (max 0 @max-layout-height))] - (when-not (= to-value (.-_value val)) - (if (or (nil? @animate?) @animate?) - (anim/start (anim/timing val {:toValue to-value - :duration 300})) - (anim/set-value val to-value)))))) - -(defn container [response-height & _] - (let [;; todo to-response-height, cur-response-height must be specific - ;; for each chat - to-response-height (subscribe [:response-height :default]) - input-margin (subscribe [:input-margin]) - changed (subscribe [:animations :response-height-changed]) - animate? (subscribe [:animate?]) - context {:to-value to-response-height - :val response-height - :animate? animate?} - on-update #(container-animation-logic context)] - (r/create-class - {:component-did-mount - on-update - :component-did-update - on-update - :reagent-render - (fn [response-height & children] - @to-response-height @changed - (into [animated-view {:style (st/response-view - response-height - @input-margin)}] - children))}))) - -(defn on-navigation-change - [event] - (let [{:strs [loading url]} (js->clj event)] - (when-not (= "about:blank" url) - (when-not loading - (dispatch [:set-web-view-url url]) - (dispatch [:set-chat-command-content (str cu/command-prefix url)]))))) - -(defn web-view-error [] - (r/as-element - [view {:justify-content :center - :align-items :center - :flex-direction :row} - [text (label :t/web-view-error)]])) - -(defview suggestions-web-view [] - [url [:web-view-url] - extra-js [:web-view-extra-js] - rpc-url [:get :rpc-url]] - (when url - [webview-bridge - {:ref #(dispatch [:set-webview-bridge %]) - :on-bridge-message #(dispatch [:webview-bridge-message %]) - :source {:uri url} - :render-error web-view-error - :java-script-enabled true - :injected-on-start-loading-java-script (str js-res/web3 - js-res/jquery - (js-res/web3-init rpc-url)) - :injected-java-script (str js-res/webview-js extra-js) - :bounces false - :on-navigation-state-change on-navigation-change - :local-storage-enabled true}])) - -(defn placeholder [] - [view st/input-placeholder]) - -(defview response-suggestions-view [] - [suggestions [:get-content-suggestions]] - (when (seq suggestions) suggestions)) - -(defn response-view [] - (let [response-height (anim/create-value c/input-height) - command (subscribe [:get-chat-command]) - text (subscribe [:get-chat-input-text]) - suggestions (subscribe [:get-content-suggestions]) - errors (subscribe [:validation-errors]) - custom-errors (subscribe [:custom-validation-errors])] - (fn [] - (when (or (:fullscreen @command) - (= :response (:type @command)) - (and (not (s/blank? @text)) (seq @suggestions)) - (seq @errors) - (seq @custom-errors)) - [container response-height - [request-info response-height] - [suggestions-web-view] - [response-suggestions-view] - [cv/validation-messages] - [placeholder]])))) diff --git a/src/status_im/chat/views/suggestions.cljs b/src/status_im/chat/views/suggestions.cljs deleted file mode 100644 index 007a13bd3f..0000000000 --- a/src/status_im/chat/views/suggestions.cljs +++ /dev/null @@ -1,130 +0,0 @@ -(ns status-im.chat.views.suggestions - (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch]] - [status-im.components.react :refer [view - scroll-view - text - icon - image - touchable-highlight - list-view - list-item - animated-view]] - [status-im.utils.listview :refer [to-datasource]] - [status-im.chat.styles.suggestions :as st] - [status-im.chat.styles.dragdown :as ddst] - [reagent.core :as r] - [status-im.components.animation :as anim] - [status-im.components.drag-drop :as drag] - [status-im.utils.platform :refer [ios?]] - [status-im.chat.suggestions-responder :as resp] - [status-im.chat.constants :as chat-consts] - [status-im.i18n :refer [label]] - [status-im.chat.views.response :as response])) - -(defn set-command-input [command] - (dispatch [:set-chat-command command])) - -(defview request-item [{:keys [type message-id]}] - [{:keys [color description] - icon-path :icon - :as response} [:get-response type] - {:keys [name chat-id]} [:get-current-chat] - {:keys [added]} [:get-request message-id]] - [touchable-highlight - {:on-press #(dispatch [:set-response-chat-command message-id type])} - [view st/request-container - [view st/request-icon-container - [view (st/request-icon-background color) - (when icon-path - [icon icon-path st/request-icon])]] - [view st/request-info-container - [text {:style st/request-info-description} description] - (when added - [text {:style st/request-message-info} - (response/request-info-text name chat-id added)])]]]) - -(defn suggestion-list-item - [[command {:keys [title description] - name :name - :as suggestion}]] - (let [label (str chat-consts/command-char name)] - [touchable-highlight - {:onPress #(set-command-input command) - :style st/suggestion-highlight} - [view st/suggestion-container - [view st/suggestion-sub-container - [view st/command-description-container - [text {:style st/value-text} title] - [text {:style st/description-text} description]] - [view st/command-label-container - [view (st/suggestion-background suggestion) - [text {:style st/suggestion-text} label]]]]]])) - -(defn title [s] - [view st/title-container - [text {:style st/title-text} s]]) - -(defview suggestions-view [] - [suggestions [:get-suggestions] - requests [:get-requests]] - [view {:flex 1} - [scroll-view {:keyboardShouldPersistTaps true} - (when (seq requests) - [title (label :t/suggestions-requests)]) - (when (seq requests) - (for [{:keys [chat-id message-id] :as request} requests] - ^{:key [chat-id message-id]} - [request-item request])) - [title (label :t/suggestions-commands)] - (for [suggestion (remove #(nil? (:title (second %))) suggestions)] - ^{:key (first suggestion)} - [suggestion-list-item suggestion])]]) - -(defn header [h] - (let [layout-height (subscribe [:max-layout-height :default]) - pan-responder (resp/pan-responder h - layout-height - :fix-commands-suggestions-height)] - (fn [_] - [view - (merge (drag/pan-handlers pan-responder) - {:style ddst/drag-down-touchable}) - [view st/header-icon]]))) - -(defn container-animation-logic [{:keys [to-value val animate?]}] - (when-let [to-value @to-value] - (let [max-layout-height (subscribe [:max-layout-height :default]) - to-value (min to-value (max 0 @max-layout-height))] - (when-not (= to-value (.-_value val)) - (if (or (nil? @animate?) @animate?) - (anim/start (anim/spring val {:toValue to-value})) - (anim/set-value val to-value)))))) - -(defn container [h & _] - (let [;; todo to-response-height, cur-response-height must be specific - ;; for each chat - to-response-height (subscribe [:command-suggestions-height]) - input-margin (subscribe [:input-margin]) - changed (subscribe [:animations :commands-height-changed]) - animate? (subscribe [:animate?]) - context {:to-value to-response-height - :val h - :animate? animate?} - on-update #(container-animation-logic context)] - (r/create-class - {:component-did-mount - on-update - :component-did-update - on-update - :reagent-render - (fn [h & elements] - @to-response-height @changed - (into [animated-view {:style (st/container h @input-margin)}] elements))}))) - -(defview suggestion-container [] - (let [h (anim/create-value chat-consts/input-height)] - [container h - [header h] - [suggestions-view] - [view {:height chat-consts/input-height}]])) diff --git a/src/status_im/chats_list/views/inner_item.cljs b/src/status_im/chats_list/views/inner_item.cljs index 157f8b22bc..8172c2cb38 100644 --- a/src/status_im/chats_list/views/inner_item.cljs +++ b/src/status_im/chats_list/views/inner_item.cljs @@ -26,7 +26,7 @@ (fn [] (when (and (get-in @message [:content :command]) (not @preview)) - (dispatch [:request-command-preview @message :short-preview]))) + (dispatch [:request-command-data @message :short-preview]))) :reagent-render (fn [_] @@ -50,7 +50,7 @@ (:content content)] (:command content) - preview + (:markup preview) :else [text {:style st/last-message-text diff --git a/src/status_im/commands/handlers/jail.cljs b/src/status_im/commands/handlers/jail.cljs index bdacb7b0d3..5535a7f59c 100644 --- a/src/status_im/commands/handlers/jail.cljs +++ b/src/status_im/commands/handlers/jail.cljs @@ -1,6 +1,6 @@ (ns status-im.commands.handlers.jail (:require [re-frame.core :refer [after dispatch subscribe trim-v debug]] - [status-im.utils.handlers :as u] + [status-im.utils.handlers :as handlers] [status-im.utils.utils :refer [http-get show-popup]] [status-im.utils.types :refer [json->clj]] [status-im.commands.utils :refer [generate-hiccup reg-handler]] @@ -9,12 +9,8 @@ [status-im.models.commands :as cm] [status-im.constants :refer [console-chat-id]] [status-im.i18n :refer [get-contact-translated]] - [taoensso.timbre :as log])) - -(defn render-command - [db [chat-id message-id markup]] - (let [hiccup (generate-hiccup markup)] - (assoc-in db [:rendered-commands chat-id message-id] hiccup))) + [taoensso.timbre :as log] + [status-im.commands.utils :as cu])) (defn command-handler! [_ [chat-id @@ -22,12 +18,10 @@ {:keys [result error]}]] (let [{:keys [context returned]} result {handler-error :error} returned] - (log/debug "command handler: " result error parameters) (cond handler-error - (log/debug :error-from-handler handler-error - :chat-id chat-id - :command command-message) + (when-let [markup (:markup handler-error)] + (dispatch [:set-chat-ui-props :validation-messages (cu/generate-hiccup markup)])) result (let [command' (assoc command-message :handler-data returned) @@ -41,50 +35,38 @@ :else nil))) -(defn suggestions-handler! - [{:keys [contacts chats] :as db} [{:keys [chat-id]} {:keys [result]}]] - (let [{:keys [markup webViewUrl]} (:returned result) - {:keys [dapp? dapp-url]} (get contacts chat-id) - text (get-in chats [chat-id :input-text]) - hiccup (when-not (s/blank? text) (generate-hiccup markup)) - web-view-url (if (and (= webViewUrl "dapp-url") dapp? dapp-url) - (get-contact-translated chat-id :dapp-url dapp-url) - webViewUrl)] - (-> db - (assoc-in [:suggestions chat-id] hiccup) - (assoc-in [:web-view-url chat-id] web-view-url) - (assoc-in [:has-suggestions? chat-id] (or hiccup web-view-url))))) - -(defn suggestions-events-handler! - [{:keys [current-chat-id] :as db} [[n data]]] - (log/debug "Suggestion event: " data) - (let [{:keys [dapp?]} (get-in db [:contacts current-chat-id]) - command? (= :command (:type (cm/get-chat-command db)))] - (case (keyword n) - :set-value (if command? - (dispatch [:fill-chat-command-content data]) - (when dapp? - (dispatch [:set-chat-input-text data]))) - ;; todo show error? - nil))) - (defn print-error-message! [message] (fn [_ params] (when (:error (last params)) (show-popup "Error" (s/join "\n" [message params])) (log/debug message params)))) -(reg-handler ::render-command render-command) - (reg-handler :command-handler! (after (print-error-message! "Error on command handling")) - (u/side-effect! command-handler!)) + (handlers/side-effect! command-handler!)) -(reg-handler :suggestions-handler - [(after #(dispatch [:animate-show-response])) - (after (print-error-message! "Error on param suggestions"))] - suggestions-handler!) -(reg-handler :suggestions-event! (u/side-effect! suggestions-events-handler!)) +(reg-handler + :suggestions-handler + [(after (print-error-message! "Error on param suggestions"))] + (fn [{:keys [contacts chats] :as db} [{:keys [chat-id command parameter-index result]}]] + (let [{:keys [markup]} (get-in result [:result :returned]) + {:keys [dapp? dapp-url]} (get contacts chat-id) + hiccup (generate-hiccup markup) + path (if command + [:chats chat-id :parameter-boxes (:name command) parameter-index] + [:chats chat-id :parameter-boxes :message])] + (assoc-in db path (when hiccup + {:hiccup hiccup}))))) + +(reg-handler + :suggestions-event! + (handlers/side-effect! + (fn [{:keys [current-chat-id] :as db} [[n arg]]] + (let [{:keys [dapp?]} (get-in db [:contacts current-chat-id])] + (case (keyword n) + :set-command-argument (dispatch [:set-command-argument arg]) + :set-value (dispatch [:set-chat-input-text arg]) + nil))))) (reg-handler :set-local-storage (fn [{:keys [current-chat-id] :as db} [{:keys [data] :as event}]] diff --git a/src/status_im/commands/handlers/loading.cljs b/src/status_im/commands/handlers/loading.cljs index 91472244f8..8cc292bfc3 100644 --- a/src/status_im/commands/handlers/loading.cljs +++ b/src/status_im/commands/handlers/loading.cljs @@ -139,6 +139,7 @@ [(path :chats) (after save-commands-js!) (after #(dispatch [:check-autorun])) + (after #(dispatch [:update-suggestions])) (after (fn [_ [id]] (dispatch [:invoke-commands-loading-callbacks id]) (dispatch [:invoke-chat-loaded-callbacks id])))] diff --git a/src/status_im/commands/utils.cljs b/src/status_im/commands/utils.cljs index 6ed45cd2bf..599fd645c7 100644 --- a/src/status_im/commands/utils.cljs +++ b/src/status_im/commands/utils.cljs @@ -1,24 +1,31 @@ (ns status-im.commands.utils (:require [clojure.set :as set] [clojure.walk :as w] - [status-im.components.react :refer [text scroll-view view web-view - image touchable-highlight]] + [status-im.components.react :refer [text + scroll-view + view + web-view + image + touchable-highlight]] + [status-im.chat.views.input.web-view :as chat-web-view] + [status-im.chat.views.input.validation-messages :as chat-validation-messages] [re-frame.core :refer [dispatch trim-v debug]] - [status-im.utils.handlers :refer [register-handler]])) - -(def command-prefix "c ") + [status-im.utils.handlers :refer [register-handler]] + [taoensso.timbre :as log])) (defn json->clj [json] (when-not (= json "undefined") (js->clj (.parse js/JSON json) :keywordize-keys true))) (def elements - {:text text - :view view - :scroll-view scroll-view - :web-view web-view - :image image - :touchable touchable-highlight}) + {:text text + :view view + :scroll-view scroll-view + :web-view web-view + :image image + :touchable touchable-highlight + :bridged-web-view chat-web-view/bridged-web-view + :validation-message chat-validation-messages/validation-message}) (defn get-element [n] (elements (keyword (.toLowerCase n)))) diff --git a/src/status_im/components/list_selection.cljs b/src/status_im/components/list_selection.cljs index 299f4f83a9..f716215845 100644 --- a/src/status_im/components/list_selection.cljs +++ b/src/status_im/components/list_selection.cljs @@ -32,9 +32,9 @@ :callback (fn [index] (case index 0 (do - (dispatch [:set-chat-command :browse]) - (dispatch [:fill-chat-command-content link]) - (js/setTimeout #(dispatch [:send-command!]) 500)) + (dispatch [:select-chat-input-command {:name "browse" + :prefill [link]}]) + (js/setTimeout #(dispatch [:send-current-message]) 500)) 1 (.openURL linking link) :default)) :cancel-text (label :t/browsing-cancel)}))) diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index 841e932fcf..b897705b61 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -3,7 +3,8 @@ [status-im.components.styles :as st] [status-im.utils.utils :as u :refer [get-react-property get-class adapt-class]] - [status-im.utils.platform :refer [platform-specific ios?]])) + [status-im.utils.platform :refer [platform-specific]] + [status-im.i18n :as i18n])) (def react-native (js/require "react-native")) (def native-modules (.-NativeModules react-native)) @@ -79,7 +80,7 @@ [text-input-class (merge {:underline-color-android :transparent :placeholder-text-color st/text2-color - :placeholder "Type" + :placeholder (i18n/label :t/type-a-message) :value text} (-> opts (dissoc :font) @@ -88,8 +89,9 @@ (defn icon ([n] (icon n st/icon-default)) ([n style] - [image {:source {:uri (keyword (str "icon_" (name n)))} - :style style}])) + [image {:source {:uri (keyword (str "icon_" (name n)))} + :resizeMode "contain" + :style style}])) (defn list-view [props] [list-view-class (merge {:enableEmptySections true} props)]) diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index e3216be35a..2bc04149dc 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -44,6 +44,8 @@ (def separator-color "#0000001f") (def default-chat-color color-purple) +;;rgb 237 241 243 + (def flex {:flex 1}) diff --git a/src/status_im/data_store/messages.cljs b/src/status_im/data_store/messages.cljs index f7ea680e87..cc6e746b2b 100644 --- a/src/status_im/data_store/messages.cljs +++ b/src/status_im/data_store/messages.cljs @@ -47,6 +47,11 @@ (some-> (data-store/get-by-id message-id) (clojure.core/update :user-statuses user-statuses-to-map))) +(defn get-message-content-by-id [message-id] + (when-let [{:keys [content-type content] :as message} (get-by-id message-id)] + (when (command-type? content-type) + (str-to-map content)))) + (defn get-messages [messages] (->> messages diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index 153127deaa..3d8c53dd85 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -33,16 +33,12 @@ :contacts-ids #{} :selected-contacts #{} :chats-updated-signal 0 - :chat-ui-props {:show-actions? false - :show-bottom-info? false} :selected-participants #{} :view-id nil :navigation-stack '() :current-tag nil :qr-codes {} :keyboard-height 0 - :animations {;; todo clear this - } :loading-allowed true :sync-state :done diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index 0d4a01d122..ba459c6d0a 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -42,10 +42,6 @@ (register-handler :set-in set-in) -(register-handler :set-animation - (fn [db [_ k v]] - (assoc-in db [:animations k] v))) - (register-handler :initialize-db (fn [{:keys [status-module-initialized? status-node-started? network-status network]} _] diff --git a/src/status_im/ios/platform.cljs b/src/status_im/ios/platform.cljs index 473c7f4caa..284498a2d8 100644 --- a/src/status_im/ios/platform.cljs +++ b/src/status_im/ios/platform.cljs @@ -84,7 +84,8 @@ :medium {:font-family "SFUIText-Medium"} :bold {:font-family "SFUIText-Bold"} - :toolbar-title {:font-family "SFUIText-Semibold"}}) + :toolbar-title {:font-family "SFUIText-Semibold"} + :roboto-mono {:font-family "RobotoMono-Medium"}}) ;; Dialogs diff --git a/src/status_im/models/commands.cljs b/src/status_im/models/commands.cljs index e9595012e8..2f3887e373 100644 --- a/src/status_im/models/commands.cljs +++ b/src/status_im/models/commands.cljs @@ -2,83 +2,6 @@ (:require [status-im.db :as db] [tailrecursion.priority-map :refer [priority-map-by]])) -(defn get-commands [{:keys [current-chat-id] :as db}] - (or (get-in db [:chats current-chat-id :commands]) {})) - -(defn get-response-or-command - [type {:keys [current-chat-id] :as db} command-key] - ((or (get-in db [:chats current-chat-id type]) {}) command-key)) - -(defn get-chat-command-content - [{:keys [current-chat-id] :as db}] - (get-in db (db/chat-command-content-path current-chat-id))) - -(defn set-chat-command-content - [{:keys [current-chat-id] :as db} content] - (assoc-in db (db/chat-command-content-path current-chat-id) content)) - -(defn set-command-parameter - [{:keys [current-chat-id] :as db} name value] - (assoc-in db [:chats current-chat-id :command-input :params name] value)) - -(defn get-chat-command - [{:keys [current-chat-id] :as db}] - (get-in db (db/chat-command-path current-chat-id))) - -(defn get-command-input [{:keys [current-chat-id] :as db}] - (get-in db [:chats current-chat-id :command-input])) - -(defn add-params [command params] - (let [command-params (:params command) - command-params (vec (map (fn [param] - (let [param-key (keyword (:name param)) - value (get params param-key)] - (assoc param :value value))) command-params))] - (assoc command :params command-params))) - -(defn set-command-input - ([db type command-key] - (set-command-input db type nil command-key)) - ([db type message-id command-key] - (set-command-input db type message-id command-key nil)) - ([{:keys [current-chat-id] :as db} type message-id command-key params] - (let [command (get-response-or-command type db command-key) - command' (add-params command params) - first-parameter (get (:params command') 0) - value (:value first-parameter)] - (update-in db [:chats current-chat-id :command-input] merge - {:content value - :command command' - :parameter-idx 0 - :params params - :to-message-id message-id})))) - -(defn get-command-parameter-index - ([{:keys [current-chat-id] :as db}] - (get-command-parameter-index db current-chat-id)) - ([db chat-id] - (get-in db [:chats chat-id :command-input :parameter-idx]))) - -(defn next-command-parameter - [{:keys [current-chat-id] :as db}] - (let [parameter-index (get-command-parameter-index db) - command (get-chat-command db) - next-parameter (get (:params command) (inc parameter-index)) - value (:value next-parameter)] - (-> db - (update-in [:chats current-chat-id :command-input :parameter-idx] inc) - (set-chat-command-content value)))) - - -(defn get-chat-command-to-message-id - [{:keys [current-chat-id] :as db}] - (get-in db (db/chat-command-to-message-id-path current-chat-id))) - -(defn get-chat-command-request - [{:keys [current-chat-id] :as db}] - (get-in db (db/chat-command-request-path current-chat-id - (get-chat-command-to-message-id db)))) - (defn parse-command-message-content [commands content] (if (map? content) (update content :command #((keyword %) commands)) diff --git a/src/status_im/profile/handlers.cljs b/src/status_im/profile/handlers.cljs index 0d248257b7..31e0199608 100644 --- a/src/status_im/profile/handlers.cljs +++ b/src/status_im/profile/handlers.cljs @@ -43,13 +43,13 @@ (u/side-effect! (fn [db _] (dispatch [:navigate-to :chat console-chat-id]) - (dispatch [:set-chat-command :phone])))) + (js/setTimeout #(dispatch [:select-chat-input-command {:name "phone"}]) 500)))) (register-handler :open-chat-with-the-send-transaction (u/side-effect! (fn [db [_ chat-id]] (dispatch [:navigate-to :chat chat-id]) - (dispatch [:set-chat-command :send])))) + (js/setTimeout #(dispatch [:select-chat-input-command {:name "send"}]) 500)))) (defn prepare-edit-profile [{:keys [current-account-id] :as db} _] diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index a79860c48a..3bfdfa9f77 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -23,10 +23,6 @@ (fn [db [_ path]] (reaction (get-in @db path)))) -(register-sub :animations - (fn [db [_ k]] - (reaction (get-in @db [:animations k])))) - (register-sub :signed-up? (fn [] (let [account-id (subscribe [:get :current-account-id]) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 2a363a3a74..9460c88576 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -11,6 +11,8 @@ :search-for "Search for..." :cancel "Cancel" :next "Next" + :type-a-message "Type a message..." + :type-a-command "Start typing a command..." ;drawer :invite-friends "Invite friends" diff --git a/src/status_im/utils/js_resources.cljs b/src/status_im/utils/js_resources.cljs index 0f7e019596..a5d17ab8fa 100644 --- a/src/status_im/utils/js_resources.cljs +++ b/src/status_im/utils/js_resources.cljs @@ -8,7 +8,7 @@ (def commands-js (slurp "resources/commands.js")) (def console-js (slurp "resources/console.js")) (def status-js (slurp "resources/status.js")) -(def wallet-js (str commands-js (slurp "resources/wallet.js"))) +(def wallet-js (slurp "resources/wallet.js")) (def dapp-js (str (slurp "resources/dapp.js"))) (def webview-js (slurp "resources/webview.js")) From 35210f043ddb8dfb8350965f4c3681e96cfe605f Mon Sep 17 00:00:00 2001 From: alwx Date: Thu, 6 Apr 2017 13:33:30 +0300 Subject: [PATCH 33/48] Request auto-selection on typing [chat-ui] --- src/status_im/chat/models/input.cljs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs index a9132ae16c..d1c78672f7 100644 --- a/src/status_im/chat/models/input.cljs +++ b/src/status_im/chat/models/input.cljs @@ -58,14 +58,14 @@ command-args (split-command-args input-text) command-name (first command-args)] (when (.startsWith (or command-name "") const/command-char) - (when-let [command (-> (filter (fn [[{:keys [name]} message-id]] - (and (= name (subs command-name 1)) - (= message-id (or (:to-message-id input-metadata) - :any)))) - possible-actions) - (ffirst))] + (when-let [[command to-message-id] (-> (filter (fn [[{:keys [name]} message-id]] + (= name (subs command-name 1))) + possible-actions) + (first))] {:command command - :metadata input-metadata + :metadata (if (not= :any to-message-id) + (assoc input-metadata :to-message-id to-message-id) + input-metadata) :args (remove empty? (rest command-args))})))) ([{:keys [current-chat-id] :as db} chat-id] (selected-chat-command db chat-id (get-in db [:chats chat-id :input-text])))) From 6e4931417b70d3deb3f11227a7a846d61f38d26f Mon Sep 17 00:00:00 2001 From: alwx Date: Fri, 7 Apr 2017 01:09:55 +0300 Subject: [PATCH 34/48] Password and phone inputs [chat-ui] --- env/dev/env/android/main.cljs | 2 +- env/dev/env/ios/main.cljs | 2 +- externs/externs.js | 5 +- resources/console.js | 59 ++++--- resources/status.js | 1 + src/status_im/chat/handlers/input.cljs | 153 ++++++++++++------ src/status_im/chat/models/input.cljs | 114 ++++++------- src/status_im/chat/models/password_input.cljs | 48 ------ src/status_im/chat/styles/input/input.cljs | 16 +- src/status_im/chat/subs.cljs | 10 +- src/status_im/chat/views/input/input.cljs | 125 ++++++++------ 11 files changed, 293 insertions(+), 242 deletions(-) delete mode 100644 src/status_im/chat/models/password_input.cljs diff --git a/env/dev/env/android/main.cljs b/env/dev/env/android/main.cljs index cc3b4f7493..f2554e135d 100644 --- a/env/dev/env/android/main.cljs +++ b/env/dev/env/android/main.cljs @@ -19,6 +19,6 @@ :heads-up-display false :jsload-callback callback) -(rr/enable-re-frisk-remote!) +(rr/enable-re-frisk-remote! {:host "10.0.2.2:4567"}) (core/init) diff --git a/env/dev/env/ios/main.cljs b/env/dev/env/ios/main.cljs index 276a16026d..0a66fc0d23 100644 --- a/env/dev/env/ios/main.cljs +++ b/env/dev/env/ios/main.cljs @@ -16,6 +16,6 @@ :heads-up-display false :jsload-callback #(swap! cnt inc)) -(rr/enable-re-frisk-remote!) +(rr/enable-re-frisk-remote! {:host "localhost:4567"}) (core/init) \ No newline at end of file diff --git a/externs/externs.js b/externs/externs.js index 2e75a0638f..de0491a06d 100644 --- a/externs/externs.js +++ b/externs/externs.js @@ -1,9 +1,11 @@ var TopLevel = { +"abs" : function () {}, "ActionSheetIOS" : function () {}, "addEntropy" : function () {}, "addEventListener" : function () {}, "addListener" : function () {}, "addOrientationListener" : function () {}, +"addSymKey" : function () {}, "Alert" : function () {}, "alert" : function () {}, "Animated" : function () {}, @@ -81,13 +83,13 @@ var TopLevel = { "goog" : function () {}, "guid" : function () {}, "hash" : function () {}, +"hasSymKey" : function () {}, "headers" : function () {}, "height" : function () {}, "hex" : function () {}, "hide" : function () {}, "HttpProvider" : function () {}, "IBGLog" : function () {}, -"indexOf" : function () {}, "initialPage" : function () {}, "initJail" : function () {}, "isAddress" : function () {}, @@ -196,6 +198,7 @@ var TopLevel = { "toAscii" : function () {}, "toBits" : function () {}, "toDecimal" : function () {}, +"toHex" : function () {}, "toLocaleString" : function () {}, "toLowerCase" : function () {}, "toNumber" : function () {}, diff --git a/resources/console.js b/resources/console.js index 4b5fcd7d57..6a945e7ba3 100644 --- a/resources/console.js +++ b/resources/console.js @@ -10,7 +10,7 @@ I18n.translations = { password_description: 'Password', password_placeholder: 'Type your password', - password_placeholder2: 'Please re-enter password to confirm', + password_placeholder2: 'Confirm', password_error: 'Password should be not less then 6 symbols.', password_error1: 'Password confirmation doesn\'t match password.', password_validation_title: 'Password', @@ -1653,6 +1653,7 @@ var phoneConfig = { color: "#5bb2a2", title: I18n.t('phone_title'), description: I18n.t('phone_description'), + sequentialParams: true, validator: function (params) { return { validationHandler: "phone", @@ -1872,32 +1873,40 @@ status.response({ color: "#7099e6", description: I18n.t('password_description'), icon: "lock_white", - params: [{ - name: "password", - type: status.types.PASSWORD, - placeholder: I18n.t('password_placeholder'), - hidden: true - }, { - name: "password_confirmation", - type: status.types.PASSWORD, - placeholder: "Confirm", - hidden: true - }], + sequentialParams: true, + params: [ + { + name: "password", + type: status.types.PASSWORD, + placeholder: I18n.t('password_placeholder'), + hidden: true + }, + { + name: "password-confirmation", + type: status.types.PASSWORD, + placeholder: I18n.t('password_placeholder2'), + hidden: true + } + ], validator: function (params, context) { - if (params["password_confirmation"] != params["password"]) { - var error = status.components.validationMessage( - I18n.t('password_validation_title'), - I18n.t('password_error1') - ); - return {markup: error}; - } - if (params.password.length < 6) { - var error = status.components.validationMessage( - I18n.t('password_validation_title'), - I18n.t('password_error') - ); - return {markup: error}; + if (!params.hasOwnProperty("password-confirmation") || params["password-confirmation"].length === 0) { + if (params.password === null || params.password.length < 6) { + var error = status.components.validationMessage( + I18n.t('password_validation_title'), + I18n.t('password_error') + ); + return {markup: error}; + } + } else { + if (params.password !== params["password-confirmation"]) { + var error = status.components.validationMessage( + I18n.t('password_validation_title'), + I18n.t('password_error1') + ); + return {markup: error}; + } } + }, preview: function (params, context) { var style = { diff --git a/resources/status.js b/resources/status.js index 00a04e61b8..5cda037319 100644 --- a/resources/status.js +++ b/resources/status.js @@ -36,6 +36,7 @@ Command.prototype.create = function (com) { this["on-send"] = com.onSend; this.fullscreen = com.fullscreen; this.request = com.request; + this["sequential-params"] = com.sequentialParams; this.addToCatalog(); return this; diff --git a/src/status_im/chat/handlers/input.cljs b/src/status_im/chat/handlers/input.cljs index cd69500c54..a5d19cdfb0 100644 --- a/src/status_im/chat/handlers/input.cljs +++ b/src/status_im/chat/handlers/input.cljs @@ -3,7 +3,6 @@ [taoensso.timbre :as log] [status-im.chat.constants :as const] [status-im.chat.models.input :as input-model] - [status-im.chat.models.password-input :as password-input] [status-im.chat.models.suggestions :as suggestions] [status-im.components.react :as react-comp] [status-im.components.status :as status] @@ -16,27 +15,17 @@ (handlers/register-handler :set-chat-input-text (fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]] - (let [chat-id (or chat-id current-chat-id) - selection (get-in chat-ui-props [chat-id :selection])] + (let [chat-id (or chat-id current-chat-id) + ends-with-space? (input-model/text-ends-with-space? text)] (dispatch [:update-suggestions chat-id text]) (if-let [{command :command} (input-model/selected-chat-command db chat-id text)] (let [{old-args :args} (input-model/selected-chat-command db chat-id) - text-splitted (input-model/split-command-args text) - new-args (rest text-splitted) - modifiers (input-model/add-modifiers (:params command) new-args) - addition (if (input-model/text-ends-with-space? text) - const/spacing-char) - new-params {:modified-text (str (input-model/apply-modifiers text-splitted modifiers) - addition) - :input-text (str (input-model/make-input-text modifiers - text-splitted - old-args - selection) - addition)}] - (update-in db [:chats chat-id] merge new-params)) - (update-in db [:chats chat-id] merge {:input-text text - :modified-text nil}))))) + text-splitted (input-model/split-command-args text) + new-args (rest text-splitted) + new-input-text (input-model/make-input-text text-splitted old-args)] + (assoc-in db [:chats chat-id :input-text] new-input-text)) + (assoc-in db [:chats chat-id :input-text] text))))) (handlers/register-handler :add-to-chat-input-text @@ -58,7 +47,11 @@ (dispatch [:set-chat-ui-props :result-box nil]) (dispatch [:set-chat-ui-props :validation-messages nil]) (dispatch [:load-chat-parameter-box command 0]) - (dispatch [:chat-input-focus])))) + (if (:sequential-params command) + (js/setTimeout + #(dispatch [:chat-input-focus :seq-input-ref]) + 100) + (dispatch [:chat-input-focus :input-ref]))))) (handlers/register-handler :set-chat-input-metadata @@ -72,22 +65,29 @@ (fn [{:keys [current-chat-id] :as db} [_ [index arg]]] (let [command (-> (get-in db [:chats current-chat-id :input-text]) (input-model/split-command-args)) - command-name (first command) - command-args (into [] (rest command)) - command-args (if (< index (count command-args)) - (assoc command-args index arg) - (conj command-args arg))] - (dispatch [:set-chat-input-text (str command-name - const/spacing-char - (input-model/join-command-args command-args) - const/spacing-char)]))))) + seq-params? (-> (input-model/selected-chat-command db current-chat-id) + (get-in [:command :sequential-params]))] + (if seq-params? + (dispatch [:set-chat-seq-arg-input-text arg]) + (let [command-name (first command) + command-args (into [] (rest command)) + command-args (if (< index (count command-args)) + (assoc command-args index arg) + (conj command-args arg))] + (dispatch [:set-chat-input-text (str command-name + const/spacing-char + (input-model/join-command-args command-args) + const/spacing-char)]))))))) (handlers/register-handler :chat-input-focus (handlers/side-effect! - (fn [{:keys [current-chat-id chat-ui-props] :as db}] - (when-let [ref (get-in chat-ui-props [current-chat-id :input-ref])] - (.focus ref))))) + (fn [{:keys [current-chat-id chat-ui-props] :as db} [_ ref]] + (try + (when-let [ref (get-in chat-ui-props [current-chat-id ref])] + (.focus ref)) + (catch :default e + (log/debug "Cannot focus the reference")))))) (handlers/register-handler :update-suggestions @@ -152,34 +152,35 @@ ::proceed-command (handlers/side-effect! (fn [db [_ command chat-id]] - (dispatch [::request-command-data - {:command command - :chat-id chat-id - :data-type :validator - :after #(dispatch [::proceed-validation-messages command chat-id %2])}])))) + (let [after-validation #(dispatch [::request-command-data + {:command command + :chat-id chat-id + :data-type :on-send + :after (fn [_ res] + (dispatch [::send-command res command chat-id]))}])] + (dispatch [::request-command-data + {:command command + :chat-id chat-id + :data-type :validator + :after #(dispatch [::proceed-validation-messages + command chat-id %2 after-validation])}]))))) (handlers/register-handler ::proceed-validation-messages (handlers/side-effect! - (fn [db [_ command chat-id {:keys [markup validationHandler parameters] :as errors}]] + (fn [db [_ command chat-id {:keys [markup validationHandler parameters] :as errors} proceed-fn]] (let [set-errors #(do (dispatch [:set-chat-ui-props :validation-messages %]) - (dispatch [:set-chat-ui-props :sending-in-progress? false])) - proceed #(dispatch [::request-command-data - {:command command - :chat-id chat-id - :data-type :on-send - :after (fn [_ res] - (dispatch [::send-command res command chat-id]))}])] + (dispatch [:set-chat-ui-props :sending-in-progress? false]))] (cond markup (set-errors markup) validationHandler - (do (dispatch [::execute-validation-handler validationHandler parameters set-errors proceed]) + (do (dispatch [::execute-validation-handler validationHandler parameters set-errors proceed-fn]) (dispatch [:set-chat-ui-props :sending-in-progress? false])) :default - (proceed)))))) + (proceed-fn)))))) (handlers/register-handler ::execute-validation-handler @@ -236,11 +237,19 @@ :send-current-message (handlers/side-effect! (fn [{:keys [current-chat-id] :as db} [_ chat-id]] + (dispatch [:set-chat-ui-props :sending-in-progress? true]) (let [chat-id (or chat-id current-chat-id) - chat-command (input-model/selected-chat-command db chat-id)] - (if chat-command + chat-command (input-model/selected-chat-command db chat-id) + seq-command? (get-in chat-command [:command :sequential-params]) + chat-command (if seq-command? + (let [args (get-in db [:chats chat-id :seq-arguments])] + (assoc chat-command :args args)) + (update chat-command :args #(remove str/blank? %)))] + (if (:command chat-command) (if (= :complete (input-model/command-completion chat-command)) - (dispatch [::proceed-command chat-command chat-id]) + (do + (dispatch [::proceed-command chat-command chat-id]) + (dispatch [:clear-seq-arguments chat-id])) (let [text (get-in db [:chats chat-id :input-text])] (dispatch [:set-chat-ui-props :sending-in-progress? false]) (when-not (input-model/text-ends-with-space? text) @@ -261,4 +270,48 @@ params (fn [{:keys [result] :as data}] (dispatch [:suggestions-handler {:chat-id chat-id - :result data}]))))))) \ No newline at end of file + :result data}]))))))) + +(handlers/register-handler + :clear-seq-arguments + (fn [{:keys [current-chat-id chats] :as db} [_ chat-id]] + (let [chat-id (or chat-id current-chat-id)] + (-> db + (assoc-in [:chats chat-id :seq-arguments] []) + (assoc-in [:chats chat-id :seq-argument-input-text] nil))))) + +(handlers/register-handler + :update-seq-arguments + (fn [{:keys [current-chat-id chats] :as db} [_ chat-id]] + (let [chat-id (or chat-id current-chat-id) + text (get-in chats [chat-id :seq-argument-input-text])] + (-> db + (update-in [:chats chat-id :seq-arguments] #(into [] (conj % text))) + (assoc-in [:chats chat-id :seq-argument-input-text] nil))))) + +(handlers/register-handler + :send-seq-argument + (handlers/side-effect! + (fn [{:keys [current-chat-id chats] :as db} [_ chat-id]] + (let [chat-id (or chat-id current-chat-id) + text (get-in chats [chat-id :seq-argument-input-text]) + seq-arguments (get-in db [:chats chat-id :seq-arguments]) + command (-> (input-model/selected-chat-command db chat-id) + (assoc :args (into [] (conj seq-arguments text)))) + args (get-in chats [chat-id :seq-arguments]) + after-validation #(do + (dispatch [:update-seq-arguments chat-id]) + (dispatch [:send-current-message]))] + (dispatch [::request-command-data + {:command command + :chat-id chat-id + :data-type :validator + :after #(do + (dispatch [::proceed-validation-messages + command chat-id %2 after-validation]))}]))))) + +(handlers/register-handler + :set-chat-seq-arg-input-text + (fn [{:keys [current-chat-id] :as db} [_ text chat-id]] + (let [chat-id (or chat-id current-chat-id)] + (assoc-in db [:chats chat-id :seq-argument-input-text] text)))) \ No newline at end of file diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs index d1c78672f7..b933d74ae3 100644 --- a/src/status_im/chat/models/input.cljs +++ b/src/status_im/chat/models/input.cljs @@ -2,15 +2,15 @@ (:require [clojure.string :as str] [status-im.components.react :as rc] [status-im.chat.constants :as const] - [status-im.chat.models.password-input :as password-input] [status-im.chat.views.input.validation-messages :refer [validation-message]] [status-im.i18n :as i18n] [status-im.utils.phone-number :as phone-number] [taoensso.timbre :as log])) (defn text-ends-with-space? [text] - (= (str/last-index-of text const/spacing-char) - (dec (count text)))) + (when text + (= (str/last-index-of text const/spacing-char) + (dec (count text))))) (defn possible-chat-actions [db chat-id] (let [{:keys [commands requests]} (get-in db [:chats chat-id]) @@ -25,22 +25,27 @@ (into commands responses))) (defn split-command-args [command-text] - (let [splitted (str/split command-text const/spacing-char)] - (first - (reduce (fn [[list command-started?] arg] - (let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg)) - has-quote? (and (= quotes-count 1) - (str/index-of arg const/arg-wrapping-char)) - arg (str/replace arg #"\"" "") - new-list (if command-started? - (let [index (dec (count list))] - (update list index str const/spacing-char arg)) - (conj list arg)) - command-continues? (or (and command-started? (not has-quote?)) - (and (not command-started?) has-quote?))] - [new-list command-continues?])) - [[] false] - splitted)))) + (let [space? (text-ends-with-space? command-text) + command-text (if space? + (str command-text ".") + command-text) + splitted (cond-> (str/split command-text const/spacing-char) + space? (drop-last))] + (->> splitted + (reduce (fn [[list command-started?] arg] + (let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg)) + has-quote? (and (= quotes-count 1) + (str/index-of arg const/arg-wrapping-char)) + arg (str/replace arg #"\"" "") + new-list (if command-started? + (let [index (dec (count list))] + (update list index str const/spacing-char arg)) + (conj list arg)) + command-continues? (or (and command-started? (not has-quote?)) + (and (not command-started?) has-quote?))] + [new-list command-continues?])) + [[] false]) + (first)))) (defn join-command-args [args] (->> args @@ -54,6 +59,7 @@ ([{:keys [current-chat-id] :as db} chat-id input-text] (let [chat-id (or chat-id current-chat-id) input-metadata (get-in db [:chats chat-id :input-metadata]) + seq-arguments (get-in db [:chats chat-id :seq-arguments]) possible-actions (possible-chat-actions db chat-id) command-args (split-command-args input-text) command-name (first command-args)] @@ -66,24 +72,33 @@ :metadata (if (not= :any to-message-id) (assoc input-metadata :to-message-id to-message-id) input-metadata) - :args (remove empty? (rest command-args))})))) + :args (if (empty? seq-arguments) + (rest command-args) + seq-arguments)})))) ([{:keys [current-chat-id] :as db} chat-id] (selected-chat-command db chat-id (get-in db [:chats chat-id :input-text])))) (defn current-chat-argument-position - [{:keys [args] :as command} input-text] + [{:keys [args] :as command} input-text seq-arguments] (if command - (let [current (count args)] - (if (= (last input-text) const/spacing-char) - current - (dec current))) + (let [args-count (count args)] + (cond + (:sequential-params command) + (count seq-arguments) + + (= (last input-text) const/spacing-char) + args-count + + :default + (dec args-count))) -1)) (defn argument-position [{:keys [current-chat-id] :as db} chat-id] (let [chat-id (or chat-id current-chat-id) input-text (get-in db [:chats chat-id :input-text]) + seq-arguments (get-in db [:chats chat-id :seq-arguments]) chat-command (selected-chat-command db chat-id)] - (current-chat-argument-position chat-command input-text))) + (current-chat-argument-position chat-command input-text seq-arguments))) (defn command-completion ([{:keys [current-chat-id] :as db} chat-id] @@ -92,7 +107,8 @@ chat-command (selected-chat-command db chat-id)] (command-completion chat-command))) ([{:keys [args] :as chat-command}] - (let [params (get-in chat-command [:command :params]) + (let [args (remove str/blank? args) + params (get-in chat-command [:command :params]) required-params (remove :optional params)] (if chat-command (cond @@ -134,30 +150,6 @@ {:title (i18n/label :t/phone-number) :description (i18n/label :t/invalid-phone)}])))) -(def text-modifiers - [password-input/modifier]) - -(defn add-modifiers [params new-args] - (->> new-args - (map-indexed (fn [i arg] - {:position i - :value arg - :modifier (-> (filter - (fn [mod] - ((:execute-when mod) (get params i))) - text-modifiers) - (first))})) - (into []))) - -(defn apply-modifiers [text-splitted args] - (if-let [{:keys [position modifier]} (first args)] - (if modifier - (let [{:keys [get-modified-text]} modifier - modified-text (get-modified-text text-splitted position)] - (apply-modifiers modified-text (rest args))) - (apply-modifiers text-splitted (rest args))) - (str/join const/spacing-char text-splitted))) - (defn- changed-arg-position [xs ys] (let [longest (into [] (max-key count xs ys)) shortest (into [] (if (= longest xs) ys xs))] @@ -170,19 +162,15 @@ (remove nil?) (first)))) -(defn make-input-text [modifiers [command & args] old-args selection] - (let [arg-pos (changed-arg-position args old-args) - modifier (get-in modifiers [arg-pos :modifier]) - new-arg (if (and arg-pos modifier) - (let [{:keys [make-change]} modifier] - (make-change {:command-name (subs command 1) - :old-args old-args - :new-args args - :arg-pos arg-pos - :selection selection})) - (get (into [] args) arg-pos)) +(defn make-input-text [[command & args] old-args] + (let [args (into [] args) + old-args (into [] old-args) + + arg-pos (changed-arg-position args old-args) + new-arg (get args arg-pos) new-args (if arg-pos - (assoc (into [] old-args) arg-pos (when new-arg (str/trim new-arg))) + (assoc old-args arg-pos (when new-arg + (str/trim new-arg))) old-args)] (str command diff --git a/src/status_im/chat/models/password_input.cljs b/src/status_im/chat/models/password_input.cljs deleted file mode 100644 index d094d64dd5..0000000000 --- a/src/status_im/chat/models/password_input.cljs +++ /dev/null @@ -1,48 +0,0 @@ -(ns status-im.chat.models.password-input - (:require [status-im.chat.constants :as const] - [clojure.string :as str] - [taoensso.timbre :as log])) - -(defn- get-modified-text [text arg-pos] - (let [hide-fn #(apply str (repeat (count %) const/masking-char)) - updated-text (update text (inc arg-pos) hide-fn)] - updated-text)) - -(defn- get-change [{:keys [command-name old-args new-args arg-pos selection]}] - (let [old-args (into [] old-args) - new-args (into [] new-args) - modification (- (count (get new-args arg-pos)) - (count (get old-args arg-pos))) - type (if (> modification 0) :added :removed) - position (-> (:start selection) - (- (inc (count command-name))) - (- (count (str/join const/spacing-char (take arg-pos old-args)))) - (- modification) - (- (if (= arg-pos 0) 0 1))) - position (if (= :added type) position (inc position)) - symbols-count (.abs js/Math modification)] - {:type type - :position position - :symbols (when (= :added type) - (subs (get new-args arg-pos) - position - (+ position symbols-count)))})) - -(defn- make-change [{:keys [command-name old-args new-args arg-pos selection] :as args}] - (let [{:keys [type position symbols] :as c} (get-change args) - make-change #(if (= type :added) - (str (if % (subs % 0 position) "") - symbols - (if % (subs % position) "")) - (str (if % (subs % 0 position) "") - (if % (subs % (+ 1 position (count symbols))) ""))) - args (if (= (count old-args) 0) - [const/spacing-char] - (into [] old-args)) - updated-args (update args arg-pos make-change)] - (make-change (get args arg-pos)))) - -(def modifier - {:execute-when :hidden - :make-change make-change - :get-modified-text get-modified-text}) \ No newline at end of file diff --git a/src/status_im/chat/styles/input/input.cljs b/src/status_im/chat/styles/input/input.cljs index d30b8be928..019e836a43 100644 --- a/src/status_im/chat/styles/input/input.cljs +++ b/src/status_im/chat/styles/input/input.cljs @@ -70,10 +70,22 @@ :text-align-vertical :center :height min-input-height :align-items :center - :android {:left (+ 18 left) + :android {:left (+ 15 left) :top -1} :ios {:line-height min-input-height - :left (+ 15 left)}}) + :left (+ 9 left)}}) + +(defnstyle input-password-text [left] + {:min-width 200 + :font-size 14 + :position :absolute + :text-align-vertical :center + :height min-input-height + :align-items :center + :android {:left (+ 15 left) + :top 0.5} + :ios {:line-height min-input-height + :left (+ 9 left)}}) (def input-emoji-icon {:margin-top 7 diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index ecb45c287d..559664da86 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -24,7 +24,6 @@ (reaction))])) (into {})))) - (register-sub :chat-ui-props (fn [db [_ ui-element chat-id]] @@ -87,11 +86,12 @@ (register-sub :current-chat-argument-position (fn [db [_ chat-id]] - (let [chat-id (or chat-id (@db :current-chat-id)) - command (subscribe [:selected-chat-command chat-id]) - input-text (subscribe [:chat :input-text chat-id])] + (let [chat-id (or chat-id (@db :current-chat-id)) + command (subscribe [:selected-chat-command chat-id]) + input-text (subscribe [:chat :input-text chat-id]) + seq-arguments (subscribe [:chat :seq-arguments chat-id])] (reaction - (input-model/current-chat-argument-position @command @input-text))))) + (input-model/current-chat-argument-position @command @input-text @seq-arguments))))) (register-sub :chat-parameter-box diff --git a/src/status_im/chat/views/input/input.cljs b/src/status_im/chat/views/input/input.cljs index 0c028f8244..950ffdc3c8 100644 --- a/src/status_im/chat/views/input/input.cljs +++ b/src/status_im/chat/views/input/input.cljs @@ -52,36 +52,8 @@ ^{:key command-key} [command-view index command])]]]) -(defn- invisible-input [{:keys [set-layout-width value]}] - (let [input-text (subscribe [:chat :input-text]) - modified-text (subscribe [:chat :modified-text])] - [text {:style style/invisible-input-text - :on-layout #(let [w (-> (.-nativeEvent %) - (.-layout) - (.-width))] - (set-layout-width w))} - (utils/safe-trim (or @modified-text @input-text ""))])) - -(defn- input-helper [_] - (let [input-text (subscribe [:chat :input-text])] - (fn [{:keys [command width]}] - (when-let [placeholder (cond - (= @input-text const/command-char) - (i18n/label :t/type-a-command) - - (and command (empty? (:args command))) - (get-in command [:command :params 0 :placeholder]) - - (and command - (= (count (:args command)) 1) - (input-model/text-ends-with-space? @input-text)) - (get-in command [:command :params 1 :placeholder]))] - [text {:style (style/input-helper-text width)} - placeholder])))) - -(defn- text-field [_] +(defn- basic-text-input [_] (let [input-text (subscribe [:chat :input-text]) - modified-text (subscribe [:chat :modified-text]) command (subscribe [:selected-chat-command]) sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])] (fn [{:keys [set-layout-height height]}] @@ -90,7 +62,7 @@ :accessibility-label id/chat-message-input :blur-on-submit false :multiline true - :default-value (or @modified-text @input-text "") + :default-value (or @input-text "") :editable (not @sending-in-progress?) :on-blur #(do (dispatch [:set-chat-ui-props :input-focused? false]) (set-layout-height 0)) @@ -107,21 +79,73 @@ (set-layout-height h)) :on-selection-change #(let [s (-> (.-nativeEvent %) (.-selection))] - ;; This will be a bit tricky: - ;; iOS calls onSelectionChange BEFORE onChangeText, while - ;; Android calls onChange text first. - ;; We need some consistency, so we call the callback with a small delay: - (js/setTimeout - (fn [] (dispatch [:set-chat-ui-props :selection {:start (.-start s) - :end (.-end s)}])) - 20)) - :on-submit-editing #(do (dispatch [:set-chat-ui-props :sending-in-progress? true]) - (dispatch [:send-current-message])) + (when (and (= (.-end s) 10) + (get command [:command :sequential-params])) + (dispatch [:chat-input-focus :seq-input-ref]))) + :on-submit-editing #(dispatch [:send-current-message]) :on-focus #(do (dispatch [:set-chat-ui-props :input-focused? true]) (dispatch [:set-chat-ui-props :show-emoji? false])) :style (style/input-view height) :placeholder-text-color style/color-input-helper-placeholder}]))) +(defn- invisible-input [{:keys [set-layout-width value]}] + (let [input-text (subscribe [:chat :input-text])] + [text {:style style/invisible-input-text + :on-layout #(let [w (-> (.-nativeEvent %) + (.-layout) + (.-width))] + (set-layout-width w))} + (or @input-text "")])) + +(defn- input-helper [_] + (let [input-text (subscribe [:chat :input-text])] + (fn [{:keys [command width]}] + (when-not (get-in command [:command :sequential-params]) + (let [real-args (remove str/blank? (:args command))] + (when-let [placeholder (cond + (= @input-text const/command-char) + (i18n/label :t/type-a-command) + + (and command (empty? real-args)) + (get-in command [:command :params 0 :placeholder]) + + (and command + (= (count real-args) 1) + (input-model/text-ends-with-space? @input-text)) + (get-in command [:command :params 1 :placeholder]))] + [text {:style (style/input-helper-text width)} + placeholder])))))) + +(defn get-options [type] + (case (keyword type) + :phone {:keyboard-type "phone-pad"} + :password {:secure-text-entry true} + :number {:keyboard-type "numeric"} + nil)) + +(defn- seq-input [_] + (let [command (subscribe [:selected-chat-command]) + arg-pos (subscribe [:current-chat-argument-position]) + seq-arg-input-text (subscribe [:chat :seq-argument-input-text])] + (fn [{:keys [command-width]}] + (when (get-in @command [:command :sequential-params]) + (let [{:keys [placeholder hidden type]} (get-in @command [:command :params @arg-pos])] + [text-input (merge {:ref #(dispatch [:set-chat-ui-props :seq-input-ref %]) + :style (style/input-password-text command-width) + :default-value (or @seq-arg-input-text "") + :on-change-text #(do (dispatch [:set-chat-seq-arg-input-text %]) + (dispatch [:set-chat-ui-props :validation-messages nil])) + :secure-text-entry hidden + :placeholder placeholder + :blur-on-submit false + :on-submit-editing (fn [] + (when-not (str/blank? @seq-arg-input-text) + (dispatch [:send-seq-argument])) + (js/setTimeout + #(dispatch [:chat-input-focus :seq-input-ref]) + 100))} + (get-options type))]))))) + (defn input-view [_] (let [component (r/current-component) set-layout-width #(r/set-state component {:width %}) @@ -137,11 +161,12 @@ (let [{:keys [width height]} (r/state component) command @command] [animated-view {:style (style/input-root height anim-margin)} - [text-field {:set-layout-height set-layout-height - :height height}] + [basic-text-input {:set-layout-height set-layout-height + :height height}] [invisible-input {:set-layout-width set-layout-width}] [input-helper {:command command :width width}] + [seq-input {:command-width width}] (if-not command [touchable-highlight {:on-press #(do (dispatch [:toggle-chat-ui-props :show-emoji?]) @@ -152,21 +177,29 @@ {:on-press #(do (dispatch [:set-chat-input-text nil]) (dispatch [:set-chat-input-metadata nil]) (dispatch [:set-chat-ui-props :result-box nil]) - (dispatch [:set-chat-ui-props :validation-messages nil]))} + (dispatch [:set-chat-ui-props :validation-messages nil]) + (dispatch [:clear-seq-arguments]))} [view style/input-clear-container [icon :close_gray style/input-clear-icon]]])]))}))) (defview input-container [{:keys [anim-margin]}] [command-completion [:command-completion] selected-command [:selected-chat-command] - input-text [:chat :input-text]] + input-text [:chat :input-text] + seq-arg-input-text [:chat :seq-argument-input-text]] [view style/input-container [input-view {:anim-margin anim-margin}] (when (and (not (str/blank? input-text)) (or (not selected-command) (some #{:complete :less-than-needed} [command-completion]))) - [touchable-highlight {:on-press #(do (dispatch [:set-chat-ui-props :sending-in-progress? true]) - (dispatch [:send-current-message]))} + [touchable-highlight {:on-press #(if (get-in selected-command [:command :sequential-params]) + (do + (when-not (str/blank? seq-arg-input-text) + (dispatch [:send-seq-argument])) + (js/setTimeout + (fn [] (dispatch [:chat-input-focus :seq-input-ref])) + 100)) + (dispatch [:send-current-message]))} [view style/send-message-container [icon :arrow_top style/send-message-icon]]])]) From d0d273f1e53bf40251bd75fd84e2c0c0e20d00a4 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Thu, 13 Apr 2017 18:29:29 +0300 Subject: [PATCH 35/48] fix undeclared ios? --- src/status_im/components/react.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index b897705b61..341212e5b7 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -3,7 +3,7 @@ [status-im.components.styles :as st] [status-im.utils.utils :as u :refer [get-react-property get-class adapt-class]] - [status-im.utils.platform :refer [platform-specific]] + [status-im.utils.platform :refer [platform-specific ios?]] [status-im.i18n :as i18n])) (def react-native (js/require "react-native")) From dd2c3aa28788ba247318ea268b24d07a3de1eb05 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Thu, 13 Apr 2017 20:36:22 +0300 Subject: [PATCH 36/48] fix namespaces --- .../{confirmation-success.cljs => confirmation_success.cljs} | 0 .../{pending-transactions.cljs => pending_transactions.cljs} | 0 .../{transaction-details.cljs => transaction_details.cljs} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/status_im/transactions/screens/{confirmation-success.cljs => confirmation_success.cljs} (100%) rename src/status_im/transactions/screens/{pending-transactions.cljs => pending_transactions.cljs} (100%) rename src/status_im/transactions/screens/{transaction-details.cljs => transaction_details.cljs} (100%) diff --git a/src/status_im/transactions/screens/confirmation-success.cljs b/src/status_im/transactions/screens/confirmation_success.cljs similarity index 100% rename from src/status_im/transactions/screens/confirmation-success.cljs rename to src/status_im/transactions/screens/confirmation_success.cljs diff --git a/src/status_im/transactions/screens/pending-transactions.cljs b/src/status_im/transactions/screens/pending_transactions.cljs similarity index 100% rename from src/status_im/transactions/screens/pending-transactions.cljs rename to src/status_im/transactions/screens/pending_transactions.cljs diff --git a/src/status_im/transactions/screens/transaction-details.cljs b/src/status_im/transactions/screens/transaction_details.cljs similarity index 100% rename from src/status_im/transactions/screens/transaction-details.cljs rename to src/status_im/transactions/screens/transaction_details.cljs From 3244fa49ce6bb425c4bc43032fb4520f103d07c8 Mon Sep 17 00:00:00 2001 From: Gustavo Nunes Date: Fri, 14 Apr 2017 04:39:52 -0300 Subject: [PATCH 37/48] Transaction screens: fee and title (#995) * add estimated fee field --- src/status_im/android/core.cljs | 4 ++-- src/status_im/ios/core.cljs | 4 ++-- src/status_im/transactions/handlers.cljs | 10 ++++++---- .../transactions/screens/transaction_details.cljs | 14 +++++++++----- ...ransactions.cljs => unsigned_transactions.cljs} | 8 ++++---- src/status_im/transactions/styles/screens.cljs | 2 +- src/status_im/translations/en.cljs | 3 ++- 7 files changed, 26 insertions(+), 19 deletions(-) rename src/status_im/transactions/screens/{pending_transactions.cljs => unsigned_transactions.cljs} (92%) diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index b5f6bdf709..13ba9bac22 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -23,7 +23,7 @@ [status-im.accounts.recover.screen :refer [recover]] [status-im.accounts.screen :refer [accounts]] [status-im.transactions.screens.confirmation-success :refer [confirmation-success]] - [status-im.transactions.screens.pending-transactions :refer [pending-transactions]] + [status-im.transactions.screens.unsigned-transactions :refer [unsigned-transactions]] [status-im.transactions.screens.transaction-details :refer [transaction-details]] [status-im.chats-list.screen :refer [chats-list]] [status-im.new-chat.screen :refer [new-chat]] @@ -151,7 +151,7 @@ (let [component (case @modal-view :qr-scanner qr-scanner :qr-code-view qr-code-view - :pending-transactions pending-transactions + :unsigned-transactions unsigned-transactions :transaction-details transaction-details :confirmation-success confirmation-success :contact-list-modal contact-list-modal)] diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 86c7491092..a4368bfcf7 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -21,7 +21,7 @@ [status-im.accounts.recover.screen :refer [recover]] [status-im.accounts.screen :refer [accounts]] [status-im.transactions.screens.confirmation-success :refer [confirmation-success]] - [status-im.transactions.screens.pending-transactions :refer [pending-transactions]] + [status-im.transactions.screens.unsigned-transactions :refer [unsigned-transactions]] [status-im.transactions.screens.transaction-details :refer [transaction-details]] [status-im.chats-list.screen :refer [chats-list]] [status-im.new-chat.screen :refer [new-chat]] @@ -133,7 +133,7 @@ (let [component (case @modal-view :qr-scanner qr-scanner :qr-code-view qr-code-view - :pending-transactions pending-transactions + :unsigned-transactions unsigned-transactions :transaction-details transaction-details :confirmation-success confirmation-success :contact-list-modal contact-list-modal)] diff --git a/src/status_im/transactions/handlers.cljs b/src/status_im/transactions/handlers.cljs index 064df8ca6c..754fbab6fa 100644 --- a/src/status_im/transactions/handlers.cljs +++ b/src/status_im/transactions/handlers.cljs @@ -22,7 +22,7 @@ ;; && :navigation-replace <- on success -(defmethod nav/preload-data! :pending-transactions +(defmethod nav/preload-data! :unsigned-transactions [{:keys [transactions-queue] :as db} _] (-> db (assoc :transactions transactions-queue @@ -128,15 +128,17 @@ (status/discard-transaction id))))) (register-handler ::transaction-queued - (after #(dispatch [:navigate-to-modal :pending-transactions])) + (after #(dispatch [:navigate-to-modal :unsigned-transactions])) (fn [db [_ {:keys [id message_id args]}]] - (let [{:keys [from to value data]} args] + (let [{:keys [from to value data gas gasPrice]} args] (if (valid-hex? to) (let [transaction {:id id :from from :to to :value (.toDecimal js/Web3.prototype value) :data data + :gas (.toDecimal js/Web3.prototype gas) + :gas-price (.toDecimal js/Web3.prototype gasPrice) :message-id message_id}] (assoc-in db [:transactions-queue id] transaction)) db)))) @@ -155,7 +157,7 @@ (dispatch [::check-completed-transaction! {:message-id message-id}])) (dispatch [::remove-transaction id])) - (when (#{:pending-transactions :transaction-details} modal) + (when (#{:unsigned-transactions :transaction-details} modal) (dispatch [:navigate-to-modal :confirmation-success]))))))) (register-handler ::add-transactions-hash diff --git a/src/status_im/transactions/screens/transaction_details.cljs b/src/status_im/transactions/screens/transaction_details.cljs index fd3a6a212d..13274ce7b7 100644 --- a/src/status_im/transactions/screens/transaction_details.cljs +++ b/src/status_im/transactions/screens/transaction_details.cljs @@ -16,7 +16,7 @@ (defn toolbar-view [] [toolbar/toolbar {:background-color st/transactions-toolbar-background - :nav-action (act/back-white #(rf/dispatch [:navigate-to-modal :pending-transactions])) + :nav-action (act/back-white #(rf/dispatch [:navigate-to-modal :unsigned-transactions])) :border-style st/toolbar-border :custom-content [rn/view {:style st/toolbar-title-container} [rn/text {:style st/toolbar-title-text @@ -35,26 +35,30 @@ [rn/text {:style st/details-data-title} (i18n/label :t/data)] [rn/text {:style st/details-data-content} content]]) -(defview details [{:keys [to data] :as transaction}] +(defview details [{:keys [to data gas gas-price] :as transaction}] [current-account [:get-current-account] recipient [:contact-by-address to]] - (let [recipient-name (or (:name recipient) to)] + (let [recipient-name (or (:name recipient) to) + gas-price (.fromWei js/Web3.prototype gas-price "ether") + fee-value (* gas gas-price) + estimated-fee (str fee-value " ETH")] [rn/view st/details-container [detail-item (i18n/label :t/to) recipient-name true] [detail-item (i18n/label :t/from) (:name current-account) true] + [detail-item (i18n/label :t/estimated-fee) estimated-fee] [detail-data data]])) (defview transaction-details [] [{:keys [id] :as transaction} [:get :selected-transaction] {:keys [password]} [:get :confirm-transactions] confirmed? [:get-in [:transaction-details-ui-props :confirmed?]]] - {:component-did-update #(when-not transaction (rf/dispatch [:navigate-to-modal :pending-transactions])) + {:component-did-update #(when-not transaction (rf/dispatch [:navigate-to-modal :unsigned-transactions])) :component-will-unmount #(rf/dispatch [:set-in [:transaction-details-ui-props :confirmed?] false])} [rn/keyboard-avoiding-view {:style st/transactions-screen} [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] [toolbar-view] [rn/scroll-view st/details-screen-content-container - [transactions-list-item/view transaction #(rf/dispatch [:navigate-to-modal :pending-transactions])] + [transactions-list-item/view transaction #(rf/dispatch [:navigate-to-modal :unsigned-transactions])] [common/separator st/details-separator st/details-separator-wrapper] [details transaction]] (when confirmed? [password-form/view 1]) diff --git a/src/status_im/transactions/screens/pending_transactions.cljs b/src/status_im/transactions/screens/unsigned_transactions.cljs similarity index 92% rename from src/status_im/transactions/screens/pending_transactions.cljs rename to src/status_im/transactions/screens/unsigned_transactions.cljs index 1f028df30e..e307344ce0 100644 --- a/src/status_im/transactions/screens/pending_transactions.cljs +++ b/src/status_im/transactions/screens/unsigned_transactions.cljs @@ -1,4 +1,4 @@ -(ns status-im.transactions.screens.pending-transactions +(ns status-im.transactions.screens.unsigned-transactions (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :as rf] [status-im.components.common.common :as common] @@ -23,7 +23,7 @@ :custom-content [rn/view {:style st/toolbar-title-container} [rn/text {:style st/toolbar-title-text :font :toolbar-title} - (i18n/label :t/pending-transactions)] + (i18n/label :t/unsigned-transactions)] [rn/text {:style st/toolbar-title-count :font :toolbar-title} (count transactions)]]}]) @@ -41,13 +41,13 @@ [rn/view [transactions-list-item/view row]]])) -(defview pending-transactions [] +(defview unsigned-transactions [] [transactions [:transactions] {:keys [password]} [:get :confirm-transactions] confirmed? [:get-in [:transactions-list-ui-props :confirmed?]]] {:component-did-update #(when-not (seq transactions) (rf/dispatch [:navigate-back])) :component-will-unmount #(rf/dispatch [:set-in [:transactions-list-ui-props :confirmed?] false])} - [rn/keyboard-avoiding-view {:style st/transactions-screen} + [(if platform/ios? rn/keyboard-avoiding-view rn/view) (merge {:behavior :padding} st/transactions-screen) [status-bar/status-bar {:type (if platform/ios? :transparent :main)}] [toolbar-view transactions] [rn/view {:style st/transactions-screen-content-container} diff --git a/src/status_im/transactions/styles/screens.cljs b/src/status_im/transactions/styles/screens.cljs index 88c2d75dd4..f0b0a42bfc 100644 --- a/src/status_im/transactions/styles/screens.cljs +++ b/src/status_im/transactions/styles/screens.cljs @@ -33,7 +33,7 @@ {:ios {:background-color common/color-white :opacity 0.1}}) -;; pending-transactions +;; unsigned-transactions (def transactions-screen {:flex 1 diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 9460c88576..789a968a7f 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -279,7 +279,7 @@ :other "{{count}} transactions confirmed" :zero "No transactions confirmed"} :transaction "Transaction" - :pending-transactions "Pending transactions" + :unsigned-transactions "Unsigned transactions" :enter-password-transactions {:one "Confirm transaction by entering your password" :other "Confirm transactions by entering your password"} :status "Status" @@ -287,6 +287,7 @@ :recipient "Recipient" :one-more-item "One more item" :fee "Fee" + :estimated-fee "Est. fee" :value "Value" :to "To" :from "From" From 1b5c758098d926d562b58aba0cfbe50b3aed1dec Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Fri, 14 Apr 2017 12:10:19 +0300 Subject: [PATCH 38/48] fix command input placeholder position on real iOS device --- src/status_im/chat/styles/input/input.cljs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/status_im/chat/styles/input/input.cljs b/src/status_im/chat/styles/input/input.cljs index 019e836a43..dd7bacc884 100644 --- a/src/status_im/chat/styles/input/input.cljs +++ b/src/status_im/chat/styles/input/input.cljs @@ -73,7 +73,9 @@ :android {:left (+ 15 left) :top -1} :ios {:line-height min-input-height - :left (+ 9 left)}}) + :left (+ 3 left) + :top 0 + :padding-top -3}}) (defnstyle input-password-text [left] {:min-width 200 From b6f220d4252df8232b0e44af3daf55bf6413a2c0 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Fri, 14 Apr 2017 16:26:01 +0300 Subject: [PATCH 39/48] fix #1006 --- src/status_im/components/list_selection.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/status_im/components/list_selection.cljs b/src/status_im/components/list_selection.cljs index f716215845..61b07b131f 100644 --- a/src/status_im/components/list_selection.cljs +++ b/src/status_im/components/list_selection.cljs @@ -28,7 +28,8 @@ (defn browse [link] (let [list-selection-fn (:list-selection-fn platform-specific)] (list-selection-fn {:title (label :t/browsing-title) - :options [(label :t/browsing-browse) (label :t/browsing-open-in-web-browser)] + :options [{:text (label :t/browsing-browse)} + {:text (label :t/browsing-open-in-web-browser)}] :callback (fn [index] (case index 0 (do From 738f1468960d511858ea6dd72c86ad455ac2c747 Mon Sep 17 00:00:00 2001 From: alwx Date: Fri, 14 Apr 2017 20:54:21 +0300 Subject: [PATCH 40/48] Tap on Return adds new line to input instead of sending a message (#1000) --- src/status_im/chat/views/input/input.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/status_im/chat/views/input/input.cljs b/src/status_im/chat/views/input/input.cljs index 950ffdc3c8..cda9bf8ce8 100644 --- a/src/status_im/chat/views/input/input.cljs +++ b/src/status_im/chat/views/input/input.cljs @@ -60,7 +60,7 @@ [text-input {:ref #(dispatch [:set-chat-ui-props :input-ref %]) :accessibility-label id/chat-message-input - :blur-on-submit false + :blur-on-submit true :multiline true :default-value (or @input-text "") :editable (not @sending-in-progress?) From 004b87ebd1174ee7ceb612ca4306ee1652580ee0 Mon Sep 17 00:00:00 2001 From: alwx Date: Fri, 14 Apr 2017 20:33:38 +0300 Subject: [PATCH 41/48] Correct keyboard types (#1002) --- resources/commands.js | 2 ++ resources/console.js | 1 + 2 files changed, 3 insertions(+) diff --git a/resources/commands.js b/resources/commands.js index 811ae30d6a..f802980a01 100644 --- a/resources/commands.js +++ b/resources/commands.js @@ -809,6 +809,7 @@ var send = { color: "#5fc48d", title: I18n.t('send_title'), description: I18n.t('send_description'), + sequentialParams: true, params: [{ name: "amount", type: status.types.NUMBER @@ -890,6 +891,7 @@ status.command({ color: "#5fc48d", title: I18n.t('request_title'), description: I18n.t('request_description'), + sequentialParams: true, params: [{ name: "amount", type: status.types.NUMBER diff --git a/resources/console.js b/resources/console.js index 6a945e7ba3..7e7eff3e0a 100644 --- a/resources/console.js +++ b/resources/console.js @@ -1852,6 +1852,7 @@ status.response({ name: "confirmation-code", color: "#7099e6", description: I18n.t('confirm_description'), + sequentialParams: true, params: [{ name: "code", type: status.types.NUMBER From 10cce42403abb9b44bd103a3a3b78fab60b883eb Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Sat, 15 Apr 2017 00:07:11 +0300 Subject: [PATCH 42/48] fix #1001 --- resources/commands.js | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/commands.js b/resources/commands.js index f802980a01..c2e833b15f 100644 --- a/resources/commands.js +++ b/resources/commands.js @@ -667,6 +667,7 @@ status.command({ title: I18n.t('location_title'), description: I18n.t('location_description'), color: "#a187d5", + sequentialParams: true, preview: function (params) { var text = status.components.text( { From 4633a23c176fe1366416504d60d6d8e5d2ae7ce7 Mon Sep 17 00:00:00 2001 From: alwx Date: Sat, 15 Apr 2017 11:58:11 +0300 Subject: [PATCH 43/48] Cursor is moved to command box instead of parameter box if edit phone from profile [ui-refresh] (#998) --- src/status_im/chat/styles/input/input.cljs | 2 +- src/status_im/chat/views/input/input.cljs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/status_im/chat/styles/input/input.cljs b/src/status_im/chat/styles/input/input.cljs index dd7bacc884..5d7a01d781 100644 --- a/src/status_im/chat/styles/input/input.cljs +++ b/src/status_im/chat/styles/input/input.cljs @@ -84,7 +84,7 @@ :text-align-vertical :center :height min-input-height :align-items :center - :android {:left (+ 15 left) + :android {:left (+ 10 left) :top 0.5} :ios {:line-height min-input-height :left (+ 9 left)}}) diff --git a/src/status_im/chat/views/input/input.cljs b/src/status_im/chat/views/input/input.cljs index cda9bf8ce8..112b0136d5 100644 --- a/src/status_im/chat/views/input/input.cljs +++ b/src/status_im/chat/views/input/input.cljs @@ -79,8 +79,8 @@ (set-layout-height h)) :on-selection-change #(let [s (-> (.-nativeEvent %) (.-selection))] - (when (and (= (.-end s) 10) - (get command [:command :sequential-params])) + (when (and (= (.-end s) (+ 2 (count (get-in @command [:command :name])))) + (get-in @command [:command :sequential-params])) (dispatch [:chat-input-focus :seq-input-ref]))) :on-submit-editing #(dispatch [:send-current-message]) :on-focus #(do (dispatch [:set-chat-ui-props :input-focused? true]) From e24df409e85cdecc9105d0d45893794fb35aa381 Mon Sep 17 00:00:00 2001 From: alwx Date: Sat, 15 Apr 2017 10:46:37 +0300 Subject: [PATCH 44/48] Tap in input filed has no effect if message was sent with Enter [ui-refresh] (#999) --- src/status_im/chat/handlers/input.cljs | 1 + src/status_im/chat/handlers/send_message.cljs | 1 - src/status_im/chat/styles/input/input.cljs | 2 +- src/status_im/chat/views/input/input.cljs | 15 +++++++++------ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/status_im/chat/handlers/input.cljs b/src/status_im/chat/handlers/input.cljs index a5d19cdfb0..39dcc41d36 100644 --- a/src/status_im/chat/handlers/input.cljs +++ b/src/status_im/chat/handlers/input.cljs @@ -142,6 +142,7 @@ :address current-account-id}] (dispatch [:set-chat-input-text nil chat-id]) (dispatch [:set-chat-input-metadata nil chat-id]) + (dispatch [:set-chat-ui-props :sending-in-progress? false]) (cond command-message (dispatch [:check-commands-handlers! data]) diff --git a/src/status_im/chat/handlers/send_message.cljs b/src/status_im/chat/handlers/send_message.cljs index 5217f7e9ae..bf4ce4e80f 100644 --- a/src/status_im/chat/handlers/send_message.cljs +++ b/src/status_im/chat/handlers/send_message.cljs @@ -168,7 +168,6 @@ (assoc :to chat-id :message-type :user-message)) params' (assoc params :message message'')] (dispatch [:update-message-overhead! chat-id network-status]) - (dispatch [:set-chat-ui-props :sending-in-progress? false]) (dispatch [::add-message params']) (dispatch [::save-message! params']))))) diff --git a/src/status_im/chat/styles/input/input.cljs b/src/status_im/chat/styles/input/input.cljs index 5d7a01d781..28830d8a70 100644 --- a/src/status_im/chat/styles/input/input.cljs +++ b/src/status_im/chat/styles/input/input.cljs @@ -77,7 +77,7 @@ :top 0 :padding-top -3}}) -(defnstyle input-password-text [left] +(defnstyle seq-input-text [left] {:min-width 200 :font-size 14 :position :absolute diff --git a/src/status_im/chat/views/input/input.cljs b/src/status_im/chat/views/input/input.cljs index 112b0136d5..58fc699fbe 100644 --- a/src/status_im/chat/views/input/input.cljs +++ b/src/status_im/chat/views/input/input.cljs @@ -66,13 +66,14 @@ :editable (not @sending-in-progress?) :on-blur #(do (dispatch [:set-chat-ui-props :input-focused? false]) (set-layout-height 0)) - :on-change-text #(when-not (str/includes? % "\n") + :on-change-text #(if-not (str/includes? % "\n") (do (dispatch [:set-chat-input-text %]) (dispatch [:load-chat-parameter-box (:command @command)]) (when (not @command) (dispatch [:set-chat-input-metadata nil]) (dispatch [:set-chat-ui-props :result-box nil])) - (dispatch [:set-chat-ui-props :validation-messages nil]))) + (dispatch [:set-chat-ui-props :validation-messages nil])) + (dispatch [:send-current-message])) :on-content-size-change #(let [h (-> (.-nativeEvent %) (.-contentSize) (.-height))] @@ -124,20 +125,22 @@ nil)) (defn- seq-input [_] - (let [command (subscribe [:selected-chat-command]) - arg-pos (subscribe [:current-chat-argument-position]) - seq-arg-input-text (subscribe [:chat :seq-argument-input-text])] + (let [command (subscribe [:selected-chat-command]) + arg-pos (subscribe [:current-chat-argument-position]) + seq-arg-input-text (subscribe [:chat :seq-argument-input-text]) + sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])] (fn [{:keys [command-width]}] (when (get-in @command [:command :sequential-params]) (let [{:keys [placeholder hidden type]} (get-in @command [:command :params @arg-pos])] [text-input (merge {:ref #(dispatch [:set-chat-ui-props :seq-input-ref %]) - :style (style/input-password-text command-width) + :style (style/seq-input-text command-width) :default-value (or @seq-arg-input-text "") :on-change-text #(do (dispatch [:set-chat-seq-arg-input-text %]) (dispatch [:set-chat-ui-props :validation-messages nil])) :secure-text-entry hidden :placeholder placeholder :blur-on-submit false + :editable (not @sending-in-progress?) :on-submit-editing (fn [] (when-not (str/blank? @seq-arg-input-text) (dispatch [:send-seq-argument])) From 5b0e6642c2b1457f76cda74d09042da159e83824 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Sun, 16 Apr 2017 11:13:22 +0300 Subject: [PATCH 45/48] fix #1014 --- src/status_im/chat/styles/input/input.cljs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/status_im/chat/styles/input/input.cljs b/src/status_im/chat/styles/input/input.cljs index 28830d8a70..b9d92f0515 100644 --- a/src/status_im/chat/styles/input/input.cljs +++ b/src/status_im/chat/styles/input/input.cljs @@ -73,9 +73,7 @@ :android {:left (+ 15 left) :top -1} :ios {:line-height min-input-height - :left (+ 3 left) - :top 0 - :padding-top -3}}) + :left (+ 10 left)}}) (defnstyle seq-input-text [left] {:min-width 200 From 4843003749f56333bca1d3f9fc65934f08534204 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Sat, 15 Apr 2017 10:36:59 +0300 Subject: [PATCH 46/48] fix #1003 --- src/status_im/chat/handlers/input.cljs | 6 +++--- src/status_im/chat/handlers/webview_bridge.cljs | 17 +++++++++++++++++ src/status_im/chat/subs.cljs | 4 ++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/status_im/chat/handlers/input.cljs b/src/status_im/chat/handlers/input.cljs index 39dcc41d36..f05977762b 100644 --- a/src/status_im/chat/handlers/input.cljs +++ b/src/status_im/chat/handlers/input.cljs @@ -150,7 +150,7 @@ (dispatch [:prepare-message data])))))) (handlers/register-handler - ::proceed-command + :proceed-command (handlers/side-effect! (fn [db [_ command chat-id]] (let [after-validation #(dispatch [::request-command-data @@ -249,7 +249,7 @@ (if (:command chat-command) (if (= :complete (input-model/command-completion chat-command)) (do - (dispatch [::proceed-command chat-command chat-id]) + (dispatch [:proceed-command chat-command chat-id]) (dispatch [:clear-seq-arguments chat-id])) (let [text (get-in db [:chats chat-id :input-text])] (dispatch [:set-chat-ui-props :sending-in-progress? false]) @@ -315,4 +315,4 @@ :set-chat-seq-arg-input-text (fn [{:keys [current-chat-id] :as db} [_ text chat-id]] (let [chat-id (or chat-id current-chat-id)] - (assoc-in db [:chats chat-id :seq-argument-input-text] text)))) \ No newline at end of file + (assoc-in db [:chats chat-id :seq-argument-input-text] text)))) diff --git a/src/status_im/chat/handlers/webview_bridge.cljs b/src/status_im/chat/handlers/webview_bridge.cljs index 690f0eec24..2328f1dc86 100644 --- a/src/status_im/chat/handlers/webview_bridge.cljs +++ b/src/status_im/chat/handlers/webview_bridge.cljs @@ -58,9 +58,26 @@ (dispatch [:chat-with-command whisper-identity action params])))) +(register-handler ::send-command + (u/side-effect! + (fn [{:keys [current-chat-id] :as db} [_ command-key params]] + (let [command (get-in db [:chats current-chat-id :commands command-key]) + command-input {:content "0" + :command command + :parameter-idx 0 + :params {"amount" (:amount params)} + :to-message-id nil}] + (dispatch [:proceed-command + {:command command, + :metadata nil, + :args [(str (:amount params))]} + current-chat-id]))))) + (defn chat-with-command [_ [_ whisper-identity command-key params]] (dispatch [:remove-contacts-click-handler]) + (dispatch [:add-chat-loaded-callback whisper-identity + #(dispatch [::send-command command-key params])]) (dispatch [:start-chat whisper-identity])) (register-handler :chat-with-command diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index 559664da86..6b1e51e9ca 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -27,8 +27,8 @@ (register-sub :chat-ui-props (fn [db [_ ui-element chat-id]] - (let [chat-id (or chat-id (:current-chat-id @db))] - (reaction (get-in @db [:chat-ui-props chat-id ui-element]))))) + (let [current-chat-id (subscribe [:get-current-chat-id])] + (reaction (get-in @db [:chat-ui-props (or chat-id @current-chat-id) ui-element]))))) (register-sub :chat-input-margin From 59a9a63fb82c602917019d375543fa33822825fb Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Sun, 16 Apr 2017 14:33:30 +0300 Subject: [PATCH 47/48] fixes https://github.com/status-im/status-react/issues/993 --- src/status_im/new_group/handlers.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/status_im/new_group/handlers.cljs b/src/status_im/new_group/handlers.cljs index 78e182cb5f..0f1c1c6b3b 100644 --- a/src/status_im/new_group/handlers.cljs +++ b/src/status_im/new_group/handlers.cljs @@ -81,7 +81,8 @@ (defn show-chat! [{:keys [new-chat]} _] - (dispatch [:navigation-replace :chat (:chat-id new-chat)])) + (dispatch [:navigate-to-clean :chat-list]) + (dispatch [:navigate-to :chat (:chat-id new-chat)])) (defn start-listen-group! [{:keys [new-chat web3 current-public-key]}] From 887dc44fc84a2cce361b1c96045521ec8be91242 Mon Sep 17 00:00:00 2001 From: alwx Date: Sun, 16 Apr 2017 23:42:19 +0300 Subject: [PATCH 48/48] Better text input, fixes for #1013 and #1017 --- src/status_im/chat/styles/input/input.cljs | 8 +++--- src/status_im/chat/views/input/input.cljs | 32 ++++++++++++---------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/status_im/chat/styles/input/input.cljs b/src/status_im/chat/styles/input/input.cljs index b9d92f0515..8dcf02f729 100644 --- a/src/status_im/chat/styles/input/input.cljs +++ b/src/status_im/chat/styles/input/input.cljs @@ -1,7 +1,8 @@ (ns status-im.chat.styles.input.input (:require-macros [status-im.utils.styles :refer [defnstyle]]) (:require [status-im.components.styles :as common] - [status-im.utils.platform :as platform])) + [status-im.utils.platform :as platform] + [taoensso.timbre :as log])) (def color-root-border "rgba(192, 198, 202, 0.28)") (def color-root-border-android "#e8eaeb") @@ -41,7 +42,7 @@ :background-color color-input :flex-direction :row :flex-grow 1 - :height (+ (min (max min-input-height content-height) max-input-height) 0) + :height (min (max min-input-height content-height) max-input-height) :margin-top anim-margin :padding-left 10 :padding-right 10 @@ -53,8 +54,7 @@ :font-size 14 :padding-top input-spacing-top :padding-bottom input-spacing-bottom - :line-height 20 - :android {:min-height content-height}}) + :height (min (max min-input-height content-height) max-input-height)}) (def invisible-input-text {:font-size 14 diff --git a/src/status_im/chat/views/input/input.cljs b/src/status_im/chat/views/input/input.cljs index 58fc699fbe..ad0b8d88e5 100644 --- a/src/status_im/chat/views/input/input.cljs +++ b/src/status_im/chat/views/input/input.cljs @@ -34,6 +34,7 @@ (defview commands-view [] [commands [:chat :command-suggestions] + requests [:chat :request-suggestions] show-suggestions? [:show-suggestions?]] [view style/commands-root [view style/command-list-icon-container @@ -47,10 +48,15 @@ [scroll-view {:horizontal true :showsHorizontalScrollIndicator false :keyboardShouldPersistTaps true} - [view style/commands - (for [[index [command-key command]] (map-indexed vector commands)] - ^{:key command-key} - [command-view index command])]]]) + (let [commands (map-indexed vector commands) + requests (map-indexed vector requests)] + [view style/commands + (for [[index [command-key command]] commands] + ^{:key command-key} + [command-view index command]) + (for [[index command] requests] + ^{:key (str "request-" index)} + [command-view index command])])]]) (defn- basic-text-input [_] (let [input-text (subscribe [:chat :input-text]) @@ -60,24 +66,22 @@ [text-input {:ref #(dispatch [:set-chat-ui-props :input-ref %]) :accessibility-label id/chat-message-input - :blur-on-submit true + :blur-on-submit false :multiline true :default-value (or @input-text "") :editable (not @sending-in-progress?) :on-blur #(do (dispatch [:set-chat-ui-props :input-focused? false]) (set-layout-height 0)) - :on-change-text #(if-not (str/includes? % "\n") - (do (dispatch [:set-chat-input-text %]) - (dispatch [:load-chat-parameter-box (:command @command)]) - (when (not @command) - (dispatch [:set-chat-input-metadata nil]) - (dispatch [:set-chat-ui-props :result-box nil])) - (dispatch [:set-chat-ui-props :validation-messages nil])) - (dispatch [:send-current-message])) - :on-content-size-change #(let [h (-> (.-nativeEvent %) + :on-change #(let [h (-> (.-nativeEvent %) (.-contentSize) (.-height))] (set-layout-height h)) + :on-change-text #(do (dispatch [:set-chat-input-text %]) + (dispatch [:load-chat-parameter-box (:command @command)]) + (when (not @command) + (dispatch [:set-chat-input-metadata nil]) + (dispatch [:set-chat-ui-props :result-box nil])) + (dispatch [:set-chat-ui-props :validation-messages nil])) :on-selection-change #(let [s (-> (.-nativeEvent %) (.-selection))] (when (and (= (.-end s) (+ 2 (count (get-in @command [:command :name]))))

KpOE?ZR!MT73+7 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 G+W!IVeN|=v literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_arrow_top.png b/android/app/src/main/res/drawable-hdpi/icon_arrow_top.png new file mode 100644 index 0000000000000000000000000000000000000000..193fe2261df4db55d9faa2c81aef5895184483db GIT binary patch literal 816 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6==i2z!;es5>XQ2>tmIipR1Rc zlAn~SSCLx))WN`DQ(*;U=BAb;Dpcg=|?L9&C18K8MsJfq@+6>EalY!TNUEORhr>JS|tJfByGyE&scG!LPD=7Mybk zzqB;E|8CU*7N_l==0A<1Go*QEicDY%a^Uh{)Kp+y;!wo8Nk{tN_7A2tGxj*nWo6vc z6#wwtj<{<#jU#iL4(aZZO`5nSP`1@!7sr9yiqA^F^sVDO^pm;5{0M7zWXa(vtQ;)r zH#Q$jU#=;6Z=I{a4*q(bnMe8y&p&y4Ow&wAf#JTU}K@+IdPL)Y4y5wz6H6DYVZ7V&WZh(9PS{)F-^LWOKVrl?kIyJ z6;)*&&1dUV<~kR2@a}nQ?z$#H^{1KKjRW659QyEYbLjW8t5SUU0={2wE1k7rM%BW- zYXcs|KazTITYahU1x^>O1>qV&2VT6jYUJYlu9kjX?ayKFKb{}1S5E)^SO07K#8x%d hB@NJUY1|+DfK8p*``F%2t};+!^>p=fS?83{1OQzbD;59% literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/icon_close_gray.png b/android/app/src/main/res/drawable-hdpi/icon_close_gray.png index 4342d2e4f00d4c020d637c738842f72c738882c8..574396b25bc2ecba0264a2dc00a0510de7d5b5c2 100644 GIT binary patch literal 622 zcmV-!0+IcRP)Px%C`m*?RA>e5Si3R=K@{y?oAVnYsl+O|z(xW;KtxDcYO#vYW`01R1Oz?+C6TBS zD8*NhuW9$p?xkx=&vf_p1j?PNsoOJi@9A?+Pxm~Ol1&^C2gCt!KpYSU#DV|ofDVV`$r+?JF4#lwZ*SETh#$-LM^oMRXS5JC7FZT7ScB3kxcs(a?OiLLx zW3udOeRFrYnB#klT43Z@gb8flTFwg=K!sCWOmV^(brvHcCr`D&U_6W}w|!%{0IjzP z{L|_nSj2DSfr(qv!u4u?tM|&Lq=);Px7oS*S8BFtX9E!1IR9{e`%G=;<|eOJ`p0{h z&O*n9U;)4Z$rusk z;+~JYZS4M&2mqi<#Hh1c$OGF39`zL$N+ve1Q~*xqJhMzD0Duk=+*fk)0Jh!Xj{a0k zIs%S)z=n7~?6|-uCKKQwk5>*uJCAg75lL1d7kMm|aIwy1bnFo*Bae07F|m`4#8?8V z$isbXb&7}<;7fiep*|5&0z%2xDI!?F@Eg`#5GlLX`yo|&JGB-b@x8%psPx# literal 347 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_close_gray.png b/android/app/src/main/res/drawable-mdpi/icon_close_gray.png index c0cca733358933d86b59399c687007f3d565fe25..0715d8b5e211e2b4eac2eeac505705564f45474d 100644 GIT binary patch literal 325 zcmV-L0lNN)P)Px#|4BqaR7ef&lQ9m0FcgN{CPu{B3+U)6@DO?dcSnO$Cy9xRyBF{joT94-&{@L- z_E(yamp(9ou?#f4_woPj-&Tn5garB~AUT2EUSBIw&ZjEcWZB{A(h3YxRGuz}@Z5mE6$ zH`yodPD@*lhRW^%ZYUQ8j7Af+LS$gTQepSa8sPd{DCbVgS?fm~SzfbFGmIgDffM)u XqPmYP)Px#%t=H+R45gVku46wKoEszwkaX&xd2E`0fzvOtHEK=1cw1j@SLKjsO>(7<2{Mnx+msc)+hp@723VdP+lnUJ$EQk?;pL8qW{p_Oq(xXN;mbPU!9jA<^sV5BuBf^qDVrM?r`c4;Y@Iq%O2SYwxE6*Mql Y-|X|O9pyIW`2YX_07*qoM6N<$g1J_5!TPx$14%?dR7ef&Q#%fVKoFhTL<)K@pe3ik#zZ>{tTYxL%fiG;du=&|tq0Jaf`XL? z*|1r6zywOB;4|~~z1g=rL}QE&^mTwGg7f8mBBogw@HRf bhIQZzMtramFYb8q00000NkvXXu0mjfd~Sr= literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/icon_input_list.png b/android/app/src/main/res/drawable-mdpi/icon_input_list.png index df86c2c636e33024cd6179a85e5f50fb72d9b491..6f58d3c7243dd863854ccdfd6c7a1559df92f370 100644 GIT binary patch literal 208 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/icon_input_list.png b/android/app/src/main/res/drawable-xhdpi/icon_input_list.png index 45c40f49c86893e759c9bc9e5850e903bdb735d3..fff2d39ec75e4f9d4f8d855f2e06b9347438892b 100644 GIT binary patch literal 664 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-HD>U<&edaSW+o ze0%Gl-ysJ9wg)%Wx{l1~Ft?pm@$r@Li|P)4#R>tH0>N6Qbq9)nu*L12QE^3jh6Jl^ z$sNtc3Cpz8%A^D9^)IZnzFil)?QKfu2X;md2L>jA1_l-d1{CHQmNRc=Kk{CB_g;m3 zUzX3ui6-VEcSXF8UJKp&YmvwHDZW=6IL|%!I<52Dv-4-v_UPxVl}}MDwVFG1cl&WQ zNxQ^lZ-168+%N6y?-ICwi`(;Fx5v)2?Jt?h@ZWotDRWZQP%<>KlC{0_{HJ4{eTU;1 zp8fbzd1URHL41>yK^trM~usUgn`N zkK19lRyL+Mm6g7^C;l}y_fywx?Mq)zu4S9Fd#cZgm*-T~eqSoQIgRu3j2Bf#jcI?~ zcg*;bcp~QA`*&ArH&yZe{9iEp`$5-enCGWOF`Reg*6Ww@2!6LAwf*YD8M9mpEw4z| zemZhy+4e{i)A^g)PJ8}cwNSI1qfgf{#QEU~PtSETc07u{#=*Blt9(QJ%Y&stoKw;x z4^NG@ZHnRC-}OB5-3Q(59evTfPxLZv*OpUCQ@@qFJ6$dR#u{$js{}+~Qy!MT_M> bUXA`WqGFczZW+$Nq{iUs>gTe~DWM4fd(I%H literal 333 zcmV-T0kZyyP)Px$2T4RhR7eeDT(xQy+s((Xniv`W$1woGe+I@y>at>WVPRpvKzv#Q7Ler(|Noc& zhuieO94H3jRltRSjMn~Xp8x*-odsmdAd8d1e!|Sim|j(!vkjz|3FdQTgRqHF$#Rf2 zGJpU7p9!;%3C0*Gnh6x==$2y>0|gsU-4k@RWbmIbF*B#Z^f3-}B7`|)lpeVuFyM)h zq>}Lezkf6T|Nk#bWPE|MTXkX9c6{ndDhWxj9Au{qwDiPhKf}-|38AGI(Ip`xBjaP_ z5)W4}40s~M<*-rlkrM&~o(PF93EO(7ctM*|l(q?B(F<-H5?vBf*>aF0z-_~!Qxa0K fO^6Z&1D*&0^;fc{?`V4|00000NkvXXu0mjf5;uyo diff --git a/android/app/src/main/res/drawable-xhdpi/icon_smile.png b/android/app/src/main/res/drawable-xhdpi/icon_smile.png index fbb4b0e99d684fb9cebac697ebe493b659423e21..0e8bb9d9df762ae661ae89f44b1a290855699d2f 100644 GIT binary patch literal 2648 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 literal 1510 zcmVPx)ph-kQR9FekS#4-rRTw_+O_rprw(8J+Pz7;J*6+?;!JvnA~+ zIdF5|^PczPIq&&=Z%FL0Tu5aOZrg=tg`me^qC*PNiFYSS2~sRd5{o2hNs#y|7zkW_ z`()qGJ8?zzD4l=*Qk%V%>xa{0z;UD=T_XBM3OOGPHK$L zGS?w+PBk$7`#sQ;6j z*{TWgus`8#({(?`B9)qLS}!brD1_|Rg5@`5EfQy1LU(-}i@m&7=2xetr$1_0 z+x+WATZ%YrwtFSfk=d>Tcf8u$+ncLs^D;PEiOKX8FE|*J7806Sc>;;p@bVURc$(aePHuTgilnn|xc6vDag~{D1{Z2Cd#I}%_d+unG zMdRM#b^$y$HPelrT`}hz1ilW1o1Q)ud;RyF0`k*)cluJ-W`5&SY??=PJI_gg>>eG6 z&O1C!sI6q9@FM`WX&wTc4TmF--)?Z)K7-8Xb6>h6N!cdRdQfjcScJvG`w%I}sCzBV|z8mC* z!gfB2mDOApqAai0a$Sho+1b$dzh%z~DUK^XiOUb&*FN6U)3a&HdFfj8*w=Lq?|xlQNL!r3H0V$dXa!gcRC(8;$G+I7%LElMS&8Wn z9>l6WVl-~@CT!FdiB7!Y2>1P)CceV&4O=;2gU>(TT2W^7pHxM*Ux)CHlvu4(iA@cnIL zm~%K}+>6AN@uTa}tMCnML15#Xuv7R};#3Txv|8T+i=UcHJ$meW8#fAF7#pu*7eIYw z(n9~|+sC&8=)$lbiMY;ZSK}U6yuLZV;Rw2hw6L<#vBx;7n)mvaL`y-0YY}68NNe#; z81xUi&Tn;(6Dz+!?jDoBQyM;RM8usBcn^b;Z^tZSv#=^%5yZiL*pVm^$`H{7FMr2% z*z$s7TNS>6&BFa_!E~f@2$NBwyACv8#C`1#pQgH4Y=dq2DS3S}HcRf?chx0~1c!47 z7Y`McFOcX{iH^6i#=6pl4Zqw&`79<^jy1++jm6&h38DSg;UfFu1jnd5B(CGvNYI4C zsFPq_w&AC?y0!8W_#xfKm>3(cVoXEJm78+*#S23Vo9~gq6G#!sxssc0H>YX7s9Pz; zzHqFKyIN$?hXNP~hSQj#>tzAiuClK(!=ZSXngeaPx%DoI2^R9Fek*gZ?bKo|$`yNl?SFCleN94sz6b+bjJehd|hRh-009JNx=Z{Q{< z4#usMZaV4c<{&r-83c<>ynov(*EDJFB>``_8cKLMZd{bZptHj_T}tT9 z(!%UXsZ{#KvAjyF)tY#Ge%%X6Smk5*A!Uuj-K~3ibb7u*g20mpri6Izd-%kL878*bbnd7#E&`UaO_ z&cuPxmL*C7LttT;z?d_6qSP?NgN5POgbAD%N)-bGEZos6I)SRcK9igS5LhM&`sXuJ zndTY-WrZ@uVEhq~Ey@Oy2r@<4V#b1WQRpA{IzYQ9{C1?il45U}NPt@PtkF06ZbF+V zDj4)l1)-A)3jLCbDhBaNAapcE>0q=#CMaEuHb@6$fi3Mx~WSbC4 zZE_5OY!U$?7t>q=kZA%L5#2V)*#(&dMh8#Y*Ue4w72@IP2$nFtVd9vG2(910db_W$^#2h2fz)B6KRl_guONHN?10000< KMNUMnLSTZ(Ul}F< diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_close_light_gray.png b/android/app/src/main/res/drawable-xxhdpi/icon_close_light_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..8f9b0d0b809e85eeaeb384517a2aff9d5b4424c3 GIT binary patch literal 753 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!jKx9jP7LeL$-HD>U|Q|z;uuoF z`1aODzdH^BYzgl*gw-H$!#k5@f%V&n>FU=mrtz^dVZ%5>0ru!L9j zt=@Vy_I;n0f8KWc+|T>fyXDUxd;D?olKlH-n{U23Jbyp`{k`SwpC!K6h0L8_^Rwo% z`Mn~0(*@o0um8TfdA^yj#q(wJ%kBimUhhBqH|qA}lPRyio%{dkp1etN-<=h9|DyJ< zTv}<9T0P~`j@4^_hu22i^&K)~;7R#;E9;1`UKNT?({(C zEz=@uSASc{_;A+cX+FZ94Z)>XFNG!Ft}|7LnNWB((|bvy%HhJ`E0@CDUjfC=gzZp> zR`e_kXnuBPrCE3DexFkgOE%ATJrnSL)mAG3p)5WR<7-+yHwuLnbeCMRkZ6~@5U`~5 zfFb*}mwR_ETz1bL4 zcqlTGOH(@_e$FJ1n++-!7TygT3++XgT2$O%UC_Jhs>eZ2{tLgpFs?b8^h;FQ=z?Oc z>B2J&CTuGNlQpJsPIz{}B>C&XAofiX6I^{Xr)f=i>Y$Tcp1AUE_d{Lo(=R2B=Y08} zw_<7b1V9dZ4i6^+@(14p8LrOarZ>Ku1(q%%$qUqhuyRo zVf7>83a;6le}k`OIjk$PpC%mrphYIuV`G%l{wrHw>1^X$|A5i`_1jG$KHHXKCK*UV cGK+m+fAMyIKzrjAP#R|NboFyt=akR{0B|5yRR910 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_input_list.png b/android/app/src/main/res/drawable-xxhdpi/icon_input_list.png deleted file mode 100644 index 9e4fd528b3052cec72c432a4092e9f297d4b997f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651 zcmV;60(AX}P)Px%MM*?KR9Fe^SiLVqK@gwWcS1))f<#G0N3D=(XzyPTL2^ezg3?DwxJwZ6FI-DQ z6k19uO2rYHQ#$YMnmsld&pFH9yWC6OHoH4JyYsPcXMS%Gs1*tY@9zG2L4isG!T>0^ zMZiLTU*}Fboenflvo`!t{^^{Q9}O!>MqKpwb&b_BVm)`%4Z+)_MAZ}CU(dNvSWLC5 zlcl-2B0o3v>G@GkG-GX)UZ?rCq49og_i#kY@+r|e=++`_k_5cH;>$*Ue|$MJdufD; z%4cI{Rr;FiD#+2f9aXkPLLyz-10Qnya8dc@IVC*SZ{mkWP9OSVDLOL3AU|B_2g?cH z#2W9{&|58WDxS zYdK!YPCa}vKu_YF2e>iGIPpN@fy4ui_W&ifc!yEvM5f`il>P*O?ER1b1qdYpibAAL z!b!^JJSRB4nLilzgYuaRB9%buQzKYjB6vQ&IzN47qqyO5g402u@-E67B`Up!E ztH`U<+yGvwc7oGN2K9r}TtkbosZ=|`X##RzD#aFZ>&rs&n+i_<)jAEoo#1rCtJB;< l4dcN_Fh>z&pIia(Xk^e@_4a002ovPDHLkV1h)hEa3nE diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_smile.png b/android/app/src/main/res/drawable-xxhdpi/icon_smile.png deleted file mode 100644 index 45dfb63996730514f7e4ea6e30282794413c733c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2424 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 Bg_r;U diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_smile.png b/android/app/src/main/res/drawable-xxxhdpi/icon_smile.png deleted file mode 100644 index 49d62400ddd0baff5d767a4893077091b6dec5f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3268 zcmV;#3_J6QP)Px>en~_@RCodHU3+j9)fqo$Hwlk$%ZNOpA`yoYI%pkhTU+cW(vSi-xqJHi zHur{`&7QMo_ddAN?99#GJ>UCx&*R&(=WIB;f=6THrtuNpd%F;#$l|<+F;T=Bo4^fBQ`L1439~)R3Drd`UeE=Z8^2 ze^hj1!Os>hTo_5c0kol1E47>H`N%TMV%6x=3R0~%ch%pqP^|t-|k73W9ikycNm7TytcaZ zSh9AK2C$*I?dz5hPoSUsNV3jkQXYfNS#I*;+N!dh$=D4HU~B7h!#;={S&Le?EJ+7W z3&!^`E)Ft-cN&ZxGI`E>A~)JKW&HRq(tY^dcSF3#3`IrnSc|c#%o0V&4W}bToGBO^ zmy~_ZTgHd-R+N;K^aRlp2*5S%?br5R6uSZ5ok5IZ=z7)Q#x{$K-_})@y&g2xpcJXT zrTrE|aO9TOBD8`#g7|}E{lF+QbZ=#4@dtk8eFONz^&OKUJ(1r4ylH-n!B7`!S_jWD zHrG{_{=<)~E^mFyhL4F}YYA#*32J6YSC04q;_KYV{Zeh!caQs$^TXWdVDx#&Ow^U5 zzJ?iWea;B8_2Fg9&g#k~!}sXMjo0*Eh*mI*Eyo?oHM+Xc5{|Om+H z^CFjC0>2h`)GSdGwhU*(R)oVP@9Ek}C0|oh$JmSP(qpLk#njw&bQ6f&$hk|mCTb~- z^?3($o2~5xHx?mH_??c^>E>C}(soxg%C-W;LLFPwoO4Fz%+zTy81&Q!jkeK?*01!z zV+YK<{7+>Icof~r%JP@UCmJl&(e_b=V7K)CxA)oY+qdU=@p}SzE^@dT3P0nei0Itl zKP{S6@P(BXOHS+XXOf3}BHzeI9lMD6b8j3y`Ir~4vI!$e{;Fk(r#+Q$9!0Ya*H)LU z^Wx10dP8&jLuk%T_+SQ1eITv{b>Z@7WL#1J8=Be+VSwh@M$3e$90sCX7z=7^N_VOF zvW?czxZz&GtsPz<+IK95ahvS6Puhe5T)P)|F#y9KHt@)A@|jwV*AGi+5T@i>WqhtR zu)ewNK4A&ZdqnC_>Z;3^%9MW?$`R`mi1h(4U(wd*ud1oo?c^I&1J|zIJ_6O6rlgby zjc7$TPDtuLSZN?bM2bOYbVeuNN|VG+w*~>&ZJk`^HG_<*f7Hwy^_6tZ@;aSN=QYJZ zu~1A(J3`!i{7m)&kv(dOr`~121Am1p znC2=%ABd;?s)JSx_&CTgCCLPkOpItT9_78KOg^zZt@b=(w+vpCgC!CGP!R`~TO>NH zb53^{sN!>Fw{p1eOzEv$+U!y6Q3W=F0YHv5d#%q-C`k@;B?uc*RaN5Q#K91=u$|!ICcTKkgjME`J{@|=^VvOu{+D-*Q9G0%l)%q zF8~+f?{R|LH|@i4E0>koPx(39Dx+t*993zn-_;ZvG5?LQLmy~QX6;o4Wp83pF}TnS zb65?U&HFB-j24j(QV^qr+Y_&vkcxbOzxiAN;O> zuw(Vw^%R>hwgDVzj(Y*yul}QQkahs6=x#LH$cH(zO>VSIl#%Tqn+ZK*1y&QsjKq?+LTE1COji-K@Pp)Cpw(aJWqKsmsSQRX^F8rzZ#%&uw zV#cWbq)G@QQpnyurDAfS(T|feoZo}mpiGxsL<1L*EwV|r{VJgtDOQyn@{FIy>9Eyz zP~L;(ZAb7uIbP=cMu&WM1kalqWa}2K`p3Rv>|7GpJN2gan!kfx=`*l;>Zo76^qlvC zh#bN^pR}a`up_nM@{h(-qW&6a7jWLFGD?bR@0p56Mx%guUhXV7puLe#rb|{%y2(Zm z@JMIhzB)O0wq1iY#=)cOegNrWbneZYku#m3bJ;-~_Zpfvs8%k?L>cXZG)EYp#qDDn z?w9#~((PxbWul`L6UCNT<~#>*$MFV`Es5m=0IaCE`x1!Fi44wjYU+5PylqYEW@(o0 zlu5i^SyuM`w89B<(Gzb(xs^x@cy5s{(n-35=%83ACW=iZ4*;8-3+o2}NW%F>!A7Js z|57P}p~7h7{4aGj+<0`#NS1VvE@xmm^29?iP%IRaQik(4 zZy1yRV<*ob0BPg`(w_ISv>C7S*eR+-fsd6nWiJ;MPWU8%Sct z@lgyEiyJMm%*3M6c!(g8GvZ$pd?RunN)9n|^#xn9%XQ!s^J7-HUlXFZKhqMO91?rnx+tEjq z#;;Z1_J(WhJqy~Qt8}M=MgxZ3=V@#%jM-bax~8I1WqZ&d;$$A3H>Fy)gQs1Oo&P?$ zCuoY}w4KUp@`-#SA9eI1<^$6T3p_U!c>+kep*h@`k6cTu%mhm0- z?OBpWJSz5z%e6-s<7@G}uCcv->hLd)Mlt5%z?jYC z#@RE~jf346Fc$PMp6_p-IVHv1aQq<_?o6FGov>kjy-H?ctXZ{Jzyp40D2gD@+QiwD6auF0UigG0>%Tf z0XqTn0o4HN4|V=I;04r=0Zsr;1I__x%s9XfKn-9W;3(h}0AsV|fJ=ahfb9T!XANKl zfZBHffGgVrm;i_c&^s}JXaLa_0cgVbL<4Z@FTp4MrsoPs0XA1HlPhk!2@N1`5FHLCGl@6U>v{; z&u*Z^yWAP&7?f@(p8-4qAepED&8Y8230gV$#|hVqfHzRb`}|43N`O7?fnJsj7!2?S zJP!y2bO90p_W=lB9UuWfG+F5at}?xgQI-HmX4K}dfFpq80J@KN`TZz~zeGnXfOty$ zpz%%ucA^bv;!%K406PH0E8xjKLj8jDa?b<63#kQ_v%c0Lh5tOZ~h6Xaf-cUIpv|kZdjkNKY;R zW&lVg8v&~T#P?GG&@Icj93}DY48|cDm;fgLgzIJi@#uNL{eWl8*E|_*AzPjRhz4i@ zkiCq57)p8$xy#S4qWlri3?Q0X0HklkKkD-pT<=HuIDl-K=qd(m0_+2<1CTvG3s?>y zy_yR!;=L%8#KW7?SA8Ftfw|&37C`=y^zn~?#wT9&2gpF4FRdl@LGA7Z!lOS#;2JXh zLs*Ju^Y4M@aNQq>)+xUO$8fJdq~e-@=%O+2EeTf|?~lrLibh$liEhH_zm;RrW+C8@ zO5(#l0P&3I`MnY{mhVqQNxHNhKr%lEpm%PUz)ikZoR&-CKlOc2*|!Gwh(6-iz2zS0 z1?-4o8g6GU<#~Jp>NM_uE3LXiCD{s%9V`7LmqaVc;(sk+8?xP!exw4ZYyxcfoiY&j zbbv$v=<0*r5Xd-??f(&wKOmdw53l07KU~1|jNbwB1N|Wz*Zs$#zWc*&T=yTxT5rSs z{$TY-{c)hW)jyGrkdLwg;b(>Zc#_Yu!Yb7J1IdPjazzK&JBCIRYic9oA=bpW0*qXw1U^(oyPQ0M7y50}vh5CK^Dxac@a9D}jX{Sr#Ti|8esF@E1flvbRrxD3a=p@4w^!k4b;Sq*^jqyFOo#0wjMm!)p$)7rNj zm+SD1`lt7)pOY4_zGv;5@FG4~OB#!KG73O`&RQ0rJ{v%MCm!5e62FM=lL2!8#Ao8= z0szGUgwMTrT6ysg@Pp>>KY0E>-?!5H2W8)Cgy)18gb#!tL@tV=tvEo` zik;#HahrHVG>TWm7sS7cuZwRSvq$$!IX|?oM>22v_=_dtO3{<%Ka^Fnf zRleW({@{DluS{*Pc31nV{nbJ0XtiFQqE1uis%NT~sE@0=)aNt`jjP5(zQ(s?iA66*0DO59mP z;{&-158@#_hL7NNyhWz)Fuwo_e-#E^{|*Y-Z3wC_H-?g*6rmo%>PPWTCJJ6mrQyQuh6Xb=W67r|(Ig*!KjqAPf))&;a}ZLjbM- zk3RQ4(e$(F8m}VOm>NylY-8_Ry(fCF_IBg%@!mtddwbWQw~2kt)S_2~dO^>vo_}M7 zcNuU$;27W#-rfq>gn9vEpO=2_@Y&;^ef3%8XV*UCAEWn=hkjiCap}i7pSpgW`lc-Gt)30hsgAeX!GI0u#6(2%;dt_E!iBK`E#N8^KnvV=LJz!CmkWJfW*zf;arY8rbDvVTj-> z__4M8bMaHQj(@>A*?P7?C>Mqb6+$K3C=3&Z3nPS)!YE<1P$g8eO>DC;MyL_S3gd)Y zVZ2bswy>>2z0e>u3QfWUp_y%C+l5)eY+;_TKv*a&;{W2;_zl5cxKG$A>=JehGlZGK z9APdy%gzbc*?HlH@SX5IZ0&+@Q}|W5#f(Ca(9607lhDU5!aY48a`vDoh$6crO6)Rw zNK}YQQ6<{IhuDesq62$MbP@-!r$tBhXZ8$x7JlhD_B?w*9LQc|e-Vd@9_$s-lf5bq z61_xk(TBapUT1HJL&OTvm;FujV{eLTQN!L6{n^{lo_FAv2D5j?05MPu5`)DMF;om= z?}_1}PK|Vc)_B-VmeNcVdhf%f1)&><2MUtQ6y!NlajU zVxpKNCW|SYan1!XRU9U!agj@0A^s{37e{bc?#A7@hd5Fk1rHM}_DM{B} z;#f%~*@$0>U-KlMEPf+?%TstNPZNLP={!UHN&HzHC)SGNc_ueV3Q5Vcc(%kPLA);B zkVHx1IpSn-lGrM?iS1&CIECl(Jn=j6dvT?>is$nJakaQcvX$(3p}1DE7uSiMyopbc z93=-nPyCE8U`l8n{$Xm7XP183&Tr?^?@o62YhtOI--Pxfsjk3Wq+&LhiR_p?bHIG$ z#0Fr0!5MiaSLVjtk!|;6gP0fdW~|$JCg${F#;ous{~Xf>{U)Wnq?CF_J~G zXcog_nV!XAj!a;Qm?x823QJ{aES+VrOlDwNm@{)&F3V&2tbi4=B38^wSSc%G68^dbYST>H;vhg%~lEw1x_z$qyKG>%cwyA<$+6Z=ngWx1M z3Il|Jf{WlRxC(BtQ%_jxAi*1!Iv7?88|59?MQC7+Y$Bh^X0a8>t4-od*bLUfH?k#c z8Si9M`6j-ZO<*(mD!zuVW`E}E*bA)J8V4Dz93tE-^Y)mKc@8$5a{Pe2gL0 zbOh-q}$l2ZSc`(jI7$oaMXO-GmQBkEa8mfKN#w4mGRadLK&5i1tj3KyXxl$XW>3KA@ ze6pfS4J112)keFDsyf_J(=$7&B~UG)&Zn-ry4uIc!>g;cMpjWZp}IQ4DC*RCYNHfb z4}=ss6;(!sHruGwW&{0dBd?1vN;)m@Qa5!g8nV^_3tHA;1PjYcs{gZnw^PIV{x z?v7Rjf~?A_x(c8AVbxXIYCJUzufiiABFZvygi)b0s&c|F!ir?pC~>LH)`G*@?0Tcn z&}`(57~iM}i!iEmYC_UJr}1HlHJ}O5G}Kj7le%0PNgLfol|9SJ%MR1rX11;FZsyyW zd*R_g0jLMosq;Fu^&|+HQ_P3BX;k|FNh_8{F;H8dYaYV>4_-G0;4Qp-o3#EfIgrX| zvoG4)iFs8TAFZZ3OcP;r)O8C&p0TMuH^S(o0|9Ea(IKap=t4!CU2Sxvt6{iu#8rfG z0J<3{vqTLJGy-j-Q%;?_vrcVv0@EUl19c@Ms=B47-0A?M;{@&82&1#Eq_V1HxcR1! z2KQa%`!2d}HXvtYRri1aIYwTeZ5$9zN($A@?slL*j`(Bb9*~3>SW(qYnhR!ScS5{0 zY?wxi*Q|9P^K*Iyx=&B5K}iAdFQ|hM?-JD?2(X(mS1nkaV`Lc@F~7*#;HqQYOvoEi zWgMW*R_7V*p_F!7=v%hB4#Qs>i2YwI1F}2ox?Pmv##!M${$P_EXmbsZFuLoyIh7vZ zGnJmYZjs7Cx^9U|FI~5SN^f1al1d+4w~ETax^5dPhv>R(sSMSrBaM7qgfUF6Op7pv z%a!R7MqeE>I)?v$;OGY&ebKiXI8vzrj#T;sM=G_zk;(wzNM#^!q%sINQW*>!sSE** zRO)o6sQ`O!#k2p@fZSo(PdJk3e;#x`2!qtSsv6 zEYKFfSyaKT!!5$16F7Hw!}v+?G9EAx{3kat+UA5$=#12=)oGpREBVf2b)>luql7-u zN^PtodpA^8Js_w>wa)`Wkmy~VO+L^D-W20uL~TB-57NBblwkKf-0bXyoVq5hQOv1t zf*TTY>U~hJtA_2~`%XPjf@9X^*C+XCF+x7*LLrZW{(ff=AVSVkf&&2W6;LR+_Iofv zkM(#tP(}iOG1HKjyE7IvB87N>6`)ZOWZ{7}4XjC(ZyRl3;A(ZgwtxmBX{E_5BLXZO zWh1I0)oGX;31iDmbasd3%0OHd;nD5c*DR>tDp#G>A{pQqVNADRkYg219Zk>ol4uoW zhEA)FB(CMdF{f2Wc1LnI7+~h@+mPm++lJe><<{0$?`o5!GbV*wpWM}Hw$7Lw-U%Hd zW$A=j{$^l^CDIs)@pEK$kpfz|OUk8%RYbx_%sA%4X~2iy)>JFK|6LUeeory}f3%PI zM*byDo8+VECvQ!)1;;#MhLx%LM8AeOPbgaGxJ_~aNOm_HCuV!tp=+cu4z^hM2ltEM zbGe(VF&=G-b;d*#CB(Hn@Kv3UY0b)~QXQ$Iu>@=_(_Mt0L8TlOPL-j$i(I}_fr@;m zlG^0q(J*R5mEqKeDkG>3RYp>qEL28O8>)<^HdLviHdLvmHaVz_p*B>hp*B<*OKqq! zj@sm-QcG>9GM?H{rHbzSQ8r0tUmL$_p$7EXBG zU@%Z!WVzh|d~GFS&b3wDVpDE+5M4cDvlM9=!`em!UTA{Qy4qk@&eCi`Y&=wwL)gQ- zZQvpZdB@hqw!`)VJ3qTJyIFQ` z*_rG^>}&1U+jrUj!$EQw>9EV;7e|Am(eX7WN2ds#tcMtdJ?jL%L_Bihu<+;uCUxOS6bK0V2YJ;a z>Yp`gO_^qu=CI~#%}swd|0w@r|5vr1+BEG$0W9FYz|_D;gQTFfLB9m22G<88&I+jx zSrhVFs8{IDu>7#+!+s4P8Gc2l(=F0{5aAWEIO1@`(-A*LxTuLE zQ7=a;qeG&Lqno0iihd#bpE33^Eir3iF2}qTYacr%c314z`upQX$1RP!8Q&8Brv$Hr z6$!5-4oiF{DKu$&(znSK$%m6~qzp^hpQ=cmllqsmq_jh6ru3Th^XXq^xMhsZIGFKK zW_9M`%*&ZK4O&BkVWZ)xESs!hS=+LH%x=y;m!rv6 zjjY;Kb*k#AF@7G`{Kh1iuLfnr)h=H-9{_a^lsN@|MRY z`A=Fl>7&VElV?u;{15+kWAd$5$JU6}5v?;?7q_l&-QD_P>yK?QZFOz!ZHw9~+Gn)y zYd_!qV@GAj6I13*`E2UMsm5t+TKKf~X{)9knRaE`Ytwbpv!^#sUo?Hs43`;2GmJCd zo^gGqYG%aDf|&)gB4(|b_2TRSv&&{Ln7w=UrP-g%?wu1pXXBjD<_69kHh13Kx99fF z3z=6tZ~eTkd2h|@nO`*j`24RIj9D;$fpNi`3x$O-3r8&S`mrh!`beZ3>#$_{?U0C+F<-W@kmrq!}Z$ozh33FO26vVYSrqB)z7YedG(vCKUfpFX33gQ*1E3kT)Thm z{cE3G`}*3?*8aTCW}WA{&~>Tn%GQlvH*MXDb@#37T6bmLU)FuF?s_NhbnOi6OzbS` ztm$m;T-3Rtb6@9~&MTcSbpE~bi_TxxE7!ZP4_F_yK5KpD`nvT~)-PGVY5l?V_pg6^ z{mbj$U;p*`TN~^*cyG{cNZnAjVeE#>8%s8h+t|Kw$;Qnak8Ct z8NKE7)&W~JTlHJ>wvOI9Y3qWm8@C?X+P(G9Ti@LJ#nzkK?6-Mu({0PxRZ&__hbOJ-hAAZC`BrdArSa@9nznsoTr8kKNv}ebM$!+YfE;-u~z9Z*Ko=`_DUU zc6jax+7Y`WcgKhw%{ylASi57-jUT}swRG3kT}O5qcRjJ| zue(0j_06u{-4444@7C>3+g-YQ?C#dx^LKad-n;ws?uU0jxBIOlA<_tC!V`}+0|-0!zPX1`&7#s2a8JN7T$ziIzx`+qzj9&kC}e<0?7 z;Xvtuu?JcX%ssI3z?K9151c=6>A>R$o;~pLfj19)aNzR;-yHbqK<`1tLC1sc2ZtPt zI+%5^;^6p$9S4^j+;VXD!NUhn9W)+%_~3H~-#YmD!JiMQ4tX64KeX@Au|t;*J$~rf zLvJ6tcIdl9HxKi}wugNVYY&GX)*ntioO8J3@bJSmhZ_&K9-eV{`QgsP+YWzw_~*l> zBaTM~9|<_3JCb@N=g6=l^+#qLS#jjPBgcnwFUQ_J_VuwJkBi6Mj|Uu2IG%TW^zoMC^N+7PzVG;%;}?%Va{Q&^?;Zc< zc+Ux^6MiRRP8d!MJJE1r=7|+2?mKb(gz>~WTMHe0`$lq|-^?lhG$LPgb6+ zJ30O2ij()9JbCholW(5<;^fa=HeH@wpb-C+m*WbIo=(>5z z=9KrT&{L_WN>A0EnsRFGsePx;pL*idE2lm@_1$UlwEOA6(}}0^Pgk9uczWLH&eQu( zpFjQF>5oo-e}@#Qoc5ceKwdZ!9JATf1?y+;vpZnXnkIsF4?%(I7^8?Qh zJ|A*E?!4iA>G|68Q_s&m|Kk1L_fNim*Zt32kS^q17=K~Tg>@J9T{wT?i3_h?_|)iS ztT1jdzH0ot@k`@R^uKN`6L^xO6lW_Dnjn82S7OvvR2duvq_=ssh|Em}EA=tBqJ|qI z=?1IDL(a;oFFU(9J4-f$!nvq*)+^`_zwUMLA-)EG6!)2?@n2i%54Mz$#b(lG#6LdB zd(SK}dSZ-VCwoD35Cq0WR&T?V%CwRJc7h}+s%=$*LXlbGh{4i1Mh~PL^h{Jp4ZnTM z(yrRz?dLmWu#dObAWsjh9)O(r-@t)3L&CXM)VgZpH8SW$y(_?7D+B(zYK3E;mYyv8 z7gwbI#9hlzlz&>@RsPC1sqfz`J2~&ulu!9yQ#0RtfTtYdhfQ?^hfG%wn3{z|j)0D{ z&3%zlt#TjBVtIyamjR$EE=CX)LNVilByedelN5ra=s-jU?g@=dA&QF8Ora2~88(i} z3>hiO`dHt=gFKxFDs9}td0eCr94W@fWeAD!dUs#ZU5h(fe<#7+%~$ZmwVRWma@WSA zjUIROu?gZ7pR~HXhJ#bn5*jy-K0JC|o&LISQe_C~7>=k&@K1qvlZM&YAhw zBMQev&R)zHhUKT~J=H@etsggH{X~P^yYD*`%|1FIb3#FoZ+uBacy5Z`%YW#k&aqYN zC#2gx{gh2gd)KV;=5((q_&|UKBZ57qcozE`;h=mp_7*Y>sWoE+L9FIV6^Ms$L46}s zOQn=ljSRbG^u0iC2~#Q+H6TAvQ5tIg7hq#EINTNVf(?Q@k*D>K6fDGL2=Vb&`uYFR zMiIr|vYFh^7TvGzs@rhYhkr z6JNhDZ+p|iB|^*+>0C;4X+%V6b4pqAgfgA3Y(lb6OrWP{V2n?hwbFAUxtSg{CzmHT zm+Ew-&2k%$pctQWZ*ybsjRr|F;3Pv8&O|&3zJ*~&rZIZc31GNV<*5l)DvAAy*n~u`a)P$`3Zk2bXJQ6a(yWJ7L3s^n znFaBU8%7n+8yTriD%FkT1Jr@96_s2uUCS>y-8A9Iv^0JtZMxp{(ZJ9cFB>0yi8d@~ zqMvr4G|*S)6OipHz) zMD}3#*oPb#F0l(HyRQeGodp{Yv-1-6cy&FgSZSIM!$p&^rWkRtvJT!#`GA{>N5dR5 zq(o0AffUol!^2Y*sfg!eBTFYtnWm3Uo>`lkT01j2T0d>dgwjZ%Vr$P^7uJmP-l*I8 zzUiIE+#WN%^N-z;tG#O1-2YY&jvR2FhW?xG>fg;tQUzxSE>LqJC@475SK%%;MV2>D zo1u?NnpvBcSvMmtNENDm;H?rrdNa&)k_v$atvMFF2P;iv5>!+Bt$Lez_ao(irK#bCkPv^0ZH zQ@^a`9T}$iT+#LVtEYukR*BNBc!Vd_F zkrKWff`T$$4`sxLJa!VxWcLeq<{i#8?iy#UvnF2StQX$oi%rX~nU?V-*F^Qlrs4ej z$2h~ld4p-4a0dI=_H3ZRQK=BjxOx+=fux?n(9U?haN0*-5WXfn^13E|YFm9!LE)i> z*MQSa!B_GYK7@4*GPvXVE@3+lltqp4CGVaOMUCM56v^Rg-`Ap+Ct{D*)j(ff@fzIB zv}D;VBgq>MnDP4EQSvIiZ)w5-Tr>*wp~Awg2G|ACk!-C@fz zR&bdX=b1+n^6%U)WTn-Y14BXslDQe26+m3VHZ;Qqb?HEon?~!bh!50@{@(;*h0p7yN6e(5l z40gXG4dIv%C61{ACl3V7lbp+53-n47nJV?=9pDl^P+{X0uF=HffPmQrDKRDXb6#8{ zrS?Sfchf4P-Taa(W0xMtGEJ9-(iLk6_fG86wanHg-WSXD5nA;m4aa^yMw1vDb)bk zJgGD-B`!8HA~ZO_El6!cfssBIGgln=j(PhoY|RsRzZot;CQ8e9Y|gCB@S8FEn4+<4@V^;SvxA2SH-tDs z0yc1rLb1YX#SI`Rt%N2Lp_IZrib`O{2${%?gQ3J4XO(#2p@**bu2l-Nf9YMv*Ln+z zr%aFW+^yn!JtKuSe2&T4PH?moBZaXvL$ZP^g)lBD5g15Hg;G*X1ujZSP!cy~Sz}0q zL^NyViKQX_ZXsG{XO)dlxT`B1h?tOIovMg&!Fmr5Gk?t!lIqVxMf=`I1GO_tCmx%c zmOSg?yqd1%!Vj#9USIXE&{9L}fZ*J!*rcj-wQpLL;_^#*vkz4J!~}Z| zTXUgy(xug9wFmw>ZCvZim-lpJ^p<)>7=m)ESB;6#4Qm!5B&aA9eYCVg~5ZCm!Nqjh!1=H|TWpD{WiVRX7?@szmH8UB9031yK{ zC2@m?#Fs`zmc|c}qFcM7y$Z*)rcKyCDIsCf{t0PqV+sdFceU2YBBO^-HKcWn)c5uA&oM)0 zOPxXx8|VkcX9Jm^IGoucFaNMO+^7#{X!C+;omh!B!FU=e4(CedG!dU5V|T{V28=j{ zQ}qg|9H(fM52z%Hs8pT`cN`3J=Pzev2}wN%#Rg%Er^ib-_^dzinb*lno#5G0y4Vdp zQ!#%7h6npN&I>`u#F1blX{#tl83W}hkD?3G)bySfaW{eR<#WATpTm2nF?x_RR32U8 z7~Pcyjt@)>J}oZlSs_$qWr>Ynn>IXQTK~y40 ztasPtMUUHDAER&BGOl1jTWz>+bZkn9>946}WvR&}FlDU0aXNd8;tay65$xR(qYuIg z&q3T)s3;UfTN_ZO=L#0bl?p|%&+R8R_dKaKuSY^{a72(}^~%V&RW(edg1@k}l~ufe zytlFjYrAx1sgHT2U?5;C3bu{E`(nT51|7A;snAAdBQl%O6i(hd&YkAimT?+h859zX z|3U%+>}Z8gW)oytxPa|ouBWIpJBs)O%N!vf_(?z{Pfde_!~_@foWhmxFA0h9u8@>c z+93MpwU#6fbJvbbh_BSUsq9k5%q=Xc9ULy&I(ypt#%NuosD{lo6OPTymh4~uOU9xI zwRcv2k!H&qYcdszv4`GWG5d)XIlW^PQ4t!0Pq3SNZKD`mW!zAesEtI*g#!H+XJit9(omX?}Thn(Pt?DQR z|FiNGNi+`L+X(Ni!VDg0@VBEyHs(|~cATV=T{tCbkUOCWTn?PL27#`gT)8NYHYGRx zo4@l0fAtrW8!tb>hnenI7=Nu0`~*a>BHMx97o&GKreTq^qPK(AQ~xTC_)a8`CND`L zcnVIH=Aqo(8H>~f_`7S|)q_0nvMXjj_i(+l##dA+tv+7Goi*kFE;vwcsc3ib*Csu* zuAKAPP3hwe{-tZKw3~9#GY`Xr>gmJkcL3y=FpDBzyvhKd-wmo6anN_W6 zEe9tja$$!lnrl)<#3hbS)9{D5PkdQyVtK45WvOZqU$?=ILs_#qpbn&&NfZ6QFyb#JlLj&AG15}7mWi3Q-5^pwkPi-Vr4bh)@hEGV8 z+UzP;KG3o1>dI_vH?O+7V#b3@OYLtc0}b`rl^wZ5hGcgPTfEYNKQZb2f}DxQuU9{} z>YMI~xeG708zz;66fZhH=7ri53kx@|AU#+INzH_$9I;Z>8A26^Mfytyu8x$z2{=0W zIC(n{Ktl%&O}esFJl$aiqBF#hh%{30I^MMNde<1v$DI6n` zoN}*@Q*288ioLxDz85d_=3u|Gt#=3YhjlM!V-c@3W44ZB$%ce*hJ+l{TEMYw0fD`e z;i$2Ky8o>{IJ;W}>=PbHzJmm8nVzi@Rv}5}NmH~d%|Xq9O$)aUTk+!hB3`)WnZ?sC zE-kV9+BV2glTq4U=+C*fWcG0X!mI>m!E}>L%sSPQTAQsc zS<+Q=x#r}OQf}+!=gGB?f`aAXNUqFnjlmZjp%9~<QzZgeNF_Iyv1#?ZE$e zjOD-($J$|fhE5a$eK#nstG4i8i^FA}+ibB*A?|A!w|;aizN6OurtkA!&_ zObOu1sPnwHcUjLX==mIa9)_M3%*)^*`&5vC?=CDlH;`iEK;nm=UPt z7XQWR6QH(UnDuJ~|4~@nn=c&g-D`4?M}r%Xa!|8nz6Ku^vR9Z0C`Xu90#VB3JG;ny z)@bD{J$KbhIp3Rt_zypD`XcDd9uF|qOZ)Ob7w6uYt(C*t zvwgTQf7v&eTH7vtz3h=u$G0x1ify~}?J{B5(IrENE1EF9n$&!JW(I#cFner5a$Q~!eH~EMr;yHqOG6MD zh8cq86?3slN!hADU|5(nA*1qC1)B4!m>v|g6!Z+XE^uzI0HyifF(onoK4kh#ofov~ z+2sb#2d9jhxxISz^O!Qe_sO0%a%8)~%gfL{a@5ppAEBdo%j#K?Z*IM5V>ji}Kj%I& zy6e7$HL)F6zF#4XJh{BGa>dCJj}`A*Hf-3^{l&z?J>cOs@X!T2G2r0<@*vjOLC)P# zTzgwZLo{I;%i3RF`CFLC-8Gin20WowSoGr!{?gRPJ4=J}8&Y{(AM5?)gS4iikf4I* z%=d+)URWqkY(L&nJg=eHyLZ2X@T)&k5$UxC4b31E`o57Cf}@#CZ-~BkzXU36*)h12 z7)VP=h>wa0aEnyRK{impF33IZnD}YgCV{(_g7s##6xW3hZ8wbST2WcK_Q3{39TohB zA~2^eGhu8_P~3?2)S8ovi-&byZp>LZucb`Kzf(k4v}PsL=7;b(aYNH0T)m20H`mtQ z*OHVq>sVuAO?JRw4k4_l_%@u&5-vAxq<}#~elHaHRdRz^frPR$X?2gU&NJs4NX+zl>-dA~W=oEy+kNGUY&D6TYRd~V9*O5QHz z{7L}<-bbndwnE-nZ5U#wKo7ha=u87iU=`Xm$yv+>0k)B7E4R;==R28R7^0nP-klg;x)v@m|y8VxDrNWqmB7 z3lXsw+`qihAz*#X`>l@=3dq4x-qTN;M)I?Y*KT$_s(O`ZrJS__*qL+IpmYXQDh;uO zoHlpGy5ZV;Le~2VK2Tec6(H)GkkD8hT_6Va)F>i;FSBfs|@!!#pD&;Mh_l2_(^bZ_{U8pds%-}l-b7y&ug@R#xF<8Y@ke9N4g}AQC!6v*ei;}dieHU5s3CN z3`D1QZ68!WXxTuZ_0yO?nR@YiQkS?hyyWH^q}jh(@#vUJ3cqp-L3bl$jYoJr`_Audqm{9CHQ$q_`Ai7 zo}G99!v&)zc!nhSWzHFw6g6)BIFoO|tZ?V^o`KO`f2kdtIh zT4MA9V+J^KN%Zp-aCVax{$O7JJNPP*I7khBz_AS49*~o1a?*j-P`E=2H}l>f!p^&! zz_2JeVfC0k2u$z1Z&up7TOh$;8yJdkEI?kc$lEDF!72);Eoo@;hP+bcY)L~)!xGyL zPHfy7XaCN1eP?aUp|-^9UdeU&Bin`yX&;qao8m1v&wXLru>9Es-be*U*;Ds zYe+87G-YL0B-Sm%{LI->tXNZ^QQ@rBx?;sLMIp%wgJ`1zWLOBNgrb~yLE0IoByhyw zzqBh9peC-I`Kt%}c)B~-DHSZ7hpQ}kM*G%v5TrZa)TT0%$;lMFTnw1EA0h!j}||mfdf&q_KN@TW*ka|7~xpr0;1$d*4>s zViSQRZIL_Pw=PEex42u<<`W1Wo{+QFl1s84ut;>K9W<=v7o<%+)L6Y%f8!ko{pRrv z2dAW8ADliudsvH~-=v{AjHb6$`1u{m`Pq-jx4qK0~F)SLwcs>3zmgFIZE9qgDN z_oKA20xMG5POu!FK&)#?bIH348Z7UH?Q^egEFZr9O7rXo=VkP|C}S(zvugH4FZUkS zv92R_RBn_Vza{#m)woq`cw$QEvcGOCAG-OOSranbhDH=-&JQk1)`~|0@)|Q;qO0@6 zpr>mwqs_%0rWZ>z#5rP_mJ;awQLUGX6g{vUd)+vq&?Z)=}-2~ z^QYxp?3s(v7Mey$@!(@HJn(&H2jPj+L@Xv+P$>P7kM}_K${i@l*-bp*zw^Z6S=2~f znq7(PRm|IZBmmjUvdGE;phKB-d_{I8f6xqP#sfoxg9BZW62j({EEgP}&^udpWrGtf zJ|o_|9QcifEli(&q^W+B-tL{kWe>LLrc7-Pn4Z3|B&{JgP`|FG@$mHY8@?I!*~44> z)GZa+^_hNVjmyqxyY*@N>6z)S;dwEe3p4!js3eR z1`ZNVlXoT^X&kY!De1aj^02t_xk1;ji^nU*#7;Ufqj!REAfq~Ea8_c^x4=ihuXix1 zQt<|2C3hBK2(um)y0askDdR)o4Q)>bV2=>NhRo^P*@^zi^;d)}p4GFMSD1`EtuQOQ zs3<$DP)h09aP_Kio`0BBRFnjuk>4|wh!ZigC&P}GA=VyRV<&S3E<{!a^DaE?N<#-M z%e^8F6x{OyEe9RUGNvOO@;W%)S<@dE9wmgOO*=73Ul;A<6crQU5HU1WV|tDU+`;SC zrO5{-#i{I`MxK&;=tpLXEAJr5@f9Lee5lLAnFhPPwG#gd$$t)6T0*r$yT7 zZkTP*017=>lbJ%&Hs&U)9AZb5lKH|yovUn-auTVZP2vELB+2?{u}n*PsoLNOx;&XD zOj9donEI1L8zM42e8zy(uIAzE8WUyP96BrDhLp0ivO2o?==9#P!r`1T37+|BJ^u#E z0-J*9WGpbI6Mq@jBPy1xGn}EtB#_^uBPzeSUkFce8OQzP6w?24)^AGQvPWjmd30HB zuDQ&+?w8e+m(!T#=aGxMReK9WTyupZ((Y5hJ$0IJJHVsb72Vt_$S_sM_ER@YR6VgAJ5^(^FII6Niw`Vb{a#SyetpB~4e5lhQB`Hq-M~SfCJ1{ICE08l`3F26f zap7+F{qF=ZwX z^oa;m4{%E=pO~9HXH0y;xW$F))JPxCz*rw2UBD1WmxS`x!ost8rjc>C5> z;ct!(z2O*vvwDoR0kz*`^fGVf3V$!7Hxt6JGcD(xre91yntn3yQGYqJyet9?XMc-?WxixhWRK9OmWa?rkZw(?S_BgOl9~_X*DcI1kP-ib^FT|`M z68Ui~9)q;;u{dB$XVN@_H&s^}p zM-z|V$u&|Yo3Siwu90KH6dv#DGBv9x8^Q}f*%vZpSY_HGK?KS`5thpMm;n2qL?ID1 z8lBKN9HszeYJ3Mm-+zEQ_i%*=j@8A-CD5rdIz6R=ASF=cp?62JOFmo03lj4~26oJv z)uHk)&i2WlGBP#DdHI?(%Uwg$N490ZZzg2cLoqQA&o&dXJ|wrMr6caxh6Tp?>xtg6 zxgn5k0DcF1y%>qr1NQ#t(;C6m1?ypXRcytXi8$IKZ_|rxXh3MtUE68FmJCC%Wyxqw zEv=8JoR$+&QBoWdR~ze_5bAYAS2;Cz%zdQ^H8H*kA%lc3i&xYqIs5CiVNru4)BW9w zm)6GTXGKH|i81(NWy8NPtr10>fD-Y$RH^1DfsPPc5=mB-lLH+Wx?+6X?Z-$OUB)8I zoX*9kGB~k^(=%Wx0%Sq>#O4QXN9U60e3DSulc~tWxufKip+l*gO?~z_XBdQ?gc3vH zU@t)-;`<%!QewyH?qrpS-FH#Zh&%@#kCroASl=tQmSw?uz3yFq1m5V}%&lkjj)Q317ENwc(PTE!HQJSdUXt@}V#=gmm6w z&ERV|3wIB23v~8yc6PI;GfSR0{YZ--Itvr5jn|t6j}?bGT7(&TYTN}u<*N~%ymhU@ zOXI3i9@%G;JNINGj`pT}<)2&<5>}MxXTy_(v5#a=k9g`SWmION-;;m(dE&7tsmYVJ zk4YLDlw`C;1lo)I`NCv$geTqqr@7M`h*qjHZok+Mw{DnH#64tuHIvkT!GE+@R1v z|EZgLv!X{#%Q8$G5slK2g|a+4Ha4<(OGnzK^5Hu&=4_c277-aXXX}EDZI$Kg)23|| zJPQ|%i;o|-sIYKhO?-UKLLlx189oL-X?X~G8~vi zJRql3ZhZ2|C#LU3pPtXf=LP!VM>fI~AgzL4mS8rWY_J_OGz|Mp*xof8e83%>!y#Sa zb|M)`4U7DWNUEB9n_;>a@N;pN05w+u89QX8CE+YvfJd0T1q(TnH0A8E6rb2npz_YF z?0c=r$=iyJR@k5o#O8!j-gNN9cQyFJ11?%xRb82tSFrMt>DkNYG?#>3j~_89-q4Vv z^($F8Zp!`h3{{m`xdkg9oiY2-75Ue-IZau4O<8_Eg$wJa8Rus9z7jq(AUT09!-r~< z)6^x4__MX^!eZApR(Fn%aS6>Dzo=5k9h2bU9hDUnlB$my?3>@XYTVe)@YuCYBRd=7 zliClr#Ei-c91@cis7sHH@b)ciShdXF%h7#wN`xUUYOuo~N6%5op_vKT+7+-D^r85M z;w3~bSZf>HD8yqmWcazr3w1 z0I{e;^ka}MUXGOn*=-3cH$Y_OV{CTTV{BGa#3?`}eoYK6$fkzb*kHY*RNB_yh-RKG zG^sE@BaQ469ce@TT|)isDF7gcemjBe0pEkQjvN6{$deEs*iWGH84s&0E$K{g{F<3* z^>lcmJ`G>e=jH??2DrN7PfkwnU-IT28C!FBZeHHp!!=`%%+0GAvGwVWj;FSa7_sH4 zj*h3dj^K~XnHg3(IctoewJdzj?83~!v3a32VRtAwgaGMGhR)q?vw`DSfF({R?vn!C#uu^|R;4YN-cmZcvf74vf3DXAwn7=SD+-XQr z)}3B4hgKWhLxS;tF%=OU9}*9AgMzg|LAInDcedveEZcKR_uCTz?ao;@=O7a|4@}`o zr_jXwu(WZRny%yPl2fya&g+IvFUW2!4RdfZt?^Eb3A9}soD$-eEIbvicMtY;QKyZF zn=)6Qk)@Az(vQUVN_i9WOjl#7bjt_&Xq+dx_=b3dMdBFBpy0j-bl+4!~3Kv0TY5PqN#Yih)7Y$C*R*Jdy!gV21& zz4xmxAr&YuMr0o<_CDXcO3c9zJW6K~+tF8&OQG|w$nD2716y+`maA;6E3YWHX_Wx! z;nN(P8&=S{VLOgrf>G7~Ht{4Ur2bEDP^!w{77}8}NJM~ z-{0Snc_{FajQM1@%2gX|Id2rC)mDwz0?mJ#G~Zm-z&2`XU=!AomrZ+P%BuYAZ8K-h zneGv$c1--#x&d+H)yST7$@!3X{u!*z#dxS-G^-1NPrjL6jIC!Yt6T?Uf zDut`~!R>lUPOL8q4=<`u zOsp#m4K1uo^oh{m{9A;NPn6cxRU1W9&TbrM)=9VER|n8ZB`nk6S`qx?loAtE3W35b zoFtICQd|HpL_(1QB-!vXL* zetGDjK>=>TmgC#_30=&MX1{Fyl1!d(RVob*&K}@?8L^3R>L|YfSHjAt6>K`-6IU9u ziO&@FE#x+dBL{~ixN5?^i08|uhZW=%h9bYt^}=THxZ)9Ng2 za{U4d`Uad%=M(i>!Dh4}!*Q_AFDC0sR7GoA?zBo>fuX20X4I_Qq>fSXSMt&f=|$P2 zrPc(Ui+a$25N-VMWM7;>OiZa7=zJ&2ft}z59B!wkMlAWx@S&-rKS&$&>Sr8Cz zIRN8huqDSe9qlIFJ_PdrXnPO%xQc6keCOV~s#aO8R;wt@=te)<;U5ivI9g(qy2mlAv}NYz$c5_nX{5i!J3a=~0q*f%9KJ0Uo}c}=5hc!p6|*%%>YsrB)Ni5bm#k-I!}QGv