mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 04:39:54 +01:00
Display conversations and groups even if they're empty.
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
<color name="content_background">#FFFFFF</color>
|
<color name="content_background">#FFFFFF</color>
|
||||||
<color name="unread_background">#FFFFFF</color>
|
<color name="unread_background">#FFFFFF</color>
|
||||||
<color name="horizontal_border">#CCCCCC</color>
|
<color name="horizontal_border">#CCCCCC</color>
|
||||||
<color name="anonymous_author">#AAAAAA</color>
|
<color name="anonymous_author">#999999</color>
|
||||||
<color name="pseudonymous_author">#000000</color>
|
<color name="no_posts">#999999</color>
|
||||||
|
<color name="no_messages">#999999</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
<string name="contact_added">Contact added</string>
|
<string name="contact_added">Contact added</string>
|
||||||
<string name="done_button">Done</string>
|
<string name="done_button">Done</string>
|
||||||
<string name="messages_title">Messages</string>
|
<string name="messages_title">Messages</string>
|
||||||
|
<string name="no_messages">(No messages)</string>
|
||||||
<string name="format_from">From: %1$s</string>
|
<string name="format_from">From: %1$s</string>
|
||||||
<string name="format_to">To: %1$s</string>
|
<string name="format_to">To: %1$s</string>
|
||||||
<string name="compose_message_title">New Message</string>
|
<string name="compose_message_title">New Message</string>
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
<string name="to">To:</string>
|
<string name="to">To:</string>
|
||||||
<string name="anonymous">(Anonymous)</string>
|
<string name="anonymous">(Anonymous)</string>
|
||||||
<string name="groups_title">Groups</string>
|
<string name="groups_title">Groups</string>
|
||||||
|
<string name="no_posts">(No posts)</string>
|
||||||
<string name="create_group_title">New Group</string>
|
<string name="create_group_title">New Group</string>
|
||||||
<string name="choose_group_name">Choose a name for your group:</string>
|
<string name="choose_group_name">Choose a name for your group:</string>
|
||||||
<string name="compose_group_title">New Post</string>
|
<string name="compose_group_title">New Post</string>
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import net.sf.briar.android.widgets.HorizontalSpace;
|
|||||||
import net.sf.briar.api.Author;
|
import net.sf.briar.api.Author;
|
||||||
import net.sf.briar.api.db.GroupMessageHeader;
|
import net.sf.briar.api.db.GroupMessageHeader;
|
||||||
import net.sf.briar.api.messaging.Rating;
|
import net.sf.briar.api.messaging.Rating;
|
||||||
import net.sf.briar.util.StringUtils;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
@@ -77,22 +76,20 @@ class GroupAdapter extends ArrayAdapter<GroupMessageHeader> {
|
|||||||
name.setTextColor(res.getColor(R.color.anonymous_author));
|
name.setTextColor(res.getColor(R.color.anonymous_author));
|
||||||
name.setText(R.string.anonymous);
|
name.setText(R.string.anonymous);
|
||||||
} else {
|
} else {
|
||||||
name.setTextColor(res.getColor(R.color.pseudonymous_author));
|
|
||||||
name.setText(author.getName());
|
name.setText(author.getName());
|
||||||
}
|
}
|
||||||
authorLayout.addView(name);
|
authorLayout.addView(name);
|
||||||
innerLayout.addView(authorLayout);
|
innerLayout.addView(authorLayout);
|
||||||
|
|
||||||
if(item.getContentType().equals("text/plain")) {
|
if(item.getContentType().equals("text/plain")) {
|
||||||
if(!StringUtils.isNullOrEmpty(item.getSubject())) {
|
TextView subject = new TextView(ctx);
|
||||||
TextView subject = new TextView(ctx);
|
subject.setTextSize(14);
|
||||||
subject.setTextSize(14);
|
subject.setMaxLines(2);
|
||||||
subject.setMaxLines(2);
|
subject.setPadding(10, 0, 10, 10);
|
||||||
subject.setPadding(10, 0, 10, 10);
|
if(!item.isRead()) subject.setTypeface(null, BOLD);
|
||||||
if(!item.isRead()) subject.setTypeface(null, BOLD);
|
String s = item.getSubject();
|
||||||
subject.setText(item.getSubject());
|
subject.setText(s == null ? "" : s);
|
||||||
innerLayout.addView(subject);
|
innerLayout.addView(subject);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LinearLayout attachmentLayout = new LinearLayout(ctx);
|
LinearLayout attachmentLayout = new LinearLayout(ctx);
|
||||||
attachmentLayout.setOrientation(HORIZONTAL);
|
attachmentLayout.setOrientation(HORIZONTAL);
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
|||||||
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
|
||||||
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -62,7 +62,6 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
|
|||||||
@Inject private volatile DatabaseComponent db;
|
@Inject private volatile DatabaseComponent db;
|
||||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||||
private volatile boolean restricted = false;
|
private volatile boolean restricted = false;
|
||||||
private volatile boolean noGroups = true;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -126,23 +125,39 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadHeaders() {
|
private void loadHeaders() {
|
||||||
|
clearHeaders();
|
||||||
dbUiExecutor.execute(new Runnable() {
|
dbUiExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
serviceConnection.waitForStartup();
|
serviceConnection.waitForStartup();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
if(restricted) noGroups = db.getLocalGroups().isEmpty();
|
Collection<Group> subs = db.getSubscriptions();
|
||||||
for(Group g : db.getSubscriptions()) {
|
if(restricted) {
|
||||||
// Filter out restricted/unrestricted groups
|
Set<GroupId> local = new HashSet<GroupId>();
|
||||||
if(g.isRestricted() != restricted) continue;
|
for(Group g : db.getLocalGroups()) local.add(g.getId());
|
||||||
if(!restricted) noGroups = false;
|
for(Group g : subs) {
|
||||||
try {
|
if(!g.isRestricted()) continue;
|
||||||
Collection<GroupMessageHeader> headers =
|
boolean postable = local.contains(g.getId());
|
||||||
db.getMessageHeaders(g.getId());
|
try {
|
||||||
displayHeaders(g, headers);
|
Collection<GroupMessageHeader> headers =
|
||||||
} catch(NoSuchSubscriptionException e) {
|
db.getMessageHeaders(g.getId());
|
||||||
if(LOG.isLoggable(INFO))
|
displayHeaders(g, postable, headers);
|
||||||
LOG.info("Subscription removed");
|
} catch(NoSuchSubscriptionException e) {
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Subscription removed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(Group g : subs) {
|
||||||
|
if(g.isRestricted()) continue;
|
||||||
|
try {
|
||||||
|
Collection<GroupMessageHeader> headers =
|
||||||
|
db.getMessageHeaders(g.getId());
|
||||||
|
displayHeaders(g, true, headers);
|
||||||
|
} catch(NoSuchSubscriptionException e) {
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Subscription removed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
@@ -160,20 +175,24 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayHeaders(final Group g,
|
private void clearHeaders() {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
adapter.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayHeaders(final Group g, final boolean postable,
|
||||||
final Collection<GroupMessageHeader> headers) {
|
final Collection<GroupMessageHeader> headers) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
// Remove the old item, if any
|
// Remove the old item, if any
|
||||||
GroupListItem item = findGroup(g.getId());
|
GroupListItem item = findGroup(g.getId());
|
||||||
if(item != null) adapter.remove(item);
|
if(item != null) adapter.remove(item);
|
||||||
// Add a new item if there are any headers to display
|
// Add a new item
|
||||||
if(!headers.isEmpty()) {
|
adapter.add(new GroupListItem(g, postable, headers));
|
||||||
List<GroupMessageHeader> headerList =
|
adapter.sort(GroupComparator.INSTANCE);
|
||||||
new ArrayList<GroupMessageHeader>(headers);
|
|
||||||
adapter.add(new GroupListItem(g, headerList));
|
|
||||||
adapter.sort(GroupComparator.INSTANCE);
|
|
||||||
}
|
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
selectFirstUnread();
|
selectFirstUnread();
|
||||||
}
|
}
|
||||||
@@ -219,7 +238,7 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
|
|||||||
startActivity(new Intent(this, CreateBlogActivity.class));
|
startActivity(new Intent(this, CreateBlogActivity.class));
|
||||||
else startActivity(new Intent(this, CreateGroupActivity.class));
|
else startActivity(new Intent(this, CreateGroupActivity.class));
|
||||||
} else if(view == composeButton) {
|
} else if(view == composeButton) {
|
||||||
if(noGroups) {
|
if(countPostableGroups() == 0) {
|
||||||
NoGroupsDialog dialog = new NoGroupsDialog();
|
NoGroupsDialog dialog = new NoGroupsDialog();
|
||||||
dialog.setListener(this);
|
dialog.setListener(this);
|
||||||
dialog.setRestricted(restricted);
|
dialog.setRestricted(restricted);
|
||||||
@@ -232,6 +251,13 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int countPostableGroups() {
|
||||||
|
int postable = 0, count = adapter.getCount();
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
if(adapter.getItem(i).isPostable()) postable++;
|
||||||
|
return postable;
|
||||||
|
}
|
||||||
|
|
||||||
public void eventOccurred(DatabaseEvent e) {
|
public void eventOccurred(DatabaseEvent e) {
|
||||||
if(e instanceof GroupMessageAddedEvent) {
|
if(e instanceof GroupMessageAddedEvent) {
|
||||||
Group g = ((GroupMessageAddedEvent) e).getGroup();
|
Group g = ((GroupMessageAddedEvent) e).getGroup();
|
||||||
@@ -258,12 +284,15 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
|
|||||||
try {
|
try {
|
||||||
serviceConnection.waitForStartup();
|
serviceConnection.waitForStartup();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
boolean postable;
|
||||||
|
if(restricted) postable = db.getLocalGroups().contains(g);
|
||||||
|
else postable = true;
|
||||||
Collection<GroupMessageHeader> headers =
|
Collection<GroupMessageHeader> headers =
|
||||||
db.getMessageHeaders(g.getId());
|
db.getMessageHeaders(g.getId());
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if(LOG.isLoggable(INFO))
|
||||||
LOG.info("Partial load took " + duration + " ms");
|
LOG.info("Partial load took " + duration + " ms");
|
||||||
displayHeaders(g, headers);
|
displayHeaders(g, postable, headers);
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch(NoSuchSubscriptionException e) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
|
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
|
||||||
removeGroup(g.getId());
|
removeGroup(g.getId());
|
||||||
@@ -306,8 +335,13 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
|
|||||||
private static final GroupComparator INSTANCE = new GroupComparator();
|
private static final GroupComparator INSTANCE = new GroupComparator();
|
||||||
|
|
||||||
public int compare(GroupListItem a, GroupListItem b) {
|
public int compare(GroupListItem a, GroupListItem b) {
|
||||||
return String.CASE_INSENSITIVE_ORDER.compare(a.getGroupName(),
|
// The item with the newest message comes first
|
||||||
b.getGroupName());
|
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
||||||
|
if(aTime > bTime) return -1;
|
||||||
|
if(aTime < bTime) return 1;
|
||||||
|
// Break ties by group name
|
||||||
|
String aName = a.getGroupName(), bName = b.getGroupName();
|
||||||
|
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,6 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
import net.sf.briar.R;
|
import net.sf.briar.R;
|
||||||
import net.sf.briar.android.widgets.HorizontalSpace;
|
import net.sf.briar.android.widgets.HorizontalSpace;
|
||||||
import net.sf.briar.util.StringUtils;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -36,12 +35,12 @@ implements OnItemClickListener {
|
|||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
GroupListItem item = getItem(position);
|
GroupListItem item = getItem(position);
|
||||||
Context ctx = getContext();
|
Context ctx = getContext();
|
||||||
|
Resources res = ctx.getResources();
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(ctx);
|
LinearLayout layout = new LinearLayout(ctx);
|
||||||
layout.setOrientation(HORIZONTAL);
|
layout.setOrientation(HORIZONTAL);
|
||||||
if(item.getUnreadCount() > 0) {
|
if(item.getUnreadCount() > 0)
|
||||||
Resources res = ctx.getResources();
|
|
||||||
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
||||||
}
|
|
||||||
|
|
||||||
LinearLayout innerLayout = new LinearLayout(ctx);
|
LinearLayout innerLayout = new LinearLayout(ctx);
|
||||||
// Give me all the unused width
|
// Give me all the unused width
|
||||||
@@ -57,34 +56,43 @@ implements OnItemClickListener {
|
|||||||
else name.setText(item.getGroupName());
|
else name.setText(item.getGroupName());
|
||||||
innerLayout.addView(name);
|
innerLayout.addView(name);
|
||||||
|
|
||||||
if(item.getContentType().equals("text/plain")) {
|
if(item.isEmpty()) {
|
||||||
if(!StringUtils.isNullOrEmpty(item.getSubject())) {
|
TextView noPosts = new TextView(ctx);
|
||||||
|
noPosts.setTextSize(14);
|
||||||
|
noPosts.setPadding(10, 0, 10, 10);
|
||||||
|
noPosts.setTextColor(res.getColor(R.color.no_posts));
|
||||||
|
noPosts.setText(R.string.no_posts);
|
||||||
|
innerLayout.addView(noPosts);
|
||||||
|
layout.addView(innerLayout);
|
||||||
|
} else {
|
||||||
|
if(item.getContentType().equals("text/plain")) {
|
||||||
TextView subject = new TextView(ctx);
|
TextView subject = new TextView(ctx);
|
||||||
subject.setTextSize(14);
|
subject.setTextSize(14);
|
||||||
subject.setMaxLines(2);
|
subject.setMaxLines(2);
|
||||||
subject.setPadding(10, 0, 10, 10);
|
subject.setPadding(10, 0, 10, 10);
|
||||||
if(item.getUnreadCount() > 0) subject.setTypeface(null, BOLD);
|
if(item.getUnreadCount() > 0) subject.setTypeface(null, BOLD);
|
||||||
subject.setText(item.getSubject());
|
String s = item.getSubject();
|
||||||
|
subject.setText(s == null ? "" : s);
|
||||||
innerLayout.addView(subject);
|
innerLayout.addView(subject);
|
||||||
|
} else {
|
||||||
|
LinearLayout attachmentLayout = new LinearLayout(ctx);
|
||||||
|
attachmentLayout.setOrientation(HORIZONTAL);
|
||||||
|
ImageView attachment = new ImageView(ctx);
|
||||||
|
attachment.setPadding(10, 0, 10, 10);
|
||||||
|
attachment.setImageResource(R.drawable.content_attachment);
|
||||||
|
attachmentLayout.addView(attachment);
|
||||||
|
attachmentLayout.addView(new HorizontalSpace(ctx));
|
||||||
|
innerLayout.addView(attachmentLayout);
|
||||||
}
|
}
|
||||||
} else {
|
layout.addView(innerLayout);
|
||||||
LinearLayout attachmentLayout = new LinearLayout(ctx);
|
|
||||||
attachmentLayout.setOrientation(HORIZONTAL);
|
|
||||||
ImageView attachment = new ImageView(ctx);
|
|
||||||
attachment.setPadding(10, 0, 10, 10);
|
|
||||||
attachment.setImageResource(R.drawable.content_attachment);
|
|
||||||
attachmentLayout.addView(attachment);
|
|
||||||
attachmentLayout.addView(new HorizontalSpace(ctx));
|
|
||||||
innerLayout.addView(attachmentLayout);
|
|
||||||
}
|
|
||||||
layout.addView(innerLayout);
|
|
||||||
|
|
||||||
TextView date = new TextView(ctx);
|
TextView date = new TextView(ctx);
|
||||||
date.setTextSize(14);
|
date.setTextSize(14);
|
||||||
date.setPadding(0, 10, 10, 10);
|
date.setPadding(0, 10, 10, 10);
|
||||||
long then = item.getTimestamp(), now = System.currentTimeMillis();
|
long then = item.getTimestamp(), now = System.currentTimeMillis();
|
||||||
date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
|
date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
|
||||||
layout.addView(date);
|
layout.addView(date);
|
||||||
|
}
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
@@ -93,6 +101,7 @@ implements OnItemClickListener {
|
|||||||
long id) {
|
long id) {
|
||||||
GroupListItem item = getItem(position);
|
GroupListItem item = getItem(position);
|
||||||
Intent i = new Intent(getContext(), GroupActivity.class);
|
Intent i = new Intent(getContext(), GroupActivity.class);
|
||||||
|
i.putExtra("net.sf.briar.RESTRICTED", item.isRestricted());
|
||||||
i.putExtra("net.sf.briar.GROUP_ID", item.getGroupId().getBytes());
|
i.putExtra("net.sf.briar.GROUP_ID", item.getGroupId().getBytes());
|
||||||
i.putExtra("net.sf.briar.GROUP_NAME", item.getGroupName());
|
i.putExtra("net.sf.briar.GROUP_NAME", item.getGroupName());
|
||||||
getContext().startActivity(i);
|
getContext().startActivity(i);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package net.sf.briar.android.groups;
|
package net.sf.briar.android.groups;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -12,24 +14,37 @@ import net.sf.briar.api.messaging.GroupId;
|
|||||||
class GroupListItem {
|
class GroupListItem {
|
||||||
|
|
||||||
private final Group group;
|
private final Group group;
|
||||||
|
private final boolean postable, empty;
|
||||||
private final String authorName, contentType, subject;
|
private final String authorName, contentType, subject;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final int unread;
|
private final int unread;
|
||||||
|
|
||||||
GroupListItem(Group group, List<GroupMessageHeader> headers) {
|
GroupListItem(Group group, boolean postable,
|
||||||
if(headers.isEmpty()) throw new IllegalArgumentException();
|
Collection<GroupMessageHeader> headers) {
|
||||||
this.group = group;
|
this.group = group;
|
||||||
Collections.sort(headers, DescendingHeaderComparator.INSTANCE);
|
this.postable = postable;
|
||||||
GroupMessageHeader newest = headers.get(0);
|
empty = headers.isEmpty();
|
||||||
Author a = newest.getAuthor();
|
if(empty) {
|
||||||
if(a == null) authorName = null;
|
authorName = null;
|
||||||
else authorName = a.getName();
|
contentType = null;
|
||||||
contentType = newest.getContentType();
|
subject = null;
|
||||||
subject = newest.getSubject();
|
timestamp = 0;
|
||||||
timestamp = newest.getTimestamp();
|
unread = 0;
|
||||||
int unread = 0;
|
} else {
|
||||||
for(GroupMessageHeader h : headers) if(!h.isRead()) unread++;
|
List<GroupMessageHeader> list =
|
||||||
this.unread = unread;
|
new ArrayList<GroupMessageHeader>(headers);
|
||||||
|
Collections.sort(list, DescendingHeaderComparator.INSTANCE);
|
||||||
|
GroupMessageHeader newest = list.get(0);
|
||||||
|
Author a = newest.getAuthor();
|
||||||
|
if(a == null) authorName = null;
|
||||||
|
else authorName = a.getName();
|
||||||
|
contentType = newest.getContentType();
|
||||||
|
subject = newest.getSubject();
|
||||||
|
timestamp = newest.getTimestamp();
|
||||||
|
int unread = 0;
|
||||||
|
for(GroupMessageHeader h : list) if(!h.isRead()) unread++;
|
||||||
|
this.unread = unread;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupId getGroupId() {
|
GroupId getGroupId() {
|
||||||
@@ -40,6 +55,18 @@ class GroupListItem {
|
|||||||
return group.getName();
|
return group.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isRestricted() {
|
||||||
|
return group.isRestricted();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPostable() {
|
||||||
|
return postable;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isEmpty() {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
String getAuthorName() {
|
String getAuthorName() {
|
||||||
return authorName;
|
return authorName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,7 +150,6 @@ implements OnClickListener {
|
|||||||
author.setTextColor(res.getColor(R.color.anonymous_author));
|
author.setTextColor(res.getColor(R.color.anonymous_author));
|
||||||
author.setText(R.string.anonymous);
|
author.setText(R.string.anonymous);
|
||||||
} else {
|
} else {
|
||||||
author.setTextColor(res.getColor(R.color.pseudonymous_author));
|
|
||||||
author.setText(authorName);
|
author.setText(authorName);
|
||||||
}
|
}
|
||||||
header.addView(author);
|
header.addView(author);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import java.util.ArrayList;
|
|||||||
import net.sf.briar.R;
|
import net.sf.briar.R;
|
||||||
import net.sf.briar.android.widgets.HorizontalSpace;
|
import net.sf.briar.android.widgets.HorizontalSpace;
|
||||||
import net.sf.briar.api.db.PrivateMessageHeader;
|
import net.sf.briar.api.db.PrivateMessageHeader;
|
||||||
import net.sf.briar.util.StringUtils;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
@@ -65,15 +64,14 @@ class ConversationAdapter extends ArrayAdapter<PrivateMessageHeader> {
|
|||||||
innerLayout.addView(name);
|
innerLayout.addView(name);
|
||||||
|
|
||||||
if(item.getContentType().equals("text/plain")) {
|
if(item.getContentType().equals("text/plain")) {
|
||||||
if(!StringUtils.isNullOrEmpty(item.getSubject())) {
|
TextView subject = new TextView(ctx);
|
||||||
TextView subject = new TextView(ctx);
|
subject.setTextSize(14);
|
||||||
subject.setTextSize(14);
|
subject.setMaxLines(2);
|
||||||
subject.setMaxLines(2);
|
subject.setPadding(10, 0, 10, 10);
|
||||||
subject.setPadding(10, 0, 10, 10);
|
if(!item.isRead()) subject.setTypeface(null, BOLD);
|
||||||
if(!item.isRead()) subject.setTypeface(null, BOLD);
|
String s = item.getSubject();
|
||||||
subject.setText(item.getSubject());
|
subject.setText(s == null ? "" : s);
|
||||||
innerLayout.addView(subject);
|
innerLayout.addView(subject);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LinearLayout attachmentLayout = new LinearLayout(ctx);
|
LinearLayout attachmentLayout = new LinearLayout(ctx);
|
||||||
attachmentLayout.setOrientation(HORIZONTAL);
|
attachmentLayout.setOrientation(HORIZONTAL);
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
||||||
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -57,7 +55,6 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
|
|||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject private volatile DatabaseComponent db;
|
@Inject private volatile DatabaseComponent db;
|
||||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||||
private volatile boolean noContacts = true;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -101,18 +98,12 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
|
|||||||
dbUiExecutor.execute(new Runnable() {
|
dbUiExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// Wait for the service to be bound and started
|
|
||||||
serviceConnection.waitForStartup();
|
serviceConnection.waitForStartup();
|
||||||
// Load the contact list from the database
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Collection<Contact> contacts = db.getContacts();
|
for(Contact c : db.getContacts()) {
|
||||||
noContacts = contacts.isEmpty();
|
|
||||||
for(Contact c : contacts) {
|
|
||||||
try {
|
try {
|
||||||
// Load the headers from the database
|
|
||||||
Collection<PrivateMessageHeader> headers =
|
Collection<PrivateMessageHeader> headers =
|
||||||
db.getPrivateMessageHeaders(c.getId());
|
db.getPrivateMessageHeaders(c.getId());
|
||||||
// Display the headers in the UI
|
|
||||||
displayHeaders(c, headers);
|
displayHeaders(c, headers);
|
||||||
} catch(NoSuchContactException e) {
|
} catch(NoSuchContactException e) {
|
||||||
if(LOG.isLoggable(INFO))
|
if(LOG.isLoggable(INFO))
|
||||||
@@ -141,13 +132,9 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
|
|||||||
// Remove the old item, if any
|
// Remove the old item, if any
|
||||||
ConversationListItem item = findConversation(c.getId());
|
ConversationListItem item = findConversation(c.getId());
|
||||||
if(item != null) adapter.remove(item);
|
if(item != null) adapter.remove(item);
|
||||||
// Add a new item if there are any headers to display
|
// Add a new item
|
||||||
if(!headers.isEmpty()) {
|
adapter.add(new ConversationListItem(c, headers));
|
||||||
List<PrivateMessageHeader> headerList =
|
adapter.sort(ConversationComparator.INSTANCE);
|
||||||
new ArrayList<PrivateMessageHeader>(headers);
|
|
||||||
adapter.add(new ConversationListItem(c, headerList));
|
|
||||||
adapter.sort(ConversationComparator.INSTANCE);
|
|
||||||
}
|
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
selectFirstUnread();
|
selectFirstUnread();
|
||||||
}
|
}
|
||||||
@@ -188,7 +175,7 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(noContacts) {
|
if(adapter.isEmpty()) {
|
||||||
NoContactsDialog dialog = new NoContactsDialog();
|
NoContactsDialog dialog = new NoContactsDialog();
|
||||||
dialog.setListener(this);
|
dialog.setListener(this);
|
||||||
dialog.show(getSupportFragmentManager(), "NoContactsDialog");
|
dialog.show(getSupportFragmentManager(), "NoContactsDialog");
|
||||||
@@ -270,7 +257,9 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
|
|||||||
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
||||||
if(aTime > bTime) return -1;
|
if(aTime > bTime) return -1;
|
||||||
if(aTime < bTime) return 1;
|
if(aTime < bTime) return 1;
|
||||||
return 0;
|
// Break ties by contact name
|
||||||
|
String aName = a.getContactName(), bName = b.getContactName();
|
||||||
|
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP_1;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import net.sf.briar.R;
|
import net.sf.briar.R;
|
||||||
import net.sf.briar.util.StringUtils;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -35,12 +34,12 @@ implements OnItemClickListener {
|
|||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
ConversationListItem item = getItem(position);
|
ConversationListItem item = getItem(position);
|
||||||
Context ctx = getContext();
|
Context ctx = getContext();
|
||||||
|
Resources res = ctx.getResources();
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(ctx);
|
LinearLayout layout = new LinearLayout(ctx);
|
||||||
layout.setOrientation(HORIZONTAL);
|
layout.setOrientation(HORIZONTAL);
|
||||||
if(item.getUnreadCount() > 0) {
|
if(item.getUnreadCount() > 0)
|
||||||
Resources res = ctx.getResources();
|
|
||||||
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
||||||
}
|
|
||||||
|
|
||||||
LinearLayout innerLayout = new LinearLayout(ctx);
|
LinearLayout innerLayout = new LinearLayout(ctx);
|
||||||
// Give me all the unused width
|
// Give me all the unused width
|
||||||
@@ -58,23 +57,32 @@ implements OnItemClickListener {
|
|||||||
else name.setText(contactName);
|
else name.setText(contactName);
|
||||||
innerLayout.addView(name);
|
innerLayout.addView(name);
|
||||||
|
|
||||||
if(!StringUtils.isNullOrEmpty(item.getSubject())) {
|
if(item.isEmpty()) {
|
||||||
|
TextView noMessages = new TextView(ctx);
|
||||||
|
noMessages.setTextSize(14);
|
||||||
|
noMessages.setPadding(10, 0, 10, 10);
|
||||||
|
noMessages.setTextColor(res.getColor(R.color.no_messages));
|
||||||
|
noMessages.setText(R.string.no_messages);
|
||||||
|
innerLayout.addView(noMessages);
|
||||||
|
layout.addView(innerLayout);
|
||||||
|
} else {
|
||||||
TextView subject = new TextView(ctx);
|
TextView subject = new TextView(ctx);
|
||||||
subject.setTextSize(14);
|
subject.setTextSize(14);
|
||||||
subject.setMaxLines(2);
|
subject.setMaxLines(2);
|
||||||
subject.setPadding(10, 0, 10, 10);
|
subject.setPadding(10, 0, 10, 10);
|
||||||
if(unread > 0) subject.setTypeface(null, BOLD);
|
if(unread > 0) subject.setTypeface(null, BOLD);
|
||||||
subject.setText(item.getSubject());
|
String s = item.getSubject();
|
||||||
|
subject.setText(s == null ? "" : s);
|
||||||
innerLayout.addView(subject);
|
innerLayout.addView(subject);
|
||||||
}
|
layout.addView(innerLayout);
|
||||||
layout.addView(innerLayout);
|
|
||||||
|
|
||||||
TextView date = new TextView(ctx);
|
TextView date = new TextView(ctx);
|
||||||
date.setTextSize(14);
|
date.setTextSize(14);
|
||||||
date.setPadding(0, 10, 10, 10);
|
date.setPadding(0, 10, 10, 10);
|
||||||
long then = item.getTimestamp(), now = System.currentTimeMillis();
|
long then = item.getTimestamp(), now = System.currentTimeMillis();
|
||||||
date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
|
date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
|
||||||
layout.addView(date);
|
layout.addView(date);
|
||||||
|
}
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package net.sf.briar.android.messages;
|
package net.sf.briar.android.messages;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -12,19 +14,29 @@ import net.sf.briar.api.db.PrivateMessageHeader;
|
|||||||
class ConversationListItem {
|
class ConversationListItem {
|
||||||
|
|
||||||
private final Contact contact;
|
private final Contact contact;
|
||||||
|
private final boolean empty;
|
||||||
private final String subject;
|
private final String subject;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final int unread;
|
private final int unread;
|
||||||
|
|
||||||
ConversationListItem(Contact contact, List<PrivateMessageHeader> headers) {
|
ConversationListItem(Contact contact,
|
||||||
if(headers.isEmpty()) throw new IllegalArgumentException();
|
Collection<PrivateMessageHeader> headers) {
|
||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
Collections.sort(headers, DescendingHeaderComparator.INSTANCE);
|
empty = headers.isEmpty();
|
||||||
subject = headers.get(0).getSubject();
|
if(empty) {
|
||||||
timestamp = headers.get(0).getTimestamp();
|
subject = null;
|
||||||
int unread = 0;
|
timestamp = 0;
|
||||||
for(PrivateMessageHeader h : headers) if(!h.isRead()) unread++;
|
unread = 0;
|
||||||
this.unread = unread;
|
} else {
|
||||||
|
List<PrivateMessageHeader> list =
|
||||||
|
new ArrayList<PrivateMessageHeader>(headers);
|
||||||
|
Collections.sort(list, DescendingHeaderComparator.INSTANCE);
|
||||||
|
subject = list.get(0).getSubject();
|
||||||
|
timestamp = list.get(0).getTimestamp();
|
||||||
|
int unread = 0;
|
||||||
|
for(PrivateMessageHeader h : list) if(!h.isRead()) unread++;
|
||||||
|
this.unread = unread;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactId getContactId() {
|
ContactId getContactId() {
|
||||||
@@ -39,6 +51,10 @@ class ConversationListItem {
|
|||||||
return contact.getLocalAuthorId();
|
return contact.getLocalAuthorId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isEmpty() {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
String getSubject() {
|
String getSubject() {
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user