diff --git a/briar-android/res/drawable-hdpi/content_new_email.png b/briar-android/res/drawable-hdpi/content_new_email.png new file mode 100644 index 0000000000000000000000000000000000000000..f1c6bcf2e001d754e21e5d9bad1d4a8de22e369a Binary files /dev/null and b/briar-android/res/drawable-hdpi/content_new_email.png differ diff --git a/briar-android/res/drawable-mdpi/content_new_email.png b/briar-android/res/drawable-mdpi/content_new_email.png new file mode 100644 index 0000000000000000000000000000000000000000..7d96f28d15f5a4a6906724b4a1516b0c1504f6b2 Binary files /dev/null and b/briar-android/res/drawable-mdpi/content_new_email.png differ diff --git a/briar-android/src/net/sf/briar/android/AscendingHeaderComparator.java b/briar-android/src/net/sf/briar/android/AscendingHeaderComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..26ac273e33ee80fb377aca5b402ee010452262c5 --- /dev/null +++ b/briar-android/src/net/sf/briar/android/AscendingHeaderComparator.java @@ -0,0 +1,19 @@ +package net.sf.briar.android; + +import java.util.Comparator; + +import net.sf.briar.api.db.MessageHeader; + +public class AscendingHeaderComparator implements Comparator<MessageHeader> { + + public static final AscendingHeaderComparator INSTANCE = + new AscendingHeaderComparator(); + + public int compare(MessageHeader a, MessageHeader b) { + // The oldest message comes first + long aTime = a.getTimestamp(), bTime = b.getTimestamp(); + if(aTime < bTime) return -1; + if(aTime > bTime) return 1; + return 0; + } +} diff --git a/briar-android/src/net/sf/briar/android/DescendingHeaderComparator.java b/briar-android/src/net/sf/briar/android/DescendingHeaderComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..02506d7a94816edb86767f3971233885a4005682 --- /dev/null +++ b/briar-android/src/net/sf/briar/android/DescendingHeaderComparator.java @@ -0,0 +1,19 @@ +package net.sf.briar.android; + +import java.util.Comparator; + +import net.sf.briar.api.db.MessageHeader; + +public class DescendingHeaderComparator implements Comparator<MessageHeader> { + + public static final DescendingHeaderComparator INSTANCE = + new DescendingHeaderComparator(); + + public int compare(MessageHeader a, MessageHeader 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; + } +} \ No newline at end of file diff --git a/briar-android/src/net/sf/briar/android/messages/AscendingHeaderComparator.java b/briar-android/src/net/sf/briar/android/messages/AscendingHeaderComparator.java deleted file mode 100644 index 651f719bea7206758654ad6febe2224df33e182d..0000000000000000000000000000000000000000 --- a/briar-android/src/net/sf/briar/android/messages/AscendingHeaderComparator.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.sf.briar.android.messages; - -import java.util.Comparator; - -import net.sf.briar.api.db.PrivateMessageHeader; - -class AscendingHeaderComparator implements Comparator<PrivateMessageHeader> { - - static final AscendingHeaderComparator INSTANCE = - new AscendingHeaderComparator(); - - public int compare(PrivateMessageHeader a, PrivateMessageHeader b) { - // The oldest message comes first - long aTime = a.getTimestamp(), bTime = b.getTimestamp(); - if(aTime < bTime) return -1; - if(aTime > bTime) return 1; - return 0; - } -} diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java index 247898665e97ccec5b8549c1ea7e0a23cbe9a128..60d3869012118d56ea94b15e01cb3791dbb598b5 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java @@ -13,6 +13,7 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; +import net.sf.briar.android.AscendingHeaderComparator; import net.sf.briar.android.BriarActivity; import net.sf.briar.android.BriarService; import net.sf.briar.android.BriarService.BriarServiceConnection; diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java index bd3e6d48e0cc487110f5f67393936b71fee1ce5c..561805748359773da5c4469758f759255503f290 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java @@ -91,7 +91,11 @@ implements OnClickListener, DatabaseListener { serviceConnection, 0); // Add some fake messages to the database in a background thread - // FIXME: Remove this + insertFakeMessages(); + } + + // FIXME: Remove this + private void insertFakeMessages() { final DatabaseComponent db = this.db; final MessageFactory messageFactory = this.messageFactory; dbExecutor.execute(new Runnable() { @@ -102,42 +106,39 @@ implements OnClickListener, DatabaseListener { // If there are no messages in the DB, create some fake ones Collection<PrivateMessageHeader> headers = db.getPrivateMessageHeaders(); - if(headers.isEmpty()) { - if(LOG.isLoggable(INFO)) - LOG.info("Inserting fake contact and messages"); - // Insert a fake contact - ContactId contactId = db.addContact("Carol"); - // Insert some text messages to and from the contact - for(int i = 0; i < 20; i++) { - String body; - if(i % 3 == 0) { - body = "Message " + i + " is short."; - } else { - body = "Message " + i + " is long enough to" - + " wrap onto a second line on some" - + " screens."; - } - Message m = messageFactory.createPrivateMessage( - null, "text/plain", body.getBytes("UTF-8")); - if(Math.random() < 0.5) - db.addLocalPrivateMessage(m, contactId); - else db.receiveMessage(contactId, m); - db.setReadFlag(m.getId(), i != 3); + if(!headers.isEmpty()) return; + if(LOG.isLoggable(INFO)) + LOG.info("Inserting fake private messages"); + // We'll also need a contact to exchange messages with + ContactId contactId = db.addContact("Carol"); + // Insert some text messages to and from the contact + for(int i = 0; i < 20; i++) { + String body; + if(i % 3 == 0) { + body = "Message " + i + " is short."; + } else { + body = "Message " + i + " is long enough to" + + " wrap onto a second line on some" + + " screens."; } - // Insert a non-text message Message m = messageFactory.createPrivateMessage(null, - "image/jpeg", new byte[1000]); - db.receiveMessage(contactId, m); - db.setStarredFlag(m.getId(), true); - // Insert a long text message - StringBuilder s = new StringBuilder(); - for(int i = 0; i < 100; i++) - s.append("This is a very tedious message. "); - m = messageFactory.createPrivateMessage(m.getId(), - "text/plain", s.toString().getBytes("UTF-8")); - db.addLocalPrivateMessage(m, contactId); - db.setStarredFlag(m.getId(), true); + "text/plain", body.getBytes("UTF-8")); + if(Math.random() < 0.5) + db.addLocalPrivateMessage(m, contactId); + else db.receiveMessage(contactId, m); + db.setReadFlag(m.getId(), i % 4 == 0); } + // Insert a non-text message + Message m = messageFactory.createPrivateMessage(null, + "image/jpeg", new byte[1000]); + db.receiveMessage(contactId, m); + // Insert a long text message + StringBuilder s = new StringBuilder(); + for(int i = 0; i < 100; i++) + s.append("This is a very tedious message. "); + m = messageFactory.createPrivateMessage(m.getId(), + "text/plain", s.toString().getBytes("UTF-8")); + db.addLocalPrivateMessage(m, contactId); } catch(DbException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -162,27 +163,6 @@ implements OnClickListener, DatabaseListener { reloadMessageHeaders(); } - @Override - public void onDestroy() { - super.onDestroy(); - db.removeListener(this); - unbindService(serviceConnection); - } - - public void onClick(View view) { - startActivity(new Intent(this, WriteMessageActivity.class)); - } - - public void eventOccurred(DatabaseEvent e) { - if(e instanceof MessageAddedEvent) { - if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading"); - reloadMessageHeaders(); - } else if(e instanceof MessageExpiredEvent) { - if(LOG.isLoggable(INFO)) LOG.info("Message removed, reloading"); - reloadMessageHeaders(); - } - } - private void reloadMessageHeaders() { final DatabaseComponent db = this.db; dbExecutor.execute(new Runnable() { @@ -249,4 +229,25 @@ implements OnClickListener, DatabaseListener { } return list; } + + @Override + public void onDestroy() { + super.onDestroy(); + db.removeListener(this); + unbindService(serviceConnection); + } + + public void onClick(View view) { + startActivity(new Intent(this, WriteMessageActivity.class)); + } + + public void eventOccurred(DatabaseEvent e) { + if(e instanceof MessageAddedEvent) { + if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading"); + reloadMessageHeaders(); + } else if(e instanceof MessageExpiredEvent) { + if(LOG.isLoggable(INFO)) LOG.info("Message removed, reloading"); + reloadMessageHeaders(); + } + } } diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java index f58645f0fdd20d8a0d7834ea3c73829109ee9b75..542a14d52e173b8c7d4b8fe7d97916167dca44b8 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java @@ -10,6 +10,7 @@ import static java.text.DateFormat.SHORT; import java.util.ArrayList; import net.sf.briar.android.widgets.CommonLayoutParams; +import net.sf.briar.util.StringUtils; import android.content.Context; import android.content.Intent; import android.text.format.DateUtils; @@ -45,17 +46,21 @@ implements OnItemClickListener { TextView name = new TextView(ctx); name.setTextSize(18); - name.setPadding(10, 10, 10, 0); - name.setText(item.getName() + " (" + item.getLength() + ")"); + name.setPadding(10, 10, 10, 10); + int unread = item.getUnreadCount(); + if(unread > 0) name.setText(item.getName() + " (" + unread + ")"); + else name.setText(item.getName()); innerLayout.addView(name); - TextView subject = new TextView(ctx); - subject.setTextSize(14); - subject.setMaxLines(2); - subject.setPadding(10, 0, 10, 10); - if(!item.isRead()) subject.setTypeface(null, BOLD); - subject.setText(item.getSubject()); - innerLayout.addView(subject); + if(!StringUtils.isNullOrEmpty(item.getSubject())) { + TextView subject = new TextView(ctx); + subject.setTextSize(14); + subject.setMaxLines(2); + subject.setPadding(10, 0, 10, 10); + if(unread > 0) subject.setTypeface(null, BOLD); + subject.setText(item.getSubject()); + innerLayout.addView(subject); + } layout.addView(innerLayout); TextView date = new TextView(ctx); diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java index 8ef55dd07bd59664c152bcb984fa09e73b3aea37..b168f7a9bce3f5b0a494efefc04185dfdee5b473 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java @@ -3,37 +3,35 @@ package net.sf.briar.android.messages; import java.util.Collections; import java.util.List; +import net.sf.briar.android.DescendingHeaderComparator; import net.sf.briar.api.Contact; import net.sf.briar.api.ContactId; import net.sf.briar.api.db.PrivateMessageHeader; class ConversationListItem { - private final ContactId contactId; - private final String name, subject; + private final Contact contact; + private final String subject; private final long timestamp; - private final int length; - private final boolean read; + private final int unread; ConversationListItem(Contact contact, List<PrivateMessageHeader> headers) { if(headers.isEmpty()) throw new IllegalArgumentException(); - contactId = contact.getId(); - name = contact.getName(); + this.contact = contact; Collections.sort(headers, DescendingHeaderComparator.INSTANCE); subject = headers.get(0).getSubject(); timestamp = headers.get(0).getTimestamp(); - length = headers.size(); - boolean allRead = true; - for(PrivateMessageHeader h : headers) allRead &= h.isRead(); - read = allRead; + int unread = 0; + for(PrivateMessageHeader h : headers) if(!h.isRead()) unread++; + this.unread = unread; } ContactId getContactId() { - return contactId; + return contact.getId(); } String getName() { - return name; + return contact.getName(); } String getSubject() { @@ -44,11 +42,7 @@ class ConversationListItem { return timestamp; } - boolean isRead() { - return read; - } - - int getLength() { - return length; + int getUnreadCount() { + return unread; } } diff --git a/briar-android/src/net/sf/briar/android/messages/DescendingHeaderComparator.java b/briar-android/src/net/sf/briar/android/messages/DescendingHeaderComparator.java deleted file mode 100644 index 1a8032f0987bed60d75d76d15635734917175685..0000000000000000000000000000000000000000 --- a/briar-android/src/net/sf/briar/android/messages/DescendingHeaderComparator.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.sf.briar.android.messages; - -import java.util.Comparator; - -import net.sf.briar.api.db.PrivateMessageHeader; - -class DescendingHeaderComparator implements Comparator<PrivateMessageHeader> { - - static final DescendingHeaderComparator INSTANCE = - new DescendingHeaderComparator(); - - 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; - } -} \ No newline at end of file