Updated group conversation view to resemble private conversation view.

This commit is contained in:
akwizgran
2014-02-08 17:36:17 +00:00
parent 4c6d79c474
commit 97fb9c8c3e
7 changed files with 181 additions and 44 deletions

View File

@@ -50,7 +50,7 @@ import android.widget.ListView;
public class ConversationActivity extends BriarActivity public class ConversationActivity extends BriarActivity
implements EventListener, OnClickListener, OnItemClickListener { implements EventListener, OnClickListener, OnItemClickListener {
private static final int REQUEST_READ_MESSAGE = 2; private static final int REQUEST_READ = 2;
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ConversationActivity.class.getName()); Logger.getLogger(ConversationActivity.class.getName());
@@ -239,7 +239,7 @@ implements EventListener, OnClickListener, OnItemClickListener {
@Override @Override
protected void onActivityResult(int request, int result, Intent data) { protected void onActivityResult(int request, int result, Intent data) {
super.onActivityResult(request, result, data); super.onActivityResult(request, result, data);
if(request == REQUEST_READ_MESSAGE && result == RESULT_PREV_NEXT) { if(request == REQUEST_READ && result == RESULT_PREV_NEXT) {
int position = data.getIntExtra("briar.POSITION", -1); int position = data.getIntExtra("briar.POSITION", -1);
if(position >= 0 && position < adapter.getCount()) if(position >= 0 && position < adapter.getCount())
displayMessage(position); displayMessage(position);
@@ -296,6 +296,6 @@ implements EventListener, OnClickListener, OnItemClickListener {
i.putExtra("briar.CONTENT_TYPE", header.getContentType()); i.putExtra("briar.CONTENT_TYPE", header.getContentType());
i.putExtra("briar.TIMESTAMP", header.getTimestamp()); i.putExtra("briar.TIMESTAMP", header.getTimestamp());
i.putExtra("briar.POSITION", position); i.putExtra("briar.POSITION", position);
startActivityForResult(i, REQUEST_READ_MESSAGE); startActivityForResult(i, REQUEST_READ);
} }
} }

View File

@@ -56,6 +56,7 @@ class ConversationAdapter extends ArrayAdapter<ConversationItem> {
authorView.init(header.getAuthor().getName(), VERIFIED); authorView.init(header.getAuthor().getName(), VERIFIED);
headerLayout.addView(authorView); headerLayout.addView(authorView);
// FIXME: Factor this out into a TimestampView
TextView date = new TextView(ctx); TextView date = new TextView(ctx);
date.setTextSize(14); date.setTextSize(14);
date.setPadding(0, pad, pad, pad); date.setPadding(0, pad, pad, pad);

View File

@@ -2,10 +2,9 @@ package org.briarproject.android.contact;
import java.util.Comparator; import java.util.Comparator;
public class ConversationItemComparator class ConversationItemComparator implements Comparator<ConversationItem> {
implements Comparator<ConversationItem> {
public static final ConversationItemComparator INSTANCE = static final ConversationItemComparator INSTANCE =
new ConversationItemComparator(); new ConversationItemComparator();
public int compare(ConversationItem a, ConversationItem b) { public int compare(ConversationItem a, ConversationItem b) {

View File

@@ -17,7 +17,6 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import org.briarproject.R; import org.briarproject.R;
import org.briarproject.android.AscendingHeaderComparator;
import org.briarproject.android.BriarActivity; import org.briarproject.android.BriarActivity;
import org.briarproject.android.util.HorizontalBorder; import org.briarproject.android.util.HorizontalBorder;
import org.briarproject.android.util.ListLoadingProgressBar; import org.briarproject.android.util.ListLoadingProgressBar;
@@ -26,6 +25,7 @@ import org.briarproject.api.android.DatabaseUiExecutor;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.MessageHeader; import org.briarproject.api.db.MessageHeader;
import org.briarproject.api.db.NoSuchMessageException;
import org.briarproject.api.db.NoSuchSubscriptionException; import org.briarproject.api.db.NoSuchSubscriptionException;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener; import org.briarproject.api.event.EventListener;
@@ -34,6 +34,7 @@ import org.briarproject.api.event.MessageExpiredEvent;
import org.briarproject.api.event.SubscriptionRemovedEvent; import org.briarproject.api.event.SubscriptionRemovedEvent;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.messaging.GroupId; import org.briarproject.api.messaging.GroupId;
import org.briarproject.api.messaging.MessageId;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@@ -48,7 +49,7 @@ import android.widget.ListView;
public class GroupActivity extends BriarActivity implements EventListener, public class GroupActivity extends BriarActivity implements EventListener,
OnClickListener, OnItemClickListener { OnClickListener, OnItemClickListener {
private static final int REQUEST_READ_POST = 2; private static final int REQUEST_READ = 2;
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(GroupActivity.class.getName()); Logger.getLogger(GroupActivity.class.getName());
@@ -125,11 +126,7 @@ OnClickListener, OnItemClickListener {
displayHeaders(headers); displayHeaders(headers);
} catch(NoSuchSubscriptionException e) { } catch(NoSuchSubscriptionException e) {
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed"); if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
runOnUiThread(new Runnable() { finishOnUiThread();
public void run() {
finish();
}
});
} catch(DbException e) { } catch(DbException e) {
if(LOG.isLoggable(WARNING)) if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e); LOG.log(WARNING, e.toString(), e);
@@ -148,30 +145,91 @@ OnClickListener, OnItemClickListener {
list.setVisibility(VISIBLE); list.setVisibility(VISIBLE);
loading.setVisibility(GONE); loading.setVisibility(GONE);
adapter.clear(); adapter.clear();
for(MessageHeader h : headers) adapter.add(h); for(MessageHeader h : headers) adapter.add(new GroupItem(h));
adapter.sort(AscendingHeaderComparator.INSTANCE); adapter.sort(GroupItemComparator.INSTANCE);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
selectFirstUnread(); expandMessages();
} }
}); });
} }
private void selectFirstUnread() { private void expandMessages() {
int firstUnread = -1, count = adapter.getCount(); // Expand unread messages and the last three messages
int firstExpanded = -1, count = adapter.getCount();
if(count == 0) return;
for(int i = 0; i < count; i++) { for(int i = 0; i < count; i++) {
if(!adapter.getItem(i).isRead()) { GroupItem item = adapter.getItem(i);
firstUnread = i; if(!item.getHeader().isRead() || i >= count - 3) {
break; if(firstExpanded == -1) firstExpanded = i;
item.setExpanded(true);
loadMessage(item.getHeader());
} }
} }
if(firstUnread == -1) list.setSelection(count - 1); // Scroll to the first expanded message
else list.setSelection(firstUnread); list.setSelection(firstExpanded);
}
private void loadMessage(final MessageHeader h) {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
lifecycleManager.waitForDatabase();
long now = System.currentTimeMillis();
byte[] body = db.getMessageBody(h.getId());
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Loading message took " + duration + " ms");
displayMessage(h.getId(), body);
if(!h.isRead()) {
now = System.currentTimeMillis();
db.setReadFlag(h.getId(), true);
duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Setting read took " + duration + " ms");
}
} catch(NoSuchMessageException e) {
if(LOG.isLoggable(INFO)) LOG.info("Message expired");
// The item will be removed when we get the event
} 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 database");
Thread.currentThread().interrupt();
}
}
});
}
private void displayMessage(final MessageId m, final byte[] body) {
runOnUiThread(new Runnable() {
public void run() {
int count = adapter.getCount();
for(int i = 0; i < count; i++) {
GroupItem item = adapter.getItem(i);
if(item.getHeader().getId().equals(m)) {
item.setBody(body);
adapter.notifyDataSetChanged();
return;
}
}
}
});
}
private void finishOnUiThread() {
runOnUiThread(new Runnable() {
public void run() {
finish();
}
});
} }
@Override @Override
protected void onActivityResult(int request, int result, Intent data) { protected void onActivityResult(int request, int result, Intent data) {
super.onActivityResult(request, result, data); super.onActivityResult(request, result, data);
if(request == REQUEST_READ_POST && result == RESULT_PREV_NEXT) { if(request == REQUEST_READ && result == RESULT_PREV_NEXT) {
int position = data.getIntExtra("briar.POSITION", -1); int position = data.getIntExtra("briar.POSITION", -1);
if(position >= 0 && position < adapter.getCount()) if(position >= 0 && position < adapter.getCount())
displayMessage(position); displayMessage(position);
@@ -197,11 +255,7 @@ OnClickListener, OnItemClickListener {
SubscriptionRemovedEvent s = (SubscriptionRemovedEvent) e; SubscriptionRemovedEvent s = (SubscriptionRemovedEvent) e;
if(s.getGroup().getId().equals(groupId)) { if(s.getGroup().getId().equals(groupId)) {
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed"); if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
runOnUiThread(new Runnable() { finishOnUiThread();
public void run() {
finish();
}
});
} }
} }
} }
@@ -218,7 +272,7 @@ OnClickListener, OnItemClickListener {
} }
private void displayMessage(int position) { private void displayMessage(int position) {
MessageHeader item = adapter.getItem(position); MessageHeader item = adapter.getItem(position).getHeader();
Intent i = new Intent(this, ReadGroupPostActivity.class); Intent i = new Intent(this, ReadGroupPostActivity.class);
i.putExtra("briar.GROUP_ID", groupId.getBytes()); i.putExtra("briar.GROUP_ID", groupId.getBytes());
i.putExtra("briar.GROUP_NAME", groupName); i.putExtra("briar.GROUP_NAME", groupName);
@@ -229,6 +283,6 @@ OnClickListener, OnItemClickListener {
i.putExtra("briar.CONTENT_TYPE", item.getContentType()); i.putExtra("briar.CONTENT_TYPE", item.getContentType());
i.putExtra("briar.TIMESTAMP", item.getTimestamp()); i.putExtra("briar.TIMESTAMP", item.getTimestamp());
i.putExtra("briar.POSITION", position); i.putExtra("briar.POSITION", position);
startActivityForResult(i, REQUEST_READ_POST); startActivityForResult(i, REQUEST_READ);
} }
} }

View File

@@ -1,7 +1,9 @@
package org.briarproject.android.groups; package org.briarproject.android.groups;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.Gravity.CENTER_VERTICAL; import static android.view.Gravity.CENTER_VERTICAL;
import static android.widget.LinearLayout.HORIZONTAL; import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.text.DateFormat.SHORT; import static java.text.DateFormat.SHORT;
import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP_1; import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP_1;
@@ -12,6 +14,7 @@ import org.briarproject.android.util.AuthorView;
import org.briarproject.android.util.LayoutUtils; import org.briarproject.android.util.LayoutUtils;
import org.briarproject.api.Author; import org.briarproject.api.Author;
import org.briarproject.api.db.MessageHeader; import org.briarproject.api.db.MessageHeader;
import org.briarproject.util.StringUtils;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
@@ -20,45 +23,71 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
class GroupAdapter extends ArrayAdapter<MessageHeader> { class GroupAdapter extends ArrayAdapter<GroupItem> {
private final int pad; private final int pad;
GroupAdapter(Context ctx) { GroupAdapter(Context ctx) {
super(ctx, android.R.layout.simple_expandable_list_item_1, super(ctx, android.R.layout.simple_expandable_list_item_1,
new ArrayList<MessageHeader>()); new ArrayList<GroupItem>());
pad = LayoutUtils.getPadding(ctx); pad = LayoutUtils.getPadding(ctx);
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
MessageHeader header = getItem(position); GroupItem item = getItem(position);
MessageHeader header = item.getHeader();
Context ctx = getContext(); Context ctx = getContext();
Resources res = ctx.getResources();
LinearLayout layout = new LinearLayout(ctx); LinearLayout headerLayout = new LinearLayout(ctx);
layout.setOrientation(HORIZONTAL); headerLayout.setOrientation(HORIZONTAL);
layout.setGravity(CENTER_VERTICAL); headerLayout.setGravity(CENTER_VERTICAL);
if(!header.isRead()) { int background;
Resources res = ctx.getResources(); if(header.isRead()) background = res.getColor(R.color.read_background);
layout.setBackgroundColor(res.getColor(R.color.unread_background)); else background = res.getColor(R.color.unread_background);
} headerLayout.setBackgroundColor(background);
AuthorView authorView = new AuthorView(ctx); AuthorView authorView = new AuthorView(ctx);
authorView.setLayoutParams(WRAP_WRAP_1); authorView.setLayoutParams(WRAP_WRAP_1);
Author author = header.getAuthor(); Author author = header.getAuthor();
if(author == null) authorView.init(null, header.getAuthorStatus()); if(author == null) authorView.init(null, header.getAuthorStatus());
else authorView.init(author.getName(), header.getAuthorStatus()); else authorView.init(author.getName(), header.getAuthorStatus());
layout.addView(authorView); headerLayout.addView(authorView);
// FIXME: Factor this out into a TimestampView
TextView date = new TextView(ctx); TextView date = new TextView(ctx);
date.setTextSize(14); date.setTextSize(14);
date.setPadding(0, pad, pad, pad); date.setPadding(0, pad, pad, pad);
long then = header.getTimestamp(), now = System.currentTimeMillis(); long then = header.getTimestamp(), now = System.currentTimeMillis();
date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT)); date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
layout.addView(date); headerLayout.addView(date);
return layout; if(!item.isExpanded()) return headerLayout;
LinearLayout expanded = new LinearLayout(ctx);
expanded.setOrientation(VERTICAL);
expanded.setGravity(CENTER_HORIZONTAL);
expanded.setBackgroundColor(background);
expanded.addView(headerLayout);
byte[] body = item.getBody();
if(body == null) {
ProgressBar progress = new ProgressBar(ctx);
progress.setPadding(pad, 0, pad, pad);
progress.setIndeterminate(true);
expanded.addView(progress);
} else if(header.getContentType().equals("text/plain")) {
TextView text = new TextView(ctx);
text.setPadding(pad, 0, pad, pad);
text.setBackgroundColor(background);
text.setText(StringUtils.fromUtf8(body));
expanded.addView(text);
}
return expanded;
} }
} }

View File

@@ -0,0 +1,37 @@
package org.briarproject.android.groups;
import org.briarproject.api.db.MessageHeader;
// This class is not thread-safe
class GroupItem {
private final MessageHeader header;
private boolean expanded;
private byte[] body;
GroupItem(MessageHeader header) {
this.header = header;
expanded = false;
body = null;
}
MessageHeader getHeader() {
return header;
}
boolean isExpanded() {
return expanded;
}
void setExpanded(boolean expanded) {
this.expanded = expanded;
}
byte[] getBody() {
return body;
}
void setBody(byte[] body) {
this.body = body;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.android.groups;
import java.util.Comparator;
class GroupItemComparator implements Comparator<GroupItem> {
static final GroupItemComparator INSTANCE = new GroupItemComparator();
public int compare(GroupItem a, GroupItem b) {
// The oldest message comes first
long aTime = a.getHeader().getTimestamp();
long bTime = b.getHeader().getTimestamp();
if(aTime < bTime) return -1;
if(aTime > bTime) return 1;
return 0;
}
}