From 4bcd20468730b646c769f7a2ac4428ddc9f8d5e4 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 22 Dec 2015 18:22:51 -0200 Subject: [PATCH 1/2] Use a RecyclerView for the Contact List --- briar-android/build.gradle | 1 + .../res/drawable-hdpi/contact_connected.png | Bin 1316 -> 0 bytes .../drawable-hdpi/contact_disconnected.png | Bin 1133 -> 0 bytes .../res/drawable-hdpi/social_add_person.png | Bin 1784 -> 0 bytes .../res/drawable-mdpi/contact_connected.png | Bin 1025 -> 0 bytes .../drawable-mdpi/contact_disconnected.png | Bin 484 -> 0 bytes .../res/drawable-mdpi/social_add_person.png | Bin 1496 -> 0 bytes .../res/drawable-xhdpi/contact_connected.png | Bin 1094 -> 0 bytes .../drawable-xhdpi/contact_disconnected.png | Bin 1168 -> 0 bytes .../res/drawable-xhdpi/social_add_person.png | Bin 2103 -> 0 bytes .../res/drawable/contact_connected.xml | 26 ++ .../res/drawable/contact_disconnected.xml | 5 + .../res/drawable/social_add_person.xml | 5 + .../res/drawable/social_remove_person.xml | 5 + .../res/layout/activity_contact_list.xml | 33 +++ .../res/layout/list_item_contact.xml | 51 ++++ briar-android/res/layout/transports_list.xml | 5 +- briar-android/res/menu/contact_actions.xml | 12 + .../res/menu/contact_list_actions.xml | 12 + briar-android/res/values/strings.xml | 2 + briar-android/res/values/styles.xml | 9 + .../android/contact/ContactListActivity.java | 249 ++++++------------ .../android/contact/ContactListAdapter.java | 230 ++++++++++++---- .../android/contact/ConversationActivity.java | 90 +++++++ 24 files changed, 505 insertions(+), 230 deletions(-) delete mode 100644 briar-android/res/drawable-hdpi/contact_connected.png delete mode 100644 briar-android/res/drawable-hdpi/contact_disconnected.png delete mode 100644 briar-android/res/drawable-hdpi/social_add_person.png delete mode 100644 briar-android/res/drawable-mdpi/contact_connected.png delete mode 100644 briar-android/res/drawable-mdpi/contact_disconnected.png delete mode 100644 briar-android/res/drawable-mdpi/social_add_person.png delete mode 100644 briar-android/res/drawable-xhdpi/contact_connected.png delete mode 100644 briar-android/res/drawable-xhdpi/contact_disconnected.png delete mode 100644 briar-android/res/drawable-xhdpi/social_add_person.png create mode 100644 briar-android/res/drawable/contact_connected.xml create mode 100644 briar-android/res/drawable/contact_disconnected.xml create mode 100644 briar-android/res/drawable/social_add_person.xml create mode 100644 briar-android/res/drawable/social_remove_person.xml create mode 100644 briar-android/res/layout/activity_contact_list.xml create mode 100644 briar-android/res/layout/list_item_contact.xml create mode 100644 briar-android/res/menu/contact_actions.xml create mode 100644 briar-android/res/menu/contact_list_actions.xml diff --git a/briar-android/build.gradle b/briar-android/build.gradle index 3e6d17c84..f06ca62b1 100644 --- a/briar-android/build.gradle +++ b/briar-android/build.gradle @@ -7,6 +7,7 @@ dependencies { compile project(':briar-core') compile fileTree(dir: 'libs', include: '*.jar') compile "com.android.support:appcompat-v7:23.1.1" + compile 'com.android.support:recyclerview-v7:23.1.1' } android { diff --git a/briar-android/res/drawable-hdpi/contact_connected.png b/briar-android/res/drawable-hdpi/contact_connected.png deleted file mode 100644 index 9fa452b33cdc41c6771b7df4bd6d24c60458d851..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1316 zcmV+<1>5?GP)Px(-bqA3RA}DqnNMg`R}{v-@4lJI%p^0(jJ28svQcZgh~hk?i&9!^5u~d^7D}Md z+Jy_DZUZh0Ze6%=p+XCxE(CWK#D8rmSmZs?bfK8iHV_7Cok?b#Ofoa?eqH1R6s`I9 zMlH;@oHzI0^SkHVch5Nw=%}NPI_hWxV$>75uIorjlI#J{9sXPc@I=yr@B6_U3s5K& zvH(U%ZU@i@AR9iaNSY-%1z^(iyviE`P$(4QBzH>MPhywEge(Z41;B=XGXP>V5UGZQ zdnB((df@wh^R)rEuDeUpL6SSIMSQ+&D)FSM?;Wn~&b)26gb)A_t3BpFKb_6o2GEzz z*(|9hfCnTmd!Bdil>)e~Ya|^a`3WG@D<;Sf1?AC`<>L}-@ucmhLHy}4vS>Byrb?rp zi{rUdrD-RZ%322?BwZzW!Sg)Zc7Q^mkOc5KiTADLLL#N+*y+-j@h+u;7Dc{%P6={i zVsnx8iDUWmjXLATC@J9=0N?q(ztA>-LZLvCUjh1XuIQ9L`)2N=p*@X3<0!xOy%21` z()69g%%u~(H+%boJis3%o%MZRtDVJJ%aQ{F17m>p%@v*5FV2@n`-hv`NTj5dcm8=# zP{t^o8w|D#f4n$!YogmrX6!ov(#2wNGID@Ip)f-7u(fP_I$rspf4I3#A^>8o#sdh) zER9cPZD#9mEB*VgU4I(GZ36=Xe-w+wzgIJlS>>Tk05}K;iIkc{dm4jMboYk@4DD$Q zCQ@nwf~14tn$Z9N*iLe|UNOPg>CzG7C@)db0Z_(Ke(ZGVNWEeL0K)*bM+PA2fVD{E zhl1I7my+uZo0Y;T-lb%ID43O)0B|4@0M~W9NsP>wO=a|C`FPM`gu(Nyf)+J;vV45L zY$||8T-WX15I}fg?FNttS}0k|CsFSFi#%a1p9C$G03;;sc3szO!~-b+J8VF+?`U;z zB4sn}PLC5Qo7s1?y4MCY0Cq@9ts6j6Cd?|E-J7(T2C=s1_Xe@XOE)d{ za+fjaVB%yII@x+hBmAZ z!1sL%;4XlM6GPq@^+-_r;vF(ZJx&aH01c9NLmSqA6Z^hj12~z^+3dyf+$krfwq0aS zOuRUrJC)AaEWk<6^J-Bgb5}?;O4CkXbCC;686yT7WZVy1Fwp>bp4T9G86X;U#;5NjW*A{0k-+qw z#7v{kcv$3L_B^i>kX&nupx!=Ossh6MDI;wlmu|y z_x-6Vj|0sa5lDo+*ohU6gtku?rh+e5Sn)V2b3M)n0$W`EW=kB|Z0n13=^-I6CU6qmDY- akp2bu44pSGze%?M0000~8k} diff --git a/briar-android/res/drawable-hdpi/contact_disconnected.png b/briar-android/res/drawable-hdpi/contact_disconnected.png deleted file mode 100644 index 9de4968499c5c464a53beb423088bbe7c618b5b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1133 zcmV-z1d{uSP)Px(CrLy>RA}Dqna^ufR~*GZXGW8#F$p!Hya!68ih_;8d(cH))S?J(Tw4U8;Qv%; zS8WkoyAdRc&~{bsZB42uO3m(qLGVY6COUJv@Cvr3m`r9y7jstgW|;f^o_oLde$PD* z1{h#~0S4Fv)a?Q5x^CJYku(bI$X`DLmTbR>F}6Nh0##Lw0W*^J0TaMj{^^PBN0ROV z^C5&M9}R)3s-m3Uott(DIF%olBwgra!~GvZ2yIChY%kfy_Ng4R zI|P7zk`CG)mUJnEu-NSm9zs}@bO{&+4g&kSM!@#Tocuxv;W|A+2;sV<1xdre$*vHn z>v{(;1GH_=_CcS`+HTvP$+0^pkQ>&Kd`>?BZuUBR+c$HpA=^jlx^8S{1-1eE^J%pR zEcIapma+_K0{d-m>zF|9k`t0zk{$xDdam!KS6NH7BuxN2J0>7$yQFcTW&814+NPIi z0gr9BfN@FNH?sn7lOf9o`mhhy{M^YNSk5!wv^{RS*@yg_S$;ROG+*8ffv3QuJlHN^ zOCJbq$+4O__S4M}cn;jP-I6qw^?a|(XH?RZq?YZwIfu>&WU+Q5>;5rGhx)Jrhis1l ztCDWKPcXi>6KA~y8$a&3&5Z)`**DL0(04tKFtExKItIX@VK9(;wE4Ht6 zQ;psOZs&{m>AJ3`dXW5-?bA8N?QFqxhd>BnRnq0$4@QBrRaG^*m3$uSY#tlimqQ4v zUA>W|lpYjCu~X6kpajN>qL@o5d6P5WkaQ0CGUqcJV_diD-B4pHisCO|Qqo>Y)4=Yc zDE>|>=TpkcesYl9ct4M~kma21#Xt^#*L2p`VeU4zV+?V0Q-Oi22dy$;-y z^l{niYwVAvq!HWiyx;)3{(@tG0R|XgfKA~a{i+eJYP;8)00000NkvXXu0mjf7%mje diff --git a/briar-android/res/drawable-hdpi/social_add_person.png b/briar-android/res/drawable-hdpi/social_add_person.png deleted file mode 100644 index 38b91cc7ce29dac49f4f048c4e7738bde2e41bf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1784 zcmaJ?c~BEq98QrK1eK$V4IsJ(JV27{<^Ylq&ICy%luJRBmK+NNNOrSXAYj#aaCo#@ z#SR{Lj0ei02(1@LMUh4;M{AYCDpW-*RY6B3)T7-XVE-uHncer^Z@%yQoo{wyWW=Ir z*3Q->5^0(wOcYJ5p!v0$Onl=kh6{+r2^YuXF-S6=EyG|^kP?x@fJ7}zfumuWGDmwA z_9KxdxvOI1@px%CUxBC@GBbvuSEB@*MDh#JqcTN0j018wMWqqa25Ntx0V<`C7RQx> zQZxikRfXkZa7=DQtRgpE!Bf%#`~g2bpAb;PxD3#%Gc-EBUPv3!@fLT!{M>26CjfnJp3Tkv*R-+p&6HzdxUWPIu253%c3@DZUKUA$AN9*ut_(Qz^ zDXfdlL1AVztV1#}1<|-jH$9bUpv1irC87-4s_|Tz18-I1t?jEuUm4! zWku<>d^_Ol5>idjzLw>c&RfZ>g7#KQ`z1TOY;C2l*5SIPVn)i}DGm{Ht0*r-9)ZEV zq~hMH{`<@Fh6)SwqNZ%ykl4I)NDj}-MI0?SRdWpk+Y{rjM#g$3Imchpzfx4&#Kc<_ zSr=0h`op_&G0E`s@MJ1kcC_{KjU9#qdyWL|k84ePBlq}~zVO&e^t_SmvV`7aV}w3w z{3dAArdr1~iT%J5n*~+SpGR)|ax4)a7A7XSQZ0}}zQ$SAaHwra21)hL&o7-nms8>t4GE zU)^|67{;noKI*p0Z(!eLS0osUF0M)_=jM!~^fwvk9KZdI)h{XZId+GaJbJ^ZUtZnfTH3IyquXayeZodfQ@wrk%ksh6 zq32cQPcOzg47mYU(qgvcrB~N%j<>7O={k|=__BPH$VhX4c;;CWXZ@#go^&9e>i=ra zn#R`aPuzQWQR>jIS`WSmUR|+%P6Fn8A@gZIel{ROaH!^x>y`w=cQXp8{45uk@j~E8 z&GE>pv9~mO`e*sh%$&8)S0XVv| A7ytkO diff --git a/briar-android/res/drawable-mdpi/contact_connected.png b/briar-android/res/drawable-mdpi/contact_connected.png deleted file mode 100644 index d91970da5b783896c4d9054cbd9e37538fe20d2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1025 zcmV+c1pfPpP)H@rHO9+)AU7ayfHq@wV)tx_}1AE)4 zQWmyIQHLt5VL(L{^?NZL5;Yy#3fUMH5-8xc1S*{R4Tu}aRATr5QZUq z-%pd6i45+THb-;$DCM|_0Kj&jU)1zTV#w|~8V^NK4T9jL7kg;{-}ey&0X)x}QHr0w ztT{uI3oU;1$??b8k?1BJxBwtl%%8iu@%>6>?fH6AZWN+d*2?`b46D6w#0Dr9i>Op8 zC>H(c)-gZNPZ_tobWqL?+nc6M0E7tS^+yN_v@1B;SAVQ7=T;j(>vl3DUsfu?)_D*E zGEkgppWw6k#p4gB%gs3|Xo3W#PpAMw2t>rfY^|n#*jULtO{DDCVHj4=+C!aF`!p%{ z@>3?+-JF^v1(5#S>>`k)qMj}{=kik~sTA+|zMqZ_pcJQH)|^y%>EJdMG}+y?_w1X_ zQ){T8%S#8hU(}owi0Rk>k-^=`g_g<=+Yy57)%zk6fe>VN*p7U#&{7idZY%)L^C!$J zj?6C}-!g3ilym>QZzd=(ZDM}$_*SQh5zq4{E(B02l|YK0D@56Aqb3jGCHoZtA+C*@ ze6A2>N%)@U4F<5*YLeql0v#&q?xDM!1Q04}CxH&hagur%9i+K$pgmwiRE19)K3VUG~ZpZ2abmYPF^`t%8S9=1HxYtl1 zazeQ&NcG4z&A+o<0-26R%;JXCw%eR2KUXOD*(ZpMBURD!Kyv50!T9)BG7Jb~{Q zXGn=Px$o=HSOR9M69mOoDdK@i1%iV0LEBxkdb&|*R3bT&d^)GtD7gN4MJMjBhbh#Cv| z0;2^DmMCNk&k#CHG_jc$?vF>%gje3pynQ=6J8xlw4c3gUG)W>-25LaXK8=8Zs*YDG zKt#@f6JQU>0bllO2lxiwfqPZG%~XJhRDcVh2#kS8-~|XRBmnk-BcKdSfooMA{aS#C z902FQ9O$X4M#Kxy1PZ{7sy;1?&&AmJCGY{XRP`-Nu=n0O=N^DVpy8Z*_TJAH#cxOO zwQT2YRsD>6t`^(2+}5(#?TCgeTG{7GyW4VlK+(7oSKt(wM4fqr2n8m_6<>he^8n~) zFl+iiV4SflP_qUdW*}f_T(u+uDmG-o3w!CG>J(^-NFl}I1v91TGJB4? z1zmHsj)>$FES?8CmfKD3hTi*`bM6&r0LRWb@4fdi%6l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVi(%+%Pz#K_gu$-u?X(ACh=#L&{!#L3yw z&D7A`#K{n**Cju>G&eP`1g19yq1O$kUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dZnrq& zG!Lpb1-DyVaO%|uIz}H9wMbD769T3m5EGtofgE_!Pt60S_ab1zo)^j5$H2hk<>}%W zQgQ3a^xfXdfg;C@11G)t#S$2P&&{U4l3*4r$lk;iwzGo$aKRTIb)Reg2}esL-!-I`9lF0D@Mr9- z%L+gE#O|0a3Q09Sopzc3*g-~%E5ypy*i z-z?~NcHb&sc>(mdKI;Vst0IBOL)c^nh diff --git a/briar-android/res/drawable-xhdpi/contact_connected.png b/briar-android/res/drawable-xhdpi/contact_connected.png deleted file mode 100644 index 4341f01a1a16797592c31e81c119d260cff7f9c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1094 zcmV-M1iAZ(P)Px(07*naRCwC$nmuS;Wf;eQ_v_@li3v4Ut)bPpv`cs>=#;woK?lLXK?(__;O3-L zrsANJvxEdnhYqCPBj01N}K=pJAbcnUlLiom9GuJ+OxU}inQ zY2Xxa66gbZfo}cFbKn`U4XgkUfFDa4^RebKvnlSJum3KqUV7!<4@oh=iGx-8(?Prz{kL(>Uv3! zx`6fJw<=FR__Fxn;A^#W`~AMSnqBz$+rgVV8`)7{2-wx5KyAZa;8*9|R_Y8evp0Y* zfU~O8IlX^ndVX!@An%-;8o8o2qpob}2L1r9Ip_XOjR9u%E^rBWRbRaecsM=3_DvM; zpPL%_4mhEV2!O}HtaI+Kwi{q(s25(dAZpA_WPyJqpV){?*-TI{y6YFjG?yS z2j|>k+YB(X*H!rAYPgu5U%M1%&oVbPGOIuHz^Y96@1XC?9mb%zZHmo#7YQV4>ni^0UI9{7biveN@ z*AV)|8jAtF4O7#!sVcVKxC|HodX9hrJz|Z0F7Q&Q6$6SIcV{#aNt?nIs2#CJZom^Q zLZsb*XJU=TfNlLIUtG;Dq^0Cy$%}0}E(12%+q5VHnV)8cZluKkv1G)yBGwlhM70oS z3s_QrTd(Y9PNc;Eu~gI(EQvMR3~fkj|L-OW&n>i>|KHh@L3M&AuO=gPo>R$_Lw zZr@gkAzUtB5M!+C0l%rC0eCY7Uq58n7F+BKBFpUU)fMywzHj5#4`Ua^v>dwus$aL% z&{TlY`}czDNf%x*N5!xO+-jxnA8IJ1iDkZvpO0-)Nk zW0OSc&#KD{#Be)_xj=IkYynr<+o;SnfF)7*aOnFOxO$lFa=$qm1zbmOk2jdmxd$W~ zOz7MrGEGKw<{_zljOff`a{Cz3nFl4COi1NXSuZayFE1}IFRxD3|8PgMT?Y<&b^rhX M07*qoM6N<$f=^ryhX4Qo diff --git a/briar-android/res/drawable-xhdpi/contact_disconnected.png b/briar-android/res/drawable-xhdpi/contact_disconnected.png deleted file mode 100644 index d0499ddf1ffb6335c4b4f48d42ffed128d863a62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1168 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 SCLS>V%0;1(g44X@ynh4GY&7Bk diff --git a/briar-android/res/drawable/contact_connected.xml b/briar-android/res/drawable/contact_connected.xml new file mode 100644 index 000000000..95e7a0bc0 --- /dev/null +++ b/briar-android/res/drawable/contact_connected.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/briar-android/res/drawable/contact_disconnected.xml b/briar-android/res/drawable/contact_disconnected.xml new file mode 100644 index 000000000..d8ee38c1e --- /dev/null +++ b/briar-android/res/drawable/contact_disconnected.xml @@ -0,0 +1,5 @@ + + + diff --git a/briar-android/res/drawable/social_add_person.xml b/briar-android/res/drawable/social_add_person.xml new file mode 100644 index 000000000..982183dea --- /dev/null +++ b/briar-android/res/drawable/social_add_person.xml @@ -0,0 +1,5 @@ + + + diff --git a/briar-android/res/drawable/social_remove_person.xml b/briar-android/res/drawable/social_remove_person.xml new file mode 100644 index 000000000..4adacc148 --- /dev/null +++ b/briar-android/res/drawable/social_remove_person.xml @@ -0,0 +1,5 @@ + + + diff --git a/briar-android/res/layout/activity_contact_list.xml b/briar-android/res/layout/activity_contact_list.xml new file mode 100644 index 000000000..acde6fdc9 --- /dev/null +++ b/briar-android/res/layout/activity_contact_list.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/briar-android/res/layout/list_item_contact.xml b/briar-android/res/layout/list_item_contact.xml new file mode 100644 index 000000000..69ec0383e --- /dev/null +++ b/briar-android/res/layout/list_item_contact.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/briar-android/res/layout/transports_list.xml b/briar-android/res/layout/transports_list.xml index c1ec632f6..c359d7c1d 100644 --- a/briar-android/res/layout/transports_list.xml +++ b/briar-android/res/layout/transports_list.xml @@ -5,10 +5,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + + + + + + \ No newline at end of file diff --git a/briar-android/res/menu/contact_list_actions.xml b/briar-android/res/menu/contact_list_actions.xml new file mode 100644 index 000000000..718200a65 --- /dev/null +++ b/briar-android/res/menu/contact_list_actions.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index fe43fd7c2..0a7c7b1f0 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -126,4 +126,6 @@ Lost password Password recovery is not possible. Do you wish to delete your user, all contacts, and re-register ? + Confirm Contact Deletion + Are you sure that you want to remove this contact and all messages exchanged with this contact? diff --git a/briar-android/res/values/styles.xml b/briar-android/res/values/styles.xml index f40b8b541..0e0c2c0b9 100644 --- a/briar-android/res/values/styles.xml +++ b/briar-android/res/values/styles.xml @@ -33,4 +33,13 @@ @dimen/text_size_small @android:color/primary_text_light + + + + \ No newline at end of file diff --git a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java index fff550fc4..1edbd2d2a 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java @@ -1,28 +1,20 @@ package org.briarproject.android.contact; import android.content.Intent; -import android.content.res.Resources; +import android.graphics.PorterDuff; import android.os.Bundle; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; import android.view.View.OnCreateContextMenuListener; -import android.widget.AdapterView; -import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.TextView; -import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.BriarActivity; import org.briarproject.android.invitation.AddContactActivity; -import org.briarproject.android.util.HorizontalBorder; -import org.briarproject.android.util.ListLoadingProgressBar; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; @@ -36,43 +28,34 @@ import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.MessageAddedEvent; -import org.briarproject.api.identity.AuthorId; import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.PrivateMessageHeader; import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.sync.GroupId; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.logging.Logger; import javax.inject.Inject; -import static android.view.Gravity.CENTER; -import static android.view.Gravity.CENTER_HORIZONTAL; -import static android.view.Menu.NONE; import static android.view.View.GONE; import static android.view.View.VISIBLE; -import static android.widget.LinearLayout.VERTICAL; -import static android.widget.Toast.LENGTH_SHORT; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; -import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH; -import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP; -import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP_1; public class ContactListActivity extends BriarActivity -implements OnClickListener, OnItemClickListener, OnCreateContextMenuListener, -EventListener { + implements OnCreateContextMenuListener, EventListener { - private static final int MENU_ITEM_DELETE = 1; private static final Logger LOG = Logger.getLogger(ContactListActivity.class.getName()); @Inject private ConnectionRegistry connectionRegistry; private TextView empty = null; private ContactListAdapter adapter = null; - private ListView list = null; - private ListLoadingProgressBar loading = null; + private RecyclerView list = null; + private ProgressBar loading = null; // Fields that are accessed from background threads must be volatile @Inject private volatile ContactManager contactManager; @@ -82,47 +65,28 @@ EventListener { @Override public void onCreate(Bundle state) { super.onCreate(state); - LinearLayout layout = new LinearLayout(this); - layout.setLayoutParams(MATCH_MATCH); - layout.setOrientation(VERTICAL); - layout.setGravity(CENTER_HORIZONTAL); - empty = new TextView(this); - empty.setLayoutParams(MATCH_WRAP_1); - empty.setGravity(CENTER); - empty.setTextSize(18); - empty.setText(R.string.no_contacts); - empty.setVisibility(GONE); - layout.addView(empty); + setContentView(R.layout.activity_contact_list); adapter = new ContactListAdapter(this); - list = new ListView(this); - list.setLayoutParams(MATCH_WRAP_1); + list = (RecyclerView) findViewById(R.id.contactList); + list.setLayoutManager(new LinearLayoutManager(this)); list.setAdapter(adapter); - list.setOnItemClickListener(this); list.setOnCreateContextMenuListener(this); list.setVisibility(GONE); - layout.addView(list); + + // Show a notice when there are no contacts + empty = (TextView) findViewById(R.id.emptyView); // Show a progress bar while the list is loading - loading = new ListLoadingProgressBar(this); - layout.addView(loading); + loading = (ProgressBar) findViewById(R.id.progressBar); + loading.setVisibility(VISIBLE); + } - layout.addView(new HorizontalBorder(this)); - - LinearLayout footer = new LinearLayout(this); - footer.setLayoutParams(MATCH_WRAP); - footer.setGravity(CENTER); - Resources res = getResources(); - footer.setBackgroundColor(res.getColor(R.color.button_bar_background)); - ImageButton addContactButton = new ImageButton(this); - addContactButton.setBackgroundResource(0); - addContactButton.setImageResource(R.drawable.social_add_person); - addContactButton.setOnClickListener(this); - footer.addView(addContactButton); - layout.addView(footer); - - setContentView(layout); + @Override + public void onPause() { + super.onPause(); + eventBus.removeListener(this); } @Override @@ -132,12 +96,47 @@ EventListener { loadContacts(); } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu items for use in the action bar + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.contact_list_actions, menu); + + // adapt icon color to dark action bar + menu.findItem(R.id.action_social_add_person).getIcon().setColorFilter( + getResources().getColor(R.color.action_bar_text), + PorterDuff.Mode.SRC_IN); + + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + // Handle presses on the action bar items + switch (item.getItemId()) { + case R.id.action_social_add_person: + startActivity(new Intent(this, AddContactActivity.class)); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private void loadContacts() { - clearContacts(); + runOnUiThread(new Runnable() { + public void run() { + empty.setVisibility(GONE); + list.setVisibility(GONE); + loading.setVisibility(VISIBLE); + } + }); runOnDbThread(new Runnable() { public void run() { try { long now = System.currentTimeMillis(); + List contacts = + new ArrayList(); for (Contact c : contactManager.getContacts()) { try { ContactId id = c.getId(); @@ -145,15 +144,20 @@ EventListener { messagingManager.getConversationId(id); Collection headers = messagingManager.getMessageHeaders(id); - displayContact(c, conversation, headers); + + boolean connected = + connectionRegistry.isConnected(c.getId()); + contacts.add(new ContactListItem(c, connected, + conversation, + headers)); } catch (NoSuchContactException e) { // Continue } } + displayContacts(contacts); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Full load took " + duration + " ms"); - hideProgressBar(); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -162,110 +166,19 @@ EventListener { }); } - private void clearContacts() { + private void displayContacts(final List contacts) { runOnUiThread(new Runnable() { public void run() { - empty.setVisibility(GONE); - list.setVisibility(GONE); - loading.setVisibility(VISIBLE); - adapter.clear(); - adapter.notifyDataSetChanged(); - } - }); - } - - private void displayContact(final Contact c, final GroupId conversation, - final Collection headers) { - runOnUiThread(new Runnable() { - public void run() { - list.setVisibility(VISIBLE); - loading.setVisibility(GONE); - boolean connected = connectionRegistry.isConnected(c.getId()); - // Remove the old item, if any - ContactListItem item = findItem(c.getId()); - if (item != null) adapter.remove(item); - // Add a new item - adapter.add(new ContactListItem(c, connected, conversation, - headers)); - adapter.sort(ContactListItemComparator.INSTANCE); - adapter.notifyDataSetChanged(); - } - }); - } - - private void hideProgressBar() { - runOnUiThread(new Runnable() { - public void run() { - if (adapter.isEmpty()) empty.setVisibility(VISIBLE); - else list.setVisibility(VISIBLE); - loading.setVisibility(GONE); - } - }); - } - - private ContactListItem findItem(ContactId c) { - int count = adapter.getCount(); - for (int i = 0; i < count; i++) { - ContactListItem item = adapter.getItem(i); - if (item.getContact().getId().equals(c)) return item; - } - return null; // Not found - } - - @Override - public void onPause() { - super.onPause(); - eventBus.removeListener(this); - } - - public void onClick(View view) { - startActivity(new Intent(this, AddContactActivity.class)); - } - - public void onItemClick(AdapterView parent, View view, int position, - long id) { - ContactListItem item = adapter.getItem(position); - ContactId contactId = item.getContact().getId(); - String contactName = item.getContact().getAuthor().getName(); - GroupId groupId = item.getConversationId(); - AuthorId localAuthorId = item.getContact().getLocalAuthorId(); - Intent i = new Intent(this, ConversationActivity.class); - i.putExtra("briar.CONTACT_ID", contactId.getInt()); - i.putExtra("briar.CONTACT_NAME", contactName); - i.putExtra("briar.GROUP_ID", groupId.getBytes()); - i.putExtra("briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes()); - startActivity(i); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, - ContextMenu.ContextMenuInfo info) { - String delete = getString(R.string.delete_contact); - menu.add(NONE, MENU_ITEM_DELETE, NONE, delete); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if (menuItem.getItemId() == MENU_ITEM_DELETE) { - ContextMenuInfo info = menuItem.getMenuInfo(); - int position = ((AdapterContextMenuInfo) info).position; - ContactListItem item = adapter.getItem(position); - removeContact(item.getContact().getId()); - String deleted = getString(R.string.contact_deleted_toast); - Toast.makeText(this, deleted, LENGTH_SHORT).show(); - } - return true; - } - - private void removeContact(final ContactId c) { - runOnDbThread(new Runnable() { - public void run() { - try { - contactManager.removeContact(c); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); + if(contacts.size() > 0) { + list.setVisibility(VISIBLE); + empty.setVisibility(GONE); + } else { + list.setVisibility(GONE); + empty.setVisibility(VISIBLE); } + loading.setVisibility(GONE); + + adapter.addAll(contacts); } }); } @@ -314,7 +227,7 @@ EventListener { final Collection headers) { runOnUiThread(new Runnable() { public void run() { - ContactListItem item = findItem(c); + ContactListItem item = adapter.findItem(c); if (item != null) { item.setHeaders(headers); adapter.notifyDataSetChanged(); @@ -326,10 +239,10 @@ EventListener { private void removeItem(final ContactId c) { runOnUiThread(new Runnable() { public void run() { - ContactListItem item = findItem(c); + ContactListItem item = adapter.findItem(c); if (item != null) { adapter.remove(item); - adapter.notifyDataSetChanged(); + if (adapter.isEmpty()) { empty.setVisibility(VISIBLE); list.setVisibility(GONE); @@ -342,7 +255,7 @@ EventListener { private void setConnected(final ContactId c, final boolean connected) { runOnUiThread(new Runnable() { public void run() { - ContactListItem item = findItem(c); + ContactListItem item = adapter.findItem(c); if (item != null) { item.setConnected(connected); adapter.notifyDataSetChanged(); diff --git a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java index 1acb52435..7e511ea9a 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java @@ -1,80 +1,194 @@ package org.briarproject.android.contact; -import static android.text.TextUtils.TruncateAt.END; -import static android.view.Gravity.CENTER_VERTICAL; -import static android.widget.LinearLayout.HORIZONTAL; -import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP_1; - -import java.util.ArrayList; - -import org.briarproject.R; -import org.briarproject.android.util.LayoutUtils; - import android.content.Context; +import android.content.Intent; import android.content.res.Resources; +import android.support.v7.util.SortedList; +import android.support.v7.widget.RecyclerView; import android.text.format.DateUtils; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; -class ContactListAdapter extends ArrayAdapter { +import org.briarproject.R; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.identity.AuthorId; +import org.briarproject.api.sync.GroupId; - private final int pad; +import java.util.List; - ContactListAdapter(Context ctx) { - super(ctx, android.R.layout.simple_expandable_list_item_1, - new ArrayList()); - pad = LayoutUtils.getPadding(ctx); +public class ContactListAdapter + extends RecyclerView.Adapter { + + private SortedList contacts = + new SortedList(ContactListItem.class, + new SortedList.Callback() { + @Override + public void onInserted(int position, int count) { + notifyItemRangeInserted(position, count); + } + + @Override + public void onChanged(int position, int count) { + notifyItemRangeChanged(position, count); + } + + @Override + public void onMoved(int fromPosition, int toPosition) { + notifyItemMoved(fromPosition, toPosition); + } + + @Override + public void onRemoved(int position, int count) { + notifyItemRangeRemoved(position, count); + } + + @Override + public int compare(ContactListItem c1, + ContactListItem c2) { + return (int) (c1.getTimestamp() - + c2.getTimestamp()); + } + + @Override + public boolean areItemsTheSame(ContactListItem c1, + ContactListItem c2) { + return c1.getContact().getId().equals(c2.getContact().getId()); + } + + @Override + public boolean areContentsTheSame(ContactListItem c1, + ContactListItem c2) { + return c1.equals(c2); + } + }); + private Context ctx; + + public ContactListAdapter(Context context) { + ctx = context; } @Override - public View getView(int position, View convertView, ViewGroup parent) { - ContactListItem item = getItem(position); - Context ctx = getContext(); + public ContactHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + View v = LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.list_item_contact, viewGroup, false); + + return new ContactHolder(v); + } + + @Override + public void onBindViewHolder(final ContactHolder ui, final int position) { + final ContactListItem item = getItem(position); Resources res = ctx.getResources(); - LinearLayout layout = new LinearLayout(ctx); - layout.setOrientation(HORIZONTAL); - layout.setGravity(CENTER_VERTICAL); int unread = item.getUnreadCount(); - if (unread > 0) - layout.setBackgroundColor(res.getColor(R.color.unread_background)); - - ImageView bulb = new ImageView(ctx); - bulb.setPadding(pad, pad, pad, pad); - if (item.isConnected()) - bulb.setImageResource(R.drawable.contact_connected); - else bulb.setImageResource(R.drawable.contact_disconnected); - layout.addView(bulb); - - TextView name = new TextView(ctx); - name.setLayoutParams(WRAP_WRAP_1); - name.setTextSize(18); - name.setSingleLine(); - name.setEllipsize(END); - name.setPadding(0, pad, pad, pad); - String contactName = item.getContact().getAuthor().getName(); - if (unread > 0) name.setText(contactName + " (" + unread + ")"); - else name.setText(contactName); - layout.addView(name); - - if (item.isEmpty()) { - TextView noMessages = new TextView(ctx); - noMessages.setPadding(pad, pad, pad, pad); - noMessages.setTextColor(res.getColor(R.color.no_private_messages)); - noMessages.setText(R.string.no_private_messages); - layout.addView(noMessages); - } else { - TextView date = new TextView(ctx); - date.setPadding(pad, pad, pad, pad); - long timestamp = item.getTimestamp(); - date.setText(DateUtils.getRelativeTimeSpanString(ctx, timestamp)); - layout.addView(date); + if (unread > 0) { + ui.layout.setBackgroundColor( + res.getColor(R.color.unread_background)); } - return layout; + if (item.isConnected()) { + ui.bulb.setImageResource(R.drawable.contact_connected); + } else { + ui.bulb.setImageResource(R.drawable.contact_disconnected); + } + + String contactName = item.getContact().getAuthor().getName(); + if (unread > 0) { + ui.name.setText(contactName + " (" + unread + ")"); + } else { + ui.name.setText(contactName); + } + + if (item.isEmpty()) { + ui.date.setText(R.string.no_private_messages); + } else { + long timestamp = item.getTimestamp(); + ui.date.setText( + DateUtils.getRelativeTimeSpanString(ctx, timestamp)); + } + + ui.layout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ContactId contactId = item.getContact().getId(); + String contactName = item.getContact().getAuthor().getName(); + GroupId groupId = item.getConversationId(); + AuthorId localAuthorId = item.getContact().getLocalAuthorId(); + + Intent i = new Intent(ctx, ConversationActivity.class); + i.putExtra("briar.CONTACT_ID", contactId.getInt()); + i.putExtra("briar.CONTACT_NAME", contactName); + i.putExtra("briar.GROUP_ID", groupId.getBytes()); + i.putExtra("briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes()); + + ctx.startActivity(i); + } + }); + } + + @Override + public int getItemCount() { + return contacts == null ? 0 : contacts.size(); + } + + public boolean isEmpty() { + return contacts == null || contacts.size() == 0; + } + + public ContactListItem getItem(int position) { + if (position == -1 || contacts.size() <= position) { + return null; // Not found + } + return contacts.get(position); + } + + public ContactListItem findItem(ContactId c) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + ContactListItem item = getItem(i); + if (item.getContact().getId().equals(c)) return item; + } + return null; // Not found + } + + public void addAll(final List contacts) { + this.contacts.addAll(contacts); + } + + public void add(final ContactListItem contact) { + this.contacts.add(contact); + } + + public void remove(final ContactListItem contact) { + this.contacts.remove(contact); + } + + public void clear() { + contacts.beginBatchedUpdates(); + + while(contacts.size() != 0) { + contacts.removeItemAt(0); + } + + contacts.endBatchedUpdates(); + } + + public static class ContactHolder extends RecyclerView.ViewHolder { + public ViewGroup layout; + public ImageView bulb; + public TextView name; + public TextView date; + + public ContactHolder(View v) { + super(v); + + layout = (ViewGroup) v; + bulb = (ImageView) v.findViewById(R.id.bulbView); + name = (TextView) v.findViewById(R.id.nameView); + date = (TextView) v.findViewById(R.id.dateView); + } } } diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index ff90470fe..98dcd179f 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -1,10 +1,16 @@ package org.briarproject.android.contact; +import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; +import android.graphics.PorterDuff; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; @@ -15,6 +21,7 @@ import android.widget.ImageButton; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; +import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.BriarActivity; @@ -66,6 +73,7 @@ import javax.inject.Inject; import static android.view.View.GONE; import static android.view.View.VISIBLE; +import static android.widget.Toast.LENGTH_SHORT; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.android.contact.ReadPrivateMessageActivity.RESULT_PREV_NEXT; @@ -161,6 +169,33 @@ implements EventListener, OnClickListener, OnItemClickListener { loadHeaders(); } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu items for use in the action bar + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.contact_actions, menu); + + // adapt icon color to dark action bar + menu.findItem(R.id.action_social_remove_person).getIcon().setColorFilter( + getResources().getColor(R.color.action_bar_text), + PorterDuff.Mode.SRC_IN); + + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + // Handle presses on the action bar items + switch (item.getItemId()) { + case R.id.action_social_remove_person: + askToRemoveContact(); + + return true; + default: + return super.onOptionsItemSelected(item); + } + } + private void loadContactAndGroup() { runOnDbThread(new Runnable() { public void run() { @@ -478,4 +513,59 @@ implements EventListener, OnClickListener, OnItemClickListener { i.putExtra("briar.POSITION", position); startActivityForResult(i, REQUEST_READ); } + + private void askToRemoveContact() { + runOnUiThread(new Runnable() { + @Override + public void run() { + DialogInterface.OnClickListener okListener = + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + removeContact(); + } + }; + + AlertDialog.Builder builder = + new AlertDialog.Builder(ConversationActivity.this); + builder.setTitle( + getString(R.string.dialog_title_delete_contact)); + builder.setMessage( + getString(R.string.dialog_message_delete_contact)); + builder.setPositiveButton(android.R.string.ok, okListener); + builder.setNegativeButton(android.R.string.cancel, null); + builder.show(); + } + }); + } + + private void removeContact() { + runOnDbThread(new Runnable() { + public void run() { + try { + contactManager.removeContact(contactId); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } finally { + finishAfterContactRemoved(); + } + } + }); + } + + private void finishAfterContactRemoved() { + runOnUiThread(new Runnable() { + @Override + public void run() { + String deleted = getString(R.string.contact_deleted_toast); + Toast.makeText(ConversationActivity.this, deleted, LENGTH_SHORT) + .show(); + + finish(); + } + }); + } + } From 6a954021ae36046c78d1875d5f0c4da773856da8 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 24 Dec 2015 12:19:58 -0200 Subject: [PATCH 2/2] Sort contacts by latest activity. When you receive a message from a contact, it will be moved to the top of the list with a nice animation. Also with this commit, not the entire data set is invalidated each time data changes, but only the parts of the data that really require an update. Furthermore, the ContactListItemComparator that is not needed anymore is removed. --- .../android/contact/ContactListActivity.java | 10 +++++---- .../android/contact/ContactListAdapter.java | 22 +++++++++++++++++-- .../contact/ContactListItemComparator.java | 15 ------------- 3 files changed, 26 insertions(+), 21 deletions(-) delete mode 100644 briar-android/src/org/briarproject/android/contact/ContactListItemComparator.java diff --git a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java index 1edbd2d2a..7f9298089 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java @@ -227,10 +227,11 @@ public class ContactListActivity extends BriarActivity final Collection headers) { runOnUiThread(new Runnable() { public void run() { - ContactListItem item = adapter.findItem(c); + int position = adapter.findItemPosition(c); + ContactListItem item = adapter.getItem(position); if (item != null) { item.setHeaders(headers); - adapter.notifyDataSetChanged(); + adapter.updateItem(position, item); } } }); @@ -255,10 +256,11 @@ public class ContactListActivity extends BriarActivity private void setConnected(final ContactId c, final boolean connected) { runOnUiThread(new Runnable() { public void run() { - ContactListItem item = adapter.findItem(c); + int position = adapter.findItemPosition(c); + ContactListItem item = adapter.getItem(position); if (item != null) { item.setConnected(connected); - adapter.notifyDataSetChanged(); + adapter.notifyItemChanged(position); } } }); diff --git a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java index 7e511ea9a..2abe5e6ff 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java @@ -48,8 +48,13 @@ public class ContactListAdapter @Override public int compare(ContactListItem c1, ContactListItem c2) { - return (int) (c1.getTimestamp() - - c2.getTimestamp()); + // sort items by time + // and do not take unread messages into account + long time1 = c1.getTimestamp(); + long time2 = c2.getTimestamp(); + if (time1 < time2) return 1; + if (time1 > time2) return -1; + return 0; } @Override @@ -145,6 +150,10 @@ public class ContactListAdapter return contacts.get(position); } + public void updateItem(int position, ContactListItem item) { + contacts.updateItemAt(position, item); + } + public ContactListItem findItem(ContactId c) { int count = getItemCount(); for (int i = 0; i < count; i++) { @@ -154,6 +163,15 @@ public class ContactListAdapter return null; // Not found } + public int findItemPosition(ContactId c) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + ContactListItem item = getItem(i); + if (item.getContact().getId().equals(c)) return i; + } + return -1; // Not found + } + public void addAll(final List contacts) { this.contacts.addAll(contacts); } diff --git a/briar-android/src/org/briarproject/android/contact/ContactListItemComparator.java b/briar-android/src/org/briarproject/android/contact/ContactListItemComparator.java deleted file mode 100644 index db41a3ef5..000000000 --- a/briar-android/src/org/briarproject/android/contact/ContactListItemComparator.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.briarproject.android.contact; - -import java.util.Comparator; - -class ContactListItemComparator implements Comparator { - - static final ContactListItemComparator INSTANCE = - new ContactListItemComparator(); - - public int compare(ContactListItem a, ContactListItem b) { - String aName = a.getContact().getAuthor().getName(); - String bName = b.getContact().getAuthor().getName(); - return String.CASE_INSENSITIVE_ORDER.compare(aName, bName); - } -}