From 496fffe6eeb944b526130317577053b1eae7cd5d Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Fri, 4 Sep 2015 08:19:07 +0200 Subject: [PATCH] Notifications could still use some fine tuning, but should work fine for now --- app/src/main/AndroidManifest.xml | 2 + .../java/ch/dissem/apps/abit/Identicon.java | 14 +- .../dissem/apps/abit/MessageListActivity.java | 13 +- .../dissem/apps/abit/MessageListFragment.java | 5 + .../ch/dissem/apps/abit/MessageListener.java | 126 ++++++++++++++---- .../AndroidMessageRepository.java | 21 +++ .../res/drawable-hdpi/ic_action_delete.png | Bin 0 -> 642 bytes .../res/drawable-hdpi/ic_action_reply.png | Bin 0 -> 486 bytes .../res/drawable-mdpi/ic_action_delete.png | Bin 0 -> 428 bytes .../res/drawable-mdpi/ic_action_reply.png | Bin 0 -> 330 bytes .../res/drawable-xhdpi/ic_action_delete.png | Bin 0 -> 775 bytes .../res/drawable-xhdpi/ic_action_reply.png | Bin 0 -> 623 bytes .../res/drawable-xxhdpi/ic_action_delete.png | Bin 0 -> 1171 bytes .../res/drawable-xxhdpi/ic_action_reply.png | Bin 0 -> 929 bytes .../main/res/layout/fragment_message_list.xml | 9 +- app/src/main/res/values/strings.xml | 3 + 16 files changed, 158 insertions(+), 35 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_action_delete.png create mode 100644 app/src/main/res/drawable-hdpi/ic_action_reply.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_delete.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_reply.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_delete.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_reply.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_delete.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_reply.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e94bbb0..ce67b34 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,8 @@ + + ) { Nameable ni = (Nameable) item; switch (ni.getNameRes()) { @@ -237,7 +245,6 @@ public class MessageListActivity extends AppCompatActivity getSupportFragmentManager().beginTransaction() .replace(R.id.message_detail_container, fragment) .commit(); - } else { // In single-pane mode, simply start the detail activity // for the selected item ID. diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java index 2dca634..abbd60d 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java @@ -82,6 +82,11 @@ public class MessageListFragment extends ListFragment { super.onCreate(savedInstanceState); bmc = Singleton.getBitmessageContext(getActivity()); + } + + @Override + public void onResume() { + super.onResume(); updateList(((MessageListActivity) getActivity()).getSelectedLabel()); } diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListener.java b/app/src/main/java/ch/dissem/apps/abit/MessageListener.java index 6b533f8..c9adc4f 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageListener.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageListener.java @@ -16,54 +16,134 @@ package ch.dissem.apps.abit; +import android.annotation.TargetApi; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.Build; +import android.provider.ContactsContract; import android.support.v7.app.NotificationCompat; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.StyleSpan; import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.entity.Plaintext; +import java.util.LinkedList; + /** - * Created by chris on 22.08.15. + * Listens for decrypted Bitmessage messages. Does show a notification. + *

+ * Should show a notification when the app isn't running, but update the message list when it is. Also, + * notifications should be combined. + *

*/ public class MessageListener implements BitmessageContext.Listener { + private static final StyleSpan SPAN_EMPHASIS = new StyleSpan(Typeface.BOLD); private final Context ctx; private final NotificationManager manager; + private final LinkedList unacknowledged = new LinkedList<>(); + private final int pictureSize; + private int numberOfUnacknowledgedMessages = 0; public MessageListener(Context ctx) { this.ctx = ctx.getApplicationContext(); this.manager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); + + this.pictureSize = getMaxContactPhotoSize(ctx); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + public static int getMaxContactPhotoSize(final Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + // Note that this URI is safe to call on the UI thread. + final Uri uri = ContactsContract.DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI; + final String[] projection = new String[]{ContactsContract.DisplayPhoto.DISPLAY_MAX_DIM}; + final Cursor c = context.getContentResolver().query(uri, projection, null, null, null); + try { + c.moveToFirst(); + return c.getInt(0); + } finally { + c.close(); + } + } + // fallback: 96x96 is the max contact photo size for pre-ICS versions + return 96; } @Override public void receive(final Plaintext plaintext) { - // TODO -// ctx.runOnUiThread(new Runnable() { -// @Override -// public void run() { + synchronized (unacknowledged) { + unacknowledged.addFirst(plaintext); + numberOfUnacknowledgedMessages++; + if (unacknowledged.size() > 5) { + unacknowledged.removeLast(); + } + } + NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx); - builder.setSmallIcon(R.drawable.ic_notification_new_message) - .setContentTitle(plaintext.getFrom().toString()) - .setContentText(plaintext.getSubject()); + if (numberOfUnacknowledgedMessages == 1) { + Spannable bigText = new SpannableString(plaintext.getSubject() + "\n" + plaintext.getText()); + bigText.setSpan(SPAN_EMPHASIS, 0, plaintext.getSubject().length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + builder.setSmallIcon(R.drawable.ic_notification_new_message) + .setLargeIcon(toBitmap(new Identicon(plaintext.getFrom()))) + .setContentTitle(plaintext.getFrom().toString()) + .setContentText(plaintext.getSubject()) + .setStyle(new NotificationCompat.BigTextStyle().bigText(bigText)) + .setContentInfo("Info"); - NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); - inboxStyle.setBigContentTitle(plaintext.getFrom().toString()); - inboxStyle.setSummaryText(plaintext.getSubject()); - String text = plaintext.getText(); - if (text.length() > 100) - inboxStyle.addLine(text.substring(0, 100) + "…"); - else - inboxStyle.addLine(text); - builder.setStyle(inboxStyle); + Intent showMessageIntent = new Intent(ctx, MessageListActivity.class); + showMessageIntent.putExtra(MessageListActivity.EXTRA_SHOW_MESSAGE, plaintext); + PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, showMessageIntent, PendingIntent.FLAG_UPDATE_CURRENT); + builder.setContentIntent(pendingIntent); - Intent intent = new Intent(ctx, MessageListActivity.class); - intent.putExtra(MessageListActivity.EXTRA_SHOW_MESSAGE, plaintext); - PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, intent, 0); - builder.setContentIntent(pendingIntent); + builder.addAction(R.drawable.ic_action_reply, ctx.getString(R.string.reply), pendingIntent); + builder.addAction(R.drawable.ic_action_delete, ctx.getString(R.string.delete), pendingIntent); + } else { + builder.setSmallIcon(R.drawable.ic_notification_new_message) + .setContentTitle(ctx.getString(R.string.n_new_messages, this.unacknowledged.size())) + .setContentText(ctx.getString(R.string.app_name)); + + NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); + synchronized (unacknowledged) { + inboxStyle.setBigContentTitle(ctx.getString(R.string.n_new_messages, numberOfUnacknowledgedMessages)); + for (Plaintext msg : unacknowledged) { + Spannable sb = new SpannableString(msg.getFrom() + " " + msg.getSubject()); + sb.setSpan(SPAN_EMPHASIS, 0, String.valueOf(msg.getFrom()).length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + inboxStyle.addLine(sb); + } + } + builder.setStyle(inboxStyle); + + Intent intent = new Intent(ctx, MessageListActivity.class); + intent.setAction(MessageListActivity.ACTION_SHOW_INBOX); + PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 1, intent, 0); + builder.setContentIntent(pendingIntent); + } manager.notify(0, builder.build()); -// } -// }); + } + + private Bitmap toBitmap(Identicon identicon) { + Bitmap bitmap = Bitmap.createBitmap(pictureSize, pictureSize, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + identicon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + identicon.draw(canvas); + return bitmap; + } + + public void resetNotification() { + manager.cancel(0); + synchronized (unacknowledged) { + unacknowledged.clear(); + numberOfUnacknowledgedMessages = 0; + } } } diff --git a/app/src/main/java/ch/dissem/apps/abit/repositories/AndroidMessageRepository.java b/app/src/main/java/ch/dissem/apps/abit/repositories/AndroidMessageRepository.java index 8fa1bd6..b290834 100644 --- a/app/src/main/java/ch/dissem/apps/abit/repositories/AndroidMessageRepository.java +++ b/app/src/main/java/ch/dissem/apps/abit/repositories/AndroidMessageRepository.java @@ -19,6 +19,7 @@ package ch.dissem.apps.abit.repositories; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; +import android.database.sqlite.SQLiteConstraintException; import android.database.sqlite.SQLiteDatabase; import ch.dissem.apps.abit.R; import ch.dissem.bitmessage.InternalContext; @@ -151,6 +152,24 @@ public class AndroidMessageRepository implements MessageRepository, InternalCont return label; } + @Override + public int countUnread(Label label) { + String where; + if (label != null) { + where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ") AND "; + } else { + where = ""; + } + SQLiteDatabase db = sql.getReadableDatabase(); + Cursor c = db.query( + TABLE_NAME, new String[]{COLUMN_ID}, + where + "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" + + "SELECT id FROM Label WHERE type = '" + Label.Type.UNREAD.name() + "'))", + null, null, null, null + ); + return c.getColumnCount(); + } + @Override public List<Plaintext> findMessages(Label label) { if (label != null) { @@ -258,6 +277,8 @@ public class AndroidMessageRepository implements MessageRepository, InternalCont db.insertOrThrow(JOIN_TABLE_NAME, null, values); } db.setTransactionSuccessful(); + } catch (SQLiteConstraintException e) { + LOG.trace(e.getMessage(), e); } catch (IOException e) { LOG.error(e.getMessage(), e); } finally { diff --git a/app/src/main/res/drawable-hdpi/ic_action_delete.png b/app/src/main/res/drawable-hdpi/ic_action_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..4bb5259e1b93ae16b05c0c524be2a009525b72ee GIT binary patch literal 642 zcmV-|0)737P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm0006>Nkl<Zc-rk* zOG^S#6t*Y5ppb~D2!a+B1c8t7JyD?HMqC;})S`zQ7ZKV<A;F-K7Ha9rpW;um?}G_M z3P-wg9Agd~yw08b-Sf>k_uO-5TrNi(am0~-Bkgv3I+MvP{HF1Ee7@W5PT11;a5%i> z^?Ki-tpR#(O9FnsUpHZV%j5BUluD&3+Ytx`gU2+`=kt|yU0>^0P1AzoLg4YIeh}Cm z8v>n9XEK}3&Zg7pMJ`^pZAT!LO3lIO1H}FrjJ}3G8*$zov<^rTdd0ECAeNZnp-^ZY zli$FQx|v05QtQMdw&eu4NEI61@0qehx_q;W0I@A6fJOLX6#-&fP9PGA>|(Nl1q2Gj z7F*1yYgQ4n5lnmz*FPAZX_zpy!FxG|V~Ig5TkHkQ@67wydELw?(P(s&$~LdD&lY<C z3pePpD!fD@u|lF^1OkCT9IpRF2;>n87icH3)5g&D<M#;v54l10DzCB6xF^Oj97_yh z5z}^+=a4B>m#lj<)db*yfEWRWf@%W96eECqy{DQ0lES`Z2<@mQKuj?L$mtuZ2@q3~ zfZGBBZZQHpX{jbaOv#dA#>~lU2yGHmi~!HPn6##lK#iE9^$@oIs=||4RlK0X#1(}e zsE8B5Q!6U;Kyefv$Sd?feiR<aDfB>Y6dt%!NZ?kS0IJ7Rg{Aa~I05EuOq}}T8@f6% z#P@(+NhXs^I8BA&kxPWa6O4K_-cI!H)J@|W`wG05V>s59A3MI^PV<uzmF<x}Wk(!w c#1YHn3w4VJ<9!QSi~s-t07*qoM6N<$g7y+4X#fBK literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_action_reply.png b/app/src/main/res/drawable-hdpi/ic_action_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..be372f5c96467ac0d30703bfacfe87b700e29789 GIT binary patch literal 486 zcmV<C0U7>@P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00054Nkl<Zc-rk) z%Syvg5G^Vqin>%#@rfXU3VGBtiE)vwhPaF1rie(?A8?bkQmL))RX!!Z=DAQL2166_ zymbx?f#!01PVUUynQ1f#1OkCTApC}=X$y*?9CJy&)oLwDlJwAQHf=7+i=y}l`{GW3 zuIo$q@*PH=I{~VyE{Dl;B>=&?0`gB`^4ti3+pL0YH%guh0dSkOIP$d@0Jm8O$>%uo zwHAO&YHJwz+6rLg5wN{s<eAB`eCGT9MA$sf8?VxBwn4t1g#5rhvHl}$`0b6QTi8A9 z;t;THd!~$l-APG4jWJPec8eEA9)I#u5cwYy1mPV*PIGlLobWC-e=VAPBzEpx*PZ0* z>qiYIaT^4|7}p|j5+_w=pj=`i*T5c#=w(c!X;0xY@8WGU%SC3I<}4D!KK8gtdJ2YN z%;hQq8*b!LO5puL61T*<qoRtrZq`}|KE9VABehHK1=19Aa5XoEc%Nk=%d(~lZD{`L z#?lC2F%k89JkOE7=ecMp9mkmtWvweVQ>uI-k+vVe`fC<fG*<c7gRPMmEsn%+mp~v8 c2!t~64NNBxHBfBzL;wH)07*qoM6N<$f-wEs8UO$Q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_delete.png b/app/src/main/res/drawable-mdpi/ic_action_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..95258c3d0d287aa4a99cf57b769719d7de066a9b GIT binary patch literal 428 zcmV;d0aN~oP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004VNkl<Zc-rk( zO-sW-6s!t@ClT}~h!=~8d?&X=0==amQk3Gc5}|mIl8Xiptq6ie>A_!<pB86e1rJub z+n1j5U?A-7dvA7jwro3{HrmjPD2nzy&kJ1F4Sxe;PFa>ajT5kK`wIB_3%>84HBP{B zoS|h|FI3_OVHh5hKoA7hMhKwUb5&K_d7keQaU35tMu6vv^F2l53*a7&-j^K#=3lvn zYndbB2^21tHCzFO1cCV)1m<fKz!kehp@l*71#?Awkf!M#&b5nzJ(>`>10K}z6#Q0W zL$#*M95ExJ*x@E}{=0e~z!P?RiydAom-m58q0ceSagAF0DM{c>*8|Lv{P~?4m~bja z0Mb6{5@3#`0uuuTCXxz_4HOtlns8)b!jTvOT(cWp0?d(AU|^uYKvIFsK!HrsggpZj z_9PW>bP3>nXp0f3>v{`2I!EEz3e9IAoG_=6H(`<_2WW7@_n)tV-yGvy`^TjX-S`G> W-dgJJ?G_3E0000<MNUMnLSTY%6|>9$ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_reply.png b/app/src/main/res/drawable-mdpi/ic_action_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..f93102a77b29c80856d49fe27ea4be564aef8399 GIT binary patch literal 330 zcmV-Q0k!^#P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80003INkl<Zc-muN z7zLwX6p#tb&CLVr>+6{Z#Bx(p(_j-5lbHkJ0HDu9L6+0q0ssI1XEZZ23x`=wR|kMB z2L^j2vgLGh0MzF(=$6yP0sHswX9D^>7MtZXcL2z8V1kRsWjPdQ03DbP!a#O1kPZRr zv9z|f=BI|wlL%Oj56=KO&c?<@oGi;hzM;T!WIWlz!oq~!zQ+g+pn19^I|7*U6R70~ zpaXgX0|U8fnh1fo1jwI?#}R%s&xZE)_I%JBfuYve*ti{3rjS(-0S$;Ewj6*a;v#Gg zh>VQnqDxT>EC)1^)b#`Px&qa*(ycNASq8Lp5>R~**}kT<ItHbO;n^TT3W<OLb-*YX c1;Yja0ECPo5Q-u&r~m)}07*qoM6N<$f}|UV*Z=?k literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_delete.png b/app/src/main/res/drawable-xhdpi/ic_action_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..35c97c1364da66b6b34000dd6dbeead3527f4f81 GIT binary patch literal 775 zcmV+i1Ni)jP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0008cNkl<Zc-rk+ zTWb?h5RTX41;k=Oyr9ts5tJ5l+a#<j30)zzmRL-ih6+9?GzRg~w?0HjDJU(JqEeso zQ}WZ|_sJGYu~)jYlkI#kY}!3%=FE5IoHJ*VM8aS&7z_r3!4Mv@*=!+`$$ZB1>p>)! z%e|@B>lb6;e5q6#NvG3)4l5wxbu0+*Jn!C72tXvfiz5Nw^7;Jj-2}7#BGv?8ANa6W zTM+Ol?h&xC4*?HiPe8xlKh<b7hPcZYi^VGxer`6K=VL)Yx7$4nr|!amB0_!|@@X3Z zn}O`R38LRB<URDfqAu5U?@+f&r+weQfKBWf&w330*HL!;1Ika@pe@=|;e4S`c!Ghg zhv@WfvQFEP6Mz|6j==e?WwIPO0T{?iR0Pnr5ujiRv?5#rt;h-B`HjI$Kz;~1Pg@hT zt>!4~^?IjqR^P|0RG9JxOJnmGoTZKx>ZESkpsj&OirVe=IUH5jkr+KhGLv;2r^J~< z##hCkHONdLHU5w9*oJM{hkdETDk_5j&YVOQhc;+S9RXOM8%%?ls`3tikba8iW2CJ~ zhH|-FzFMhNF4F;q_5XzL*oJM{hkdCd&^5i4YSWfF0;Ep?jS<ihJpVfyBVb7|0+uvJ zz@lITENUd6b)r(>onQ$|iU5`6GR(@nU<Ax-jDVV81k^NUf>Tli(3Uy^kgYwJB7nBk z5x`2V6aloQaS1qrOTf{%1jYoHz?eD$Siq1XfVMR50ZG9<AgPW3&+~3b5kOlS2^bb6 zU|1ai)oS&U6alOnX{-RBks^S$R2D`<{%ZW6q*AHhYAeIIrL76v1lKeZ&^eLyz-<J) z6u1gcswIG%6G*6sIQz3|H^3cf@huE^4g>yv3{F$Woa?$b2l6X3-}kTa@&ZT3`TJiy z-}2{j2<4A>exU@P7x*q{GmZ=2DElT127|$1Fc=Ks;4d*E8+Vu3%W?n!002ovPDHLk FV1kraVFv&J literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_reply.png b/app/src/main/res/drawable-xhdpi/ic_action_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..ea7c4eacbb20115898b86547994141c2dbd52ff3 GIT binary patch literal 623 zcmV-#0+9WQP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0006uNkl<Zc-rln zO-lk%6o#$nlQt1;`k+k|waghO9mP-(bmPVrgGw1iWswy@R12YkXc0tE)UWZU**S0p znf#hTXRi007tT)S&hy?gckVrB0s$6_#bU8oEEbE!@<_U_=c?7}I63foy*`5Qnx_4d zGeE#w2v5!cJ3J`^YPH%Zz!#h0$r#WMo`eAi9}0yITEQ!CfSCDGJ9woH0I)Hb`J+zo z${HZxkGsJuX#m0l*l92D${8Tw&w7Pd$^Zm`1@GJmyfOv|_zS1-N*GWsmnUGsyL1DO zu>&#;L$^mH64^FQb2A=~FX9-|!o$p8xrKKSKQPWS7_*P&WV6{R-{JH5{3P7ewFmJ3 z0>=G>tSclEi3LC5Z~cI8j$knO4H>bA_v0CSDwUd+0p6AoPqA2R$rE@O@J=T9ruYbl z!|UW`-@Z0LCajWp{yUiPmdRvh2W|okb|bL~Co1g$Tm`HLTV9z^ku(eLr9TIB+6u!A z?&4+#pJ}((jz*(vLw^{;vKn}#!KUZcMHUpLt_3(b4O*5p<8<o{zkf#ql_`kengjoN zbhsF<NLvqdQxCu`FP;v2xb_$JA2D;3D~fihJmJx~luoDTeXkF~jT{cb07z@2)wQrN zW18l&@{N&XGC5~k>>l9Nxgl+L2rD`Lt_kA72jT@^k=S(}h89_0o1?f{!pCfAil?GU zS|HgTZ;12<675VN`H_@Z#B!t!XqZ6S02YhIVzF2(7K`P({s5=M)cYxsgctw-002ov JPDHLkV1isV74854 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_delete.png b/app/src/main/res/drawable-xxhdpi/ic_action_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..cfb99e17625e1bc3f13513ee978ca7c8ea6787a9 GIT binary patch literal 1171 zcmV;E1Z?|>P)<h;3K|Lk000e1NJLTq003YB003YJ1^@s6;+S_h000D9Nkl<Zc-rk< z`%6?o6t?#Zdf0=Yi2BKjp6ui9?$s7GSN8`|OUOk<$y!81K@w4@WmBn?FiKnd$v?$E z&CUlSY!<rfuI|ja-v<NB-Fs)wobR49GiM&Ru8trGf*=TjAP9mW2!bGpU}I}*>xl3B z7gDLzmHnpH*49g#o0~_e%`%ZpCeKGAk@w+ncwN%(3evjd^HK7<My-~CXf!%pq2m8a zLc%n)S_bgeR+)ew8yg$PsoByA$W@zwTrPKln%yS>un5od9+aBo{z(#0MFONv7$~z1 z=^z2sCE!Jw1SCm7Z3#$_01}{&04TAir{^3-$TGO9#{kQudR)VQxQ7Ik8FI*EGH0dt za!XPK4X7yWTd@K|q0le6R;ZvGT9ADEk#{T>3!|)5Ds={B2TtLL&B)t&Qxwr63VAEa z`2+=5v)^B0T0_|)!yA#Mxv8n?hU&OcOH0dDsqjmw_+kx|U20l{jF450;>X6uPD-UR zmAH_@PLLHcLv{@f>Yyu%{|^y^8X}t?TqOXqlK>Jx0!RP}sEB|GhY6T)o&ZdaOK)P% z!5+|TI-S0(Vl0r$<&MSUaZf5X<ACyKAS+~6IU+{j%=5fw@`hzYq0r}A4$x4xks%A2 zAY0%9aag+}Z`^&vhC~s4lHOqoQvC0-C~36{ie5!t$kXKAhq6#+dwcuEKnCPWbzA-Y z{im=-D3M597lqwvY;3$MzaPo(5F)3=3D@u+?!moy2G1f7weEy)(B)9Z8jlIYUBqo% zBn6o;lZJLeEdkOXu9${#1w9X`@N?hy?_sRa)zx+SFnl%2Kv^gg4KZYZEJd<?S4)6Y z^viBDRHo;XM_=5GphxAI*9Z$^ZIJ0D_3n}S%)Ntn*5om1#vpl9#@a4j)32H>An(9H zEU(!DW*rDY%xSiODF-ZIO0xxwJ759hnk`_&0Sg$>JPsIeU=CnFvkU5Vzy<Ycwt!9t zETB`f1++O}0c~mtz@&%m1VBd3E-31N3yP{GAQp=~ww(aTsM!TIIN*XB)DqzP{%zX{ zfQ)Jhz&x$(1VBc$1YiY(?F2wZwFF=<nC%2WMzsWBiAa^!`W#eRg^X$mz*f<sxmO$0 zit6pG*o7#ST(X#eCG{t4MIw;}i{n5Gb=qO`h7A=PGD@(3X^SmjItUgpVX*~F1i=Eb z7F$48JprEQ4OtwB8w!F8dS$T%^aa5Jx-GVV?jTq|hsBL>T0H?co5$kWu;w7Rpt!{@ zD6XCW-}j$dOu!TM1elYv3KsT&3aU=Z+M^*J<`|&%^8%w55ilCKV=WPPN26EE@U)aY zFFl`Fpue(#?V+NGhj2?~1KmOQ^_Ni=%H$6E9l$1OoP>+RRn1E35q!!7Z>pKf{Aten zEbREa$-23=X70f@*m?6Alo8~GqYU^dlM2bfF_POy7vrFf?T_`~_x91nxQ7RD5ClOG l1VIo4K@bE%5CriL{s7)|T+`%{0IL81002ovPDHLkV1lj^8Lj{T literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_reply.png b/app/src/main/res/drawable-xxhdpi/ic_action_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6d9efdf8c8f64f5f26fcfad31d1d1f2a48b453 GIT binary patch literal 929 zcmV;S177@zP)<h;3K|Lk000e1NJLTq003YB003YJ1^@s6;+S_h000AMNkl<Zc-rlp zS&I`v6ouo88}1L{lM5pFXx2^>@(@W#Kto_aA}XjTOki9`QDh9txPgi|xXe?2N`6{A z7kVU&qv@qOb-Vj~P;a5BoKsb|s_yO1<p?2!5JCtcgb+dqA%qY@2$^OwnQW6rB`h!= zkGGdfrK{a;cMsLDBz~b#Sf>FN#is#tW;h(~C>D!1HpHg^mc^$5b6j?|5}yXlY2-ub zJ6nlQ11yVA17cowW{FP&;v4z9AnxKU@o9i%@o9izMx)WrAmY;igA4|P-8kVc1reVH zm=*tiQ1NMip*0_etOsGlrvVXZHk*4P{-dzs(}0NLW7&BUMSL0%5)lm}e>tl7G#~`M zUT;6de`-Q}8W2K!i1yr+_%t8@{eFKRM*a(v;?n@1)a&(wafmNXo-HQ)ugN(>PT85P zpb&wu+gXW2e6M}?(bmwupuLkN5dFD}0db{TtzK-m+sEYQHI?FbI-LVCi*KU+LVJsL z&2gLysWHQK-9rfw|F4Fb@e%#LEd5Wc_>D&62>#6Lq=~<&t-*{1nZ=14`6&>8dPaQ0 z(o{}F07t+*nkMn5n*?sTKGA%)a~z{(HI3p=&4yR<Kh=pZTRCqhv7Yt@6Fy-3dP1E6 z=-8Vq7_hNZlK;$|kKLHCqAn(6%>>MZ+v;{lY1@YSm<gpU-v6jNC&)EBO|Wai0x#n% zUt380Q)`0hELe!^=-5ptm&-lvd0=Y^8TkzkPv<I?O4DRMdUGt0#1B)FK9G|v`f|(5 z1sLm#<2d<DRYXM131itfpU>yt8=M9A)ZdtT)o{yNlJc!q>#)I%!dH2#N4*K!3bQ0e zc==)zG3iVq5;rmv(Ba2g%2H~z+F2||KceQB)yIKpWY-X-GTL-q5Msj32<!ht*L6=N zE`O}4Jl)$J{S4TLmr_lU=n4u=FKFPI&wP&fRk?^uM9}qXLeTfa;xGWqP-}+ppP~CD znYp>Nq2VPxEGMV`A^bO-q`RsU^QK~g&DT`DnfT{~EIT8N`0Hvf+u|}o%0O&YM@!Dv zd;TK!^(S*##O9|8q)t@M1-Y!lk98<9L6YAz!18j$4>swT3H)T4HWO&ToRLB(ezsCU zOyGxGm6$*SEH6j=csC)05JCtcgb+dqA%qY@2=UEtK(888yXmjc00000NkvXXu0mjf D`NXp3 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/fragment_message_list.xml b/app/src/main/res/layout/fragment_message_list.xml index 6e7982b..cd73e5b 100644 --- a/app/src/main/res/layout/fragment_message_list.xml +++ b/app/src/main/res/layout/fragment_message_list.xml @@ -2,18 +2,21 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent" - xmlns:fab="http://schemas.android.com/tools"> + android:layout_height="match_parent"> <ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@id/android:list" + android:paddingBottom="88dp" + android:clipToPadding="false" + android:scrollbarStyle="outsideOverlay" + android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" - android:layout_alignParentBottom="true" /> + android:layout_alignParentBottom="true"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab_compose_message" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index be41919..9dad53f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -24,4 +24,7 @@ <string name="do_import">Import</string> <string name="cancel">Cancel</string> <string name="broadcast">Broadcast</string> + <string name="n_new_messages">%d new messages</string> + <string name="reply">Reply</string> + <string name="delete">Delete</string> </resources>