From 1ce1cf6f631612cc089f19fec9493ee8bd127860 Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Fri, 1 Mar 2013 20:59:53 +0000 Subject: [PATCH] Added conversation list screen, minor tweaks to contact list screen. --- briar-android/AndroidManifest.xml | 4 + .../res/drawable-hdpi/rating_important.png | Bin 0 -> 1704 bytes .../drawable-hdpi/rating_not_important.png | Bin 0 -> 1839 bytes .../res/drawable-mdpi/rating_important.png | Bin 0 -> 1434 bytes .../drawable-mdpi/rating_not_important.png | Bin 0 -> 1463 bytes .../res/drawable-xhdpi/content_new_email.png | Bin 0 -> 1703 bytes .../res/drawable-xhdpi/rating_important.png | Bin 0 -> 2045 bytes .../drawable-xhdpi/rating_not_important.png | Bin 0 -> 2340 bytes briar-android/res/values/strings.xml | 5 +- .../sf/briar/android/HomeScreenActivity.java | 4 +- .../android/contact/ContactListActivity.java | 21 +- .../android/contact/ContactListAdapter.java | 12 +- .../android/contact/ContactListItem.java | 3 +- .../messages/ConversationListActivity.java | 225 ++++++++++++++++++ .../messages/ConversationListAdapter.java | 75 ++++++ .../messages/ConversationListItem.java | 81 +++++++ 16 files changed, 408 insertions(+), 22 deletions(-) create mode 100644 briar-android/res/drawable-hdpi/rating_important.png create mode 100644 briar-android/res/drawable-hdpi/rating_not_important.png create mode 100644 briar-android/res/drawable-mdpi/rating_important.png create mode 100644 briar-android/res/drawable-mdpi/rating_not_important.png create mode 100644 briar-android/res/drawable-xhdpi/content_new_email.png create mode 100644 briar-android/res/drawable-xhdpi/rating_important.png create mode 100644 briar-android/res/drawable-xhdpi/rating_not_important.png create mode 100644 briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java create mode 100644 briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java create mode 100644 briar-android/src/net/sf/briar/android/messages/ConversationListItem.java diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index 44027595bf..8dcdb7163d 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -40,5 +40,9 @@ android:name=".android.invitation.AddContactActivity" android:label="@string/add_contact_title" > </activity> + <activity + android:name=".android.messages.ConversationListActivity" + android:label="@string/messages_title" > + </activity> </application> </manifest> diff --git a/briar-android/res/drawable-hdpi/rating_important.png b/briar-android/res/drawable-hdpi/rating_important.png new file mode 100644 index 0000000000000000000000000000000000000000..7c25f351188f98caa89792889ae3e27960c16da7 GIT binary patch literal 1704 zcmaJ?Yfuwc6i$H1qeTS)ff2inh{8a2HwHptBIW@SaS?%mR742L0x8*S%q|dgP{68F zP)AWwunJW~TNreTS}X#=N(4c~Hx(_6wW7rbB2^xa?FNDNN9oS&-h0oS?>pal+}W=q z!dKYax!cibG<#X7G?H2&^J_DM`o>y}?4TAmGFVPV;mKsCLXXl!Dm)1VWSAlajYJiy ztPQQGfJU?QR7cB6IkJkc#4(n_?87o(Itopr34#ndg)$8#fh06Vtrap~)ip8!wMxj0 z^+zB?CqYxyp&RvR)W+~=<;FB6PsI#c1_%s%iU31N1z^B5T7qv7GRJxO)ZT0cnZURU znI>d@6eUL@012)~0e=?cr-TAvAb`VyIS`M-^99%t41q8kgt&e%#P{d&AsCo=m{c^q zDw!WC4Vj2VorKI(lGO1*Ff%igmAQn4>r+6O$K!zz8)UQnC=Wj(OG_#Yep+I|B!d(s zlzO#}RO4E}%&17h(@7zdQu;9kOgBZVB__&56$~^ebRf)v%qdMeBFO){V%U^7K}Mqg z=>1P(B05Wlf{`eJr|Xqe<B}JcL+SVuJ*psaeKd}1CaV~cijz2zit7MLls^jw5QS2$ zHCx6J2*Q_X2~wd|qB5zFNpY~$Y89WeBp8;60|WiVkQ9c4VIBwO1#`p_QHVdx<%r=) ztQ1$KW2ly##H#+m@}|X_hXK=3k)^0!oq?)C^f(5LC(Tz+uO(nwz6q>qdM(^(u^=S| zG`IF&t)4Vd^JCsl4K8(<8hunt&AXl&Y{N0{9_qfh%cP=c!~N$a*V5*QTun72koxfc zN8fGk3_%#6u>5u9+cN9seFlfi$G7Z`$X_JP8Y;87FL9{v+9y}u*lJx60p=&}b&rEv zwWgHbFI<ZrY6_2d)a;qNS(C{g>lk}}@y)s0j^gq{&9mrBm}jCVa15<yoLh^W{7b#Q zv0pDgeQ(!WBU;$v<df&)?X|{e5g6)H=(T(_-pb<#*VwoXwt)<vGQ`I>Y-i5GJ(hWo z<wZ919Y#T_4~i5ai$q3VMAFN;yNX}7Dds{mJD^wfUTxtu9i4Wk*xNLvJ(`M$bUCAZ z)4Wq*{O&v6iMwy1m0?F*`rDh&7k@IlSn<$yrpZ=2Yh}B-RdzT1r(wq`VvZ&^=rOm; za_s%4Qtv*4*Vdy}EnKpQ$lO~?PmzUONbU+<nm90O|HMrvc6h#+-hJ8m?25+(ZtR2T zK}OHomXYol7te1m%IdD<MA0qRdOR(1TwU~T-^HtA0z-3`cvJ7(TI+_~{*`Aolnku9 zGpsr-u)03#VL6x^uPb<VJG|KcN5t*@XxUc75vH~#EN**V5Y4@pK0G_!{lLr^gRifv zO@r}#%%!|nDIUWXMNNw!7v+Fbqb$b0jBm*>#-C~0?z<~DZs<Z&KnBTDeczfjvTWG4 zTDQu^zNzh-Ei>o;x%4;GI<@mj`<XWN-F)EEi(t3ml4tduUd?ico(3er#3h`cVEdgM zht`aIW|4ehR=y7)NeE%IRD)^vle&h`VkfBi)`8=q97#fy7h_(Z+w!l5B9F>HS98Kk zO;+uTd$RKal6W1g!&kHS<jl)9>6ve8^hTNYHSP!Js=Rx?L9?oJ7YLMw(ifd49q5Cq zjN5(73;SLVER4OgeX!1H&|w|p;2}10!WtX(9UOA5%=uY!>Uep9)4+TIqnm!+zxGkX z?{>>p)3H&Xo9|*CP!fmF*6w&+5q1b8Dyu3E^jB)cM!2HjL0A2N?BM!qhht8NOrk~$ zyLE4Sa<9bSJP{jp>yH`PZ2=!l-o3U#_*2dZ^W^{$o?uaRqtSh*)lMtV?hm#Q?br8B TC7)^^j{iJl!Qs+sabn)z>{FN^ literal 0 HcmV?d00001 diff --git a/briar-android/res/drawable-hdpi/rating_not_important.png b/briar-android/res/drawable-hdpi/rating_not_important.png new file mode 100644 index 0000000000000000000000000000000000000000..c10325fe114dd69e75297bc427d5d1530466ff20 GIT binary patch literal 1839 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 literal 0 HcmV?d00001 diff --git a/briar-android/res/drawable-mdpi/rating_important.png b/briar-android/res/drawable-mdpi/rating_important.png new file mode 100644 index 0000000000000000000000000000000000000000..7b2e1d5649aff4c8adb60e454b4bd77275dc071d GIT binary patch literal 1434 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8<fR&VF+bTgE72zA8;GAESs$i;Tpqp%9W~g9hqGxDg zU}<8hqhMrUXrOOsq;FuZYiM9)YHnp<r~m~@K--E^(yW49+@N*=dA3R!B_#z``ugSN z<$C4Ddih1^`i7R4mih)p`bI{&Koz>hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s0<RzFwUtj!6b93RUi%Wu15$?rmaB)aw zL8^XGYH@yPQ8F;%(v(3~6<9eJr6!i-7lq{K=fFZSAS1sdzc?emK*2fKRL@YsH!(Rg z4<rKC;p=PVnO9trn3tUD>0+w{G(#^lGsVip*wxV4$->#x$-u?X(ACh=#L&{!#L3yw z&D7A`#K{n**Cju>G&eP`1g19yq}RmAz{u3Z1gBn5V#qB3+U$~Alv$RV;#QQOs{r=2 zRVHq?IN~%9sy79jTOj^$!l_pu=oo!a)FMSSObD2MKumbT1#;j?KQ#}S-iv?<JA-3! zA_D^xkEe@cNX4x;(|3Cx4iGu!oBQ^(yI_pS#sz#)Rve)&f+YnX4PU-{@jpquosTb1 zuW46@)lROY!qwi_!wLjmExwwS{fDnc+{@GJ(vh@}2l`u{%$xmw-sIm)ua?BV|727X zE7$&<>CY>bsa{(r-#`6$_uV5oX0N?i!#dP;U$A{%a+{mc)4*p^97jabzW(R3q6S<- z54u$<)+RHFIk5Z@u#A5*rJ>H?_|(-CK1bgBUCfvy;k@8p!P;}#E4TG>2(koTIGo(# zro8&qV?&-}j#m@(c5Y)_c7VNtHQ%NyFw|k@Rjt*QQmicpj3U^rzHbX`-8VaI{iEdz zZQZ`BxHF4CxaDzx+u||vwizE%H!ms`F03o!I(If|ffJiev#h`Z1@(o`ELhCf-fKKI zp;2`MH=9pYo@&#YH;fe<c5|yJ^2+_JyU{C9d^wGO`zBuQ1pX&cA*XZ7pU#Lbc*T6F zOL^PD^o!A}&S>sTb!paFIaPjw)p5REFIy(-tPW+Yd$vPO!Oz(6RuZG|<Idfx4mp)9 zS7v=WGOb(Xj!Ag0WuWzarp*)LZ4B3WJ-#Ovzn^Kk%x1Q*pMO^r<@D^VT+VdtN8_r( zsox*8Xoo9`)p2h-$iw>MX4{_2Vm=?%)-g$Lxc{X<)b-x!f}D<>eNh5Ql2_fABsqSN z_016WDegO8#+vcv<04;av4zKL1h-D(|M9>0)z*f1MmC0b_sT3;RPTC$N=r{yKbLh* G2~7Yru?ji> literal 0 HcmV?d00001 diff --git a/briar-android/res/drawable-mdpi/rating_not_important.png b/briar-android/res/drawable-mdpi/rating_not_important.png new file mode 100644 index 0000000000000000000000000000000000000000..392eeb00c565a513412e8cf90a208c2fe8826e2c GIT binary patch literal 1463 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8<fR&VF+bTgE72zA8;GAESs$i;Tpqp%9W~g9hqGxDg zU}<8hqhMrUXrOOsq;FuZYiM9)YHnp<r~m~@K--E^(yW49+@N*=dA3R!B_#z``ugSN z<$C4Ddih1^`i7R4mih)p`bI{&Koz>hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s0<RzFwUtj!6b93RUi%Wu15$?rmaB)aw zL8^XGYH@yPQ8F;%(v(3~6<9eJr6!i-7lq{K=fFZSAS1sdzc?emK*2fKRL@YsH!(Rg z4<rKC;p=PVnO9trn3tUD>0+w{G(#^lGsVip#M0Tq#K6_m$-u?X(ACh=#L&{!#L3yw z&D7A`#K{n**Cju>G&eP`1g19yq1O$kUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dR<{@# z7@3;5;4}}aHwCL(z<P1}Lm%iEeNfaQMKw$an0`P^c)|s8;7LC<518JIfC)P%?b;>= z1}05U7srr_TW_YH*LDdMIiB8g=*QY4XCg9`M8brPCM}vGVm52(rbTQ1u!@PDx|FtQ zV_@A<&q+zDS(hSi{4njFsG<2dy-wxW_bcIhO_J};{yuAa;p@w_#rG}0*FN7<eQxi0 zsqUjXY1??ZPo6DdoOw!KuHSuiz1eSbUB86^CpK`D2n5G9@@^5HEy*PHLjQ{NCN`68 zejARy)+?BCj$=oI@Ec)q&)Ez=zpFp!lquHHWh!!1z7f`wTdZR)%e3c#n2SiVU|;1| zy+cY9SU*+h)-s-8Z#}?wCqeIAj8Lm$+HvlR2d^tx&Oey<*LwY9t_gGAv6nxXlx#nF z&gT0J%L`d#J}|0sT})lj^<CS+kfUL%3)7Qh;xE`{$HZjazApc*G(lud)7O;Jgt>we z%-jj?={u*b_;tYMMsRe;H;tqgMcySpKGZFH&SP<D7V9H}qf>3yY`k~-#p9<k?kkrq z)H&iAW?R{AsU<hhIa<9||LZkIPf7a~X;Nz0Ww(A!eYtGAfaL++j#V3aFI`JaQC-6r z?r@gV%<Z<6GHXavL6b;!x3S!^e#PgE)~Ab}OjnRUy?IO6wI1%H_bxc!7vIaYq@~Va z&8FMD4QU%zui&5b{;`cTOU7@<`^I~j?!<)nCJ4kBZ=d>d>xoCIfioGrzZ6O<IvjeN z7`MLRfxKz5)RqRjTlKGEnKzkEFJhl!`zW;afx`Lry$hxl?^&+puqkC);`K`|FN`$& kr)6II-ygi0wT9b(VOMj_T4w7-nxLZ8)78&qol`;+00G$<$N&HU literal 0 HcmV?d00001 diff --git a/briar-android/res/drawable-xhdpi/content_new_email.png b/briar-android/res/drawable-xhdpi/content_new_email.png new file mode 100644 index 0000000000000000000000000000000000000000..674b69b08715b9978186818d728ce4133d9f1ae2 GIT binary patch literal 1703 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m{l@EB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9<K~ zz|zE0N5ROz&_LhNNZ-I**U-Sq)ZEIzPyq^*fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD<cE0=g99h1>$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;Np<V zf>iyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh**NZ(?$0 z9!LbN!`Ii!Gq1QLF)umQ)5TT^Xog;9W{Q=GtDA|jrKPK>lYxt&p{t>#iJ_&diIcOV zo2j9>iIX8ruS<S%X>Mv>2~2MaLa!T6y`aR9TL84#CABECEH%ZgC_h&L>}jh^+-`Bk zX&zK>3U0T!;MA)Rbc{YIYLTKECIn1BASOKF0y*%cpPC0u??u3b&B=P@7cjp_db&7< zRNQ(qJ2qR`QKT(>^44owqR~q;SXl)HT{PW3F7EopzUNc@5Bop7tOvPYraE5i)_Qcj zb;c`K-6oALC8;&ybqhQvpZ&#GDSmCjU$3;YK4pA1xf-X-p4q;iV`+WcYTx^AC3jB| zn>7q!4B8E%3obl7r9ai{Dc3$(R$b;}F>LY&nKJl`7H4g}CCFgN%-6I`)6>~PD}Nhf zowSO>-D^NSQH-b9Iv*D7@nW42`c++m|0=8OWYcq}{wH3LU9g+u9^3f?ss%zm8x6LZ zp8O$kd^6L##_$8-nhkp*dGE0BAGERHR%<k0@^8VBPV)oY8+fjLx)r>=!T!%5PMs!p z=OUN#WAB@%$6n7#O1ia*Wd~1LgY^U3da<V+WqyC1X7!wwDv&$VB(23d<B>}LMlp}8 z_rDe#VKrbc3ubw5pIRer;pqO3JwNn%gV^rXLZWtj^NhI@-E}r`%v~g5&0gR#tH=M- z_Y)uAEPf#ElF2KuFe&2sfpaIHFOlnuVBfyOM6c<xr0hhs$CpJS@70UD=DGAlu4Hhm zP&p@Pe?X{W(j~!2qdK-X3q8KtXy;9ur6qIG|JdFO>r~n_4=m`Lu}t7r%AR<}Uxi1M zcR9XOTD>c!CV+91#Utw-tD}#Fatb`}5Y=lg*uT#ASSa^}(}JIKqQZ9aq-pkvNuKv^ z$a9~vL#J;;zWA;bn|#J54k_{W*k#-D6F%Ghx$y7mW?SJcOc9J-vhO&~raG0xeLQ(c z+keM?QQrpV2U_y`<eFc*3Lkh_vxNCn<n#vNLoJ<FhPCbUm;Nts-dp26<KuV6gB4T7 z4yxLn`qgH!Kv87B)NijG`2<!2^H~cYy-1B^+I2kbqGd$q>VMUig+D8;EhYrGr)&-} zc5RR}v&?f@`0eGh2N#|iNH1P7q20v)U{m&mpt&7_2L%7`J60}y$JQ-eax=@5ZQt8u z<EAigyQJClEzUpU*L+{02i!ZR6`YNE5t*QSbaO-gB!;@KQ}0su)IHhexcvU3BxyxZ z`rBdXrS6n!=Iv`{)hhfzyy9%$hG|u=H~hEA>|P*xfGdG@1CxmPKQ04?g_?{dR|>L# Ql?nrcr>mdKI;Vst05B|kTL1t6 literal 0 HcmV?d00001 diff --git a/briar-android/res/drawable-xhdpi/rating_important.png b/briar-android/res/drawable-xhdpi/rating_important.png new file mode 100644 index 0000000000000000000000000000000000000000..da44dd82c3ab07009b3b45b638baceb90fcff514 GIT binary patch literal 2045 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 F{{d4*A{+n! literal 0 HcmV?d00001 diff --git a/briar-android/res/drawable-xhdpi/rating_not_important.png b/briar-android/res/drawable-xhdpi/rating_not_important.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff6c8d0e68f491e420faa9a955c9a6c19f8ea1e GIT binary patch literal 2340 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 literal 0 HcmV?d00001 diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 75b51e2dbd..79236a3960 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -12,7 +12,7 @@ <string name="contact_list_title">Contacts</string> <string name="contact_connected">Connected</string> <string name="contact_last_connected">Last connected <br /> %s</string> - <string name="add_contact_button">Add a contact</string> + <string name="add_contact_button">New Contact</string> <string name="add_contact_title">Add a Contact</string> <string name="same_network">Briar can add contacts via Wi-Fi or Bluetooth. For security reasons, you must be face-to-face to add someone as a contact. To use Wi-Fi you must both be connected to the same network.</string> <string name="wifi_not_available">Wi-Fi is not available on this device</string> @@ -39,6 +39,7 @@ <string name="interfering">This could mean that someone is trying to interfere with your connection.</string> <string name="contact_added">Contact added</string> <string name="enter_nickname">Please enter a nickname for this contact:</string> - <string name="add_another_contact_button">Add another contact</string> + <string name="messages_title">Messages</string> + <string name="compose_button">New Message</string> <string name="done_button">Done</string> </resources> diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java index 65b8fd01d7..07fe3d0b8c 100644 --- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java +++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java @@ -12,6 +12,7 @@ import net.sf.briar.R; import net.sf.briar.android.BriarService.BriarBinder; import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.contact.ContactListActivity; +import net.sf.briar.android.messages.ConversationListActivity; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; @@ -78,7 +79,8 @@ public class HomeScreenActivity extends BriarActivity { messagesButton.setText(R.string.messages_button); messagesButton.setOnClickListener(new OnClickListener() { public void onClick(View view) { - // FIXME: Hook this button up to an activity + startActivity(new Intent(HomeScreenActivity.this, + ConversationListActivity.class)); } }); buttons.add(messagesButton); diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java index b12ba8db66..53143108ea 100644 --- a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java +++ b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java @@ -59,26 +59,25 @@ implements OnClickListener, DatabaseListener, ConnectionListener { @Override public void onCreate(Bundle state) { super.onCreate(null); - if(LOG.isLoggable(INFO)) LOG.info("Created"); LinearLayout layout = new LinearLayout(this); layout.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT)); layout.setOrientation(VERTICAL); layout.setGravity(CENTER_HORIZONTAL); adapter = new ContactListAdapter(this); - ListView listView = new ListView(this); + ListView list = new ListView(this); // Give me all the width and all the unused height - listView.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, - 1f)); - listView.setAdapter(adapter); - layout.addView(listView); + list.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f)); + list.setAdapter(adapter); + layout.addView(list); Button addContactButton = new Button(this); - LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - addContactButton.setLayoutParams(lp); + addContactButton.setBackgroundResource(0); + addContactButton.setLayoutParams(new LayoutParams(MATCH_PARENT, + WRAP_CONTENT)); + addContactButton.setCompoundDrawablesWithIntrinsicBounds(0, + R.drawable.social_add_person, 0, 0); addContactButton.setText(R.string.add_contact_button); - addContactButton.setCompoundDrawablesWithIntrinsicBounds( - R.drawable.social_add_person, 0, 0, 0); addContactButton.setOnClickListener(this); layout.addView(addContactButton); @@ -146,7 +145,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener { IBinder binder = serviceConnection.waitForBinder(); ((BriarBinder) binder).getService().waitForStartup(); // Load the contacts from the database - final Collection<Contact> contacts = db.getContacts(); + Collection<Contact> contacts = db.getContacts(); if(LOG.isLoggable(INFO)) LOG.info("Loaded " + contacts.size() + " contacts"); // Update the contact list diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java index 69dcecfd8e..1849d60ede 100644 --- a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java +++ b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java @@ -20,8 +20,8 @@ import android.widget.TextView; class ContactListAdapter extends ArrayAdapter<ContactListItem> { - ContactListAdapter(Context context) { - super(context, android.R.layout.simple_expandable_list_item_1, + ContactListAdapter(Context ctx) { + super(ctx, android.R.layout.simple_expandable_list_item_1, new ArrayList<ContactListItem>()); } @@ -34,14 +34,14 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> { layout.setGravity(CENTER); ImageView bulb = new ImageView(ctx); - if(item.getConnected()) bulb.setImageResource(R.drawable.green_bulb); - else bulb.setImageResource(R.drawable.grey_bulb); bulb.setPadding(5, 5, 5, 5); + if(item.isConnected()) bulb.setImageResource(R.drawable.green_bulb); + else bulb.setImageResource(R.drawable.grey_bulb); layout.addView(bulb); TextView name = new TextView(ctx); // Give me all the unused width - name.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1f)); + name.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1)); name.setTextSize(18); name.setText(item.getName()); layout.addView(name); @@ -49,7 +49,7 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> { TextView connected = new TextView(ctx); connected.setTextSize(12); connected.setPadding(5, 0, 5, 0); - if(item.getConnected()) { + if(item.isConnected()) { connected.setText(R.string.contact_connected); } else { String format = ctx.getResources().getString( diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListItem.java b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java index 99d2a79fcc..47747e3a1b 100644 --- a/briar-android/src/net/sf/briar/android/contact/ContactListItem.java +++ b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java @@ -30,7 +30,7 @@ class ContactListItem { return contact.getLastConnected(); } - boolean getConnected() { + boolean isConnected() { return connected; } @@ -40,7 +40,6 @@ class ContactListItem { private static class ItemComparator implements Comparator<ContactListItem> { - @Override public int compare(ContactListItem a, ContactListItem b) { return String.CASE_INSENSITIVE_ORDER.compare(a.contact.getName(), b.contact.getName()); diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java new file mode 100644 index 0000000000..a45ac9c8bf --- /dev/null +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java @@ -0,0 +1,225 @@ +package net.sf.briar.android.messages; + +import static android.view.Gravity.CENTER_HORIZONTAL; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static android.widget.LinearLayout.VERTICAL; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import net.sf.briar.R; +import net.sf.briar.android.BriarActivity; +import net.sf.briar.android.BriarService; +import net.sf.briar.android.BriarService.BriarBinder; +import net.sf.briar.android.BriarService.BriarServiceConnection; +import net.sf.briar.api.Contact; +import net.sf.briar.api.ContactId; +import net.sf.briar.api.db.DatabaseComponent; +import net.sf.briar.api.db.DatabaseExecutor; +import net.sf.briar.api.db.DbException; +import net.sf.briar.api.db.PrivateMessageHeader; +import net.sf.briar.api.db.event.DatabaseEvent; +import net.sf.briar.api.db.event.DatabaseListener; +import net.sf.briar.api.db.event.MessageAddedEvent; +import net.sf.briar.api.db.event.MessageExpiredEvent; +import net.sf.briar.api.messaging.Message; +import net.sf.briar.api.messaging.MessageFactory; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.ListView; + +import com.google.inject.Inject; + +public class ConversationListActivity extends BriarActivity +implements OnClickListener, DatabaseListener { + + private static final Logger LOG = + Logger.getLogger(ConversationListActivity.class.getName()); + + private final BriarServiceConnection serviceConnection = + new BriarServiceConnection(); + + @Inject private DatabaseComponent db; + @Inject @DatabaseExecutor private Executor dbExecutor; + @Inject private MessageFactory messageFactory; + + private ArrayAdapter<ConversationListItem> adapter = null; + + @Override + public void onCreate(Bundle state) { + super.onCreate(null); + LinearLayout layout = new LinearLayout(this); + layout.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT)); + layout.setOrientation(VERTICAL); + layout.setGravity(CENTER_HORIZONTAL); + + adapter = new ConversationListAdapter(this); + ListView list = new ListView(this); + // Give me all the width and all the unused height + list.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f)); + list.setAdapter(adapter); + layout.addView(list); + + Button composeButton = new Button(this); + composeButton.setBackgroundResource(0); + composeButton.setLayoutParams(new LayoutParams(MATCH_PARENT, + WRAP_CONTENT)); + composeButton.setCompoundDrawablesWithIntrinsicBounds(0, + R.drawable.content_new_email, 0, 0); + composeButton.setText(R.string.compose_button); + composeButton.setOnClickListener(this); + layout.addView(composeButton); + + setContentView(layout); + + // Listen for messages being added or removed + db.addListener(this); + // Bind to the service so we can wait for the DB to be opened + bindService(new Intent(BriarService.class.getName()), + serviceConnection, 0); + // Load the message headers from the DB + reloadMessageHeaders(); + + // Add some fake messages to the database in a background thread + // FIXME: Remove this + dbExecutor.execute(new Runnable() { + public void run() { + try { + // Wait for the service to be bound and started + IBinder binder = serviceConnection.waitForBinder(); + ((BriarBinder) binder).getService().waitForStartup(); + if(LOG.isLoggable(INFO)) LOG.info("Service started"); + Collection<PrivateMessageHeader> headers = + db.getPrivateMessageHeaders(); + if(headers.isEmpty()) { + // Insert a fake contact + ContactId contactId = db.addContact("Carol"); + // Insert some messages to the contact + Message m = messageFactory.createPrivateMessage(null, + "First message's subject", + "First message's body".getBytes("UTF-8")); + db.addLocalPrivateMessage(m, contactId); + db.setStarredFlag(m.getId(), true); + Thread.sleep(2000); + m = messageFactory.createPrivateMessage(m.getId(), + "Second message's subject", + "Second message's body".getBytes("UTF-8")); + db.addLocalPrivateMessage(m, contactId); + db.setReadFlag(m.getId(), true); + } + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } catch(GeneralSecurityException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } catch(InterruptedException e) { + if(LOG.isLoggable(INFO)) + LOG.info("Interrupted while waiting for service"); + Thread.currentThread().interrupt(); + } catch(IOException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + } + }); + } + + @Override + public void onDestroy() { + super.onDestroy(); + db.removeListener(this); + unbindService(serviceConnection); + } + + public void onClick(View view) { + // FIXME: Hook this button up to an activity + } + + public void eventOccurred(DatabaseEvent e) { + if(e instanceof MessageAddedEvent) reloadMessageHeaders(); + else if(e instanceof MessageExpiredEvent) reloadMessageHeaders(); + } + + private void reloadMessageHeaders() { + dbExecutor.execute(new Runnable() { + public void run() { + try { + // Wait for the service to be bound and started + IBinder binder = serviceConnection.waitForBinder(); + ((BriarBinder) binder).getService().waitForStartup(); + // Load the contact list from the database + Collection<Contact> contacts = db.getContacts(); + if(LOG.isLoggable(INFO)) + LOG.info("Loaded " + contacts.size() + " contacts"); + // Load the message headers from the database + Collection<PrivateMessageHeader> headers = + db.getPrivateMessageHeaders(); + if(LOG.isLoggable(INFO)) + LOG.info("Loaded " + headers.size() + " headers"); + // Update the conversation list + updateConversationList(contacts, headers); + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } catch(InterruptedException e) { + if(LOG.isLoggable(INFO)) + LOG.info("Interrupted while waiting for service"); + Thread.currentThread().interrupt(); + } + } + }); + } + + private void updateConversationList(final Collection<Contact> contacts, + final Collection<PrivateMessageHeader> headers) { + runOnUiThread(new Runnable() { + public void run() { + adapter.clear(); + for(ConversationListItem i : sortHeaders(contacts, headers)) + adapter.add(i); + adapter.sort(ConversationListItem.COMPARATOR); + } + }); + } + + private List<ConversationListItem> sortHeaders(Collection<Contact> contacts, + Collection<PrivateMessageHeader> headers) { + // Group the headers into conversations, one per contact + Map<ContactId, List<PrivateMessageHeader>> map = + new HashMap<ContactId, List<PrivateMessageHeader>>(); + for(Contact c : contacts) + map.put(c.getId(), new ArrayList<PrivateMessageHeader>()); + for(PrivateMessageHeader h : headers) { + ContactId id = h.getContactId(); + List<PrivateMessageHeader> conversation = map.get(id); + // Ignore header if the contact was added after db.getContacts() + if(conversation != null) conversation.add(h); + } + // Create a list item for each non-empty conversation + List<ConversationListItem> list = new ArrayList<ConversationListItem>(); + for(Contact c : contacts) { + List<PrivateMessageHeader> conversation = map.get(c.getId()); + if(!conversation.isEmpty()) + list.add(new ConversationListItem(c, conversation)); + } + return list; + } +} diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java new file mode 100644 index 0000000000..f0ef7ec79f --- /dev/null +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java @@ -0,0 +1,75 @@ +package net.sf.briar.android.messages; + +import static android.graphics.Typeface.BOLD; +import static android.view.Gravity.CENTER; +import static android.view.Gravity.LEFT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static android.widget.LinearLayout.HORIZONTAL; +import static android.widget.LinearLayout.VERTICAL; +import static java.text.DateFormat.SHORT; + +import java.util.ArrayList; + +import net.sf.briar.R; +import android.content.Context; +import android.text.format.DateUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.TextView; + +class ConversationListAdapter extends ArrayAdapter<ConversationListItem> { + + ConversationListAdapter(Context ctx) { + super(ctx, android.R.layout.simple_expandable_list_item_1, + new ArrayList<ConversationListItem>()); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ConversationListItem item = getItem(position); + Context ctx = getContext(); + LinearLayout layout = new LinearLayout(ctx); + layout.setOrientation(HORIZONTAL); + layout.setGravity(CENTER); + + ImageView star = new ImageView(ctx); + star.setPadding(5, 5, 5, 5); + if(item.getStarred()) + star.setImageResource(R.drawable.rating_important); + else star.setImageResource(R.drawable.rating_not_important); + layout.addView(star); + + LinearLayout innerLayout = new LinearLayout(ctx); + // Give me all the unused width + innerLayout.setLayoutParams(new LayoutParams(WRAP_CONTENT, + WRAP_CONTENT, 1)); + innerLayout.setOrientation(VERTICAL); + innerLayout.setGravity(LEFT); + innerLayout.setPadding(0, 5, 0, 5); + + TextView name = new TextView(ctx); + name.setTextSize(18); + name.setText(item.getName() + " (" + item.getLength() + ")"); + innerLayout.addView(name); + + TextView subject = new TextView(ctx); + subject.setTextSize(14); + if(!item.getRead()) subject.setTypeface(null, BOLD); + subject.setText(item.getSubject()); + innerLayout.addView(subject); + layout.addView(innerLayout); + + TextView date = new TextView(ctx); + date.setTextSize(14); + date.setPadding(5, 0, 10, 0); + long then = item.getTimestamp(), now = System.currentTimeMillis(); + date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT)); + layout.addView(date); + + return layout; + } +} diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java new file mode 100644 index 0000000000..711329ec3b --- /dev/null +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java @@ -0,0 +1,81 @@ +package net.sf.briar.android.messages; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import net.sf.briar.api.Contact; +import net.sf.briar.api.db.PrivateMessageHeader; + +class ConversationListItem { + + static final Comparator<ConversationListItem> COMPARATOR = + new ItemComparator(); + + private static final Comparator<PrivateMessageHeader> HEADER_COMPARATOR = + new HeaderComparator(); + + private final Contact contact; + private final List<PrivateMessageHeader> headers; + private final boolean read, starred; + + ConversationListItem(Contact contact, List<PrivateMessageHeader> headers) { + if(headers.isEmpty()) throw new IllegalArgumentException(); + Collections.sort(headers, HEADER_COMPARATOR); + boolean read = false, starred = false; + for(PrivateMessageHeader h : headers) { + read &= h.getRead(); + starred |= h.getStarred(); + } + this.contact = contact; + this.headers = headers; + this.read = read; + this.starred = starred; + } + + String getName() { + return contact.getName(); + } + + String getSubject() { + return headers.get(0).getSubject(); + } + + long getTimestamp() { + return headers.get(0).getTimestamp(); + } + + boolean getRead() { + return read; + } + + boolean getStarred() { + return starred; + } + + int getLength() { + return headers.size(); + } + + private static class HeaderComparator + implements Comparator<PrivateMessageHeader> { + + public int compare(PrivateMessageHeader a, PrivateMessageHeader b) { + // The newest message comes first + long aTime = a.getTimestamp(), bTime = b.getTimestamp(); + if(aTime > bTime) return -1; + if(aTime < bTime) return 1; + return 0; + } + } + + private static class ItemComparator + implements Comparator<ConversationListItem> { + + public int compare(ConversationListItem a, ConversationListItem b) { + // The item with the newest message comes first + return HEADER_COMPARATOR.compare(a.headers.get(0), + b.headers.get(0)); + } + } +} -- GitLab