Facades for forums. #172

This commit is contained in:
akwizgran
2015-12-17 13:37:55 +00:00
parent d0ba274111
commit 4450ab171a
25 changed files with 285 additions and 128 deletions

View File

@@ -170,7 +170,7 @@ public class BriarService extends RoboService implements EventListener {
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof MessageAddedEvent) { if (e instanceof MessageAddedEvent) {
MessageAddedEvent m = (MessageAddedEvent) e; MessageAddedEvent m = (MessageAddedEvent) e;
GroupId g = m.getGroup().getId(); GroupId g = m.getGroupId();
ContactId c = m.getContactId(); ContactId c = m.getContactId();
if (c != null) showMessageNotification(g, c); if (c != null) showMessageNotification(g, c);
} }

View File

@@ -347,7 +347,7 @@ implements EventListener, OnClickListener, OnItemClickListener {
finishOnUiThread(); finishOnUiThread();
} }
} else if (e instanceof MessageAddedEvent) { } else if (e instanceof MessageAddedEvent) {
GroupId g = ((MessageAddedEvent) e).getGroup().getId(); GroupId g = ((MessageAddedEvent) e).getGroupId();
if (g.equals(groupId)) { if (g.equals(groupId)) {
LOG.info("Message added, reloading"); LOG.info("Message added, reloading");
loadHeaders(); loadHeaders();

View File

@@ -20,8 +20,8 @@ import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent; import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent;
import org.briarproject.api.event.SubscriptionAddedEvent; import org.briarproject.api.event.SubscriptionAddedEvent;
import org.briarproject.api.event.SubscriptionRemovedEvent; import org.briarproject.api.event.SubscriptionRemovedEvent;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import java.util.ArrayList; import java.util.ArrayList;
@@ -43,7 +43,6 @@ implements EventListener, OnItemClickListener {
private AvailableForumsAdapter adapter = null; private AvailableForumsAdapter adapter = null;
private ListView list = null; private ListView list = null;
private ListLoadingProgressBar loading = null;
// Fields that are accessed from background threads must be volatile // Fields that are accessed from background threads must be volatile
@Inject private volatile ForumManager forumManager; @Inject private volatile ForumManager forumManager;
@@ -60,7 +59,7 @@ implements EventListener, OnItemClickListener {
list.setOnItemClickListener(this); list.setOnItemClickListener(this);
// Show a progress bar while the list is loading // Show a progress bar while the list is loading
loading = new ListLoadingProgressBar(this); ListLoadingProgressBar loading = new ListLoadingProgressBar(this);
setContentView(loading); setContentView(loading);
} }
@@ -78,12 +77,12 @@ implements EventListener, OnItemClickListener {
Collection<ForumContacts> available = Collection<ForumContacts> available =
new ArrayList<ForumContacts>(); new ArrayList<ForumContacts>();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
for (Group g : forumManager.getAvailableGroups()) { for (Forum f : forumManager.getAvailableForums()) {
try { try {
GroupId id = g.getId(); GroupId id = f.getId();
Collection<Contact> c = Collection<Contact> c =
forumManager.getSubscribers(id); forumManager.getSubscribers(id);
available.add(new ForumContacts(g, c)); available.add(new ForumContacts(f, c));
} catch (NoSuchSubscriptionException e) { } catch (NoSuchSubscriptionException e) {
// Continue // Continue
} }
@@ -142,18 +141,18 @@ implements EventListener, OnItemClickListener {
AvailableForumsItem item = adapter.getItem(position); AvailableForumsItem item = adapter.getItem(position);
Collection<ContactId> visible = new ArrayList<ContactId>(); Collection<ContactId> visible = new ArrayList<ContactId>();
for (Contact c : item.getContacts()) visible.add(c.getId()); for (Contact c : item.getContacts()) visible.add(c.getId());
addSubscription(item.getGroup(), visible); addSubscription(item.getForum(), visible);
String subscribed = getString(R.string.subscribed_toast); String subscribed = getString(R.string.subscribed_toast);
Toast.makeText(this, subscribed, LENGTH_SHORT).show(); Toast.makeText(this, subscribed, LENGTH_SHORT).show();
} }
private void addSubscription(final Group g, private void addSubscription(final Forum f,
final Collection<ContactId> visible) { final Collection<ContactId> visible) {
runOnDbThread(new Runnable() { runOnDbThread(new Runnable() {
public void run() { public void run() {
try { try {
forumManager.addGroup(g); forumManager.addForum(f);
forumManager.setVisibility(g.getId(), visible); forumManager.setVisibility(f.getId(), visible);
} 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);

View File

@@ -41,7 +41,7 @@ class AvailableForumsAdapter extends ArrayAdapter<AvailableForumsItem> {
name.setSingleLine(); name.setSingleLine();
name.setEllipsize(END); name.setEllipsize(END);
name.setPadding(pad, pad, pad, pad); name.setPadding(pad, pad, pad, pad);
name.setText(item.getGroup().getName()); name.setText(item.getForum().getName());
layout.addView(name); layout.addView(name);
TextView status = new TextView(ctx); TextView status = new TextView(ctx);

View File

@@ -1,7 +1,7 @@
package org.briarproject.android.forum; package org.briarproject.android.forum;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.sync.Group; import org.briarproject.api.forum.Forum;
import java.util.Collection; import java.util.Collection;
@@ -13,8 +13,8 @@ class AvailableForumsItem {
this.forumContacts = forumContacts; this.forumContacts = forumContacts;
} }
Group getGroup() { Forum getForum() {
return forumContacts.getGroup(); return forumContacts.getForum();
} }
Collection<Contact> getContacts() { Collection<Contact> getContacts() {

View File

@@ -9,8 +9,8 @@ class AvailableForumsItemComparator implements Comparator<AvailableForumsItem> {
public int compare(AvailableForumsItem a, AvailableForumsItem b) { public int compare(AvailableForumsItem a, AvailableForumsItem b) {
if (a == b) return 0; if (a == b) return 0;
String aName = a.getGroup().getName(); String aName = a.getForum().getName();
String bName = b.getGroup().getName(); String bName = b.getForum().getName();
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName); return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
} }
} }

View File

@@ -17,9 +17,9 @@ import org.briarproject.R;
import org.briarproject.android.BriarActivity; import org.briarproject.android.BriarActivity;
import org.briarproject.android.util.LayoutUtils; import org.briarproject.android.util.LayoutUtils;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumFactory;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupFactory;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -52,7 +52,7 @@ implements OnEditorActionListener, OnClickListener {
private TextView feedback = null; private TextView feedback = null;
// Fields that are accessed from background threads must be volatile // Fields that are accessed from background threads must be volatile
@Inject private volatile GroupFactory groupFactory; @Inject private volatile ForumFactory forumFactory;
@Inject private volatile ForumManager forumManager; @Inject private volatile ForumManager forumManager;
@Override @Override
@@ -138,13 +138,13 @@ implements OnEditorActionListener, OnClickListener {
runOnDbThread(new Runnable() { runOnDbThread(new Runnable() {
public void run() { public void run() {
try { try {
Group g = groupFactory.createGroup(name); Forum f = forumFactory.createForum(name);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
forumManager.addGroup(g); forumManager.addForum(f);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Storing forum took " + duration + " ms"); LOG.info("Storing forum took " + duration + " ms");
displayForum(g); displayForum(f);
} 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);
@@ -154,13 +154,13 @@ implements OnEditorActionListener, OnClickListener {
}); });
} }
private void displayForum(final Group g) { private void displayForum(final Forum f) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
Intent i = new Intent(CreateForumActivity.this, Intent i = new Intent(CreateForumActivity.this,
ForumActivity.class); ForumActivity.class);
i.putExtra("briar.GROUP_ID", g.getId().getBytes()); i.putExtra("briar.GROUP_ID", f.getId().getBytes());
i.putExtra("briar.FORUM_NAME", g.getName()); i.putExtra("briar.FORUM_NAME", f.getName());
startActivity(i); startActivity(i);
Toast.makeText(CreateForumActivity.this, Toast.makeText(CreateForumActivity.this,
R.string.forum_created_toast, LENGTH_LONG).show(); R.string.forum_created_toast, LENGTH_LONG).show();

View File

@@ -26,9 +26,9 @@ import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener; import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.MessageAddedEvent; import org.briarproject.api.event.MessageAddedEvent;
import org.briarproject.api.event.SubscriptionRemovedEvent; import org.briarproject.api.event.SubscriptionRemovedEvent;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageHeader; import org.briarproject.api.sync.MessageHeader;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -74,7 +74,7 @@ OnClickListener, OnItemClickListener {
@Inject private volatile ForumManager forumManager; @Inject private volatile ForumManager forumManager;
@Inject private volatile EventBus eventBus; @Inject private volatile EventBus eventBus;
private volatile GroupId groupId = null; private volatile GroupId groupId = null;
private volatile Group group = null; private volatile Forum forum = null;
@Override @Override
public void onCreate(Bundle state) { public void onCreate(Bundle state) {
@@ -152,10 +152,10 @@ OnClickListener, OnItemClickListener {
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
group = forumManager.getGroup(groupId); forum = forumManager.getForum(groupId);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Loading group " + duration + " ms"); LOG.info("Loading forum " + duration + " ms");
displayForumName(); displayForumName();
} catch (NoSuchSubscriptionException e) { } catch (NoSuchSubscriptionException e) {
finishOnUiThread(); finishOnUiThread();
@@ -170,7 +170,7 @@ OnClickListener, OnItemClickListener {
private void displayForumName() { private void displayForumName() {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
setTitle(group.getName()); setTitle(forum.getName());
} }
}); });
} }
@@ -313,7 +313,7 @@ OnClickListener, OnItemClickListener {
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof MessageAddedEvent) { if (e instanceof MessageAddedEvent) {
if (((MessageAddedEvent) e).getGroup().getId().equals(groupId)) { if (((MessageAddedEvent) e).getGroupId().equals(groupId)) {
LOG.info("Message added, reloading"); LOG.info("Message added, reloading");
loadHeaders(); loadHeaders();
} }
@@ -330,13 +330,13 @@ OnClickListener, OnItemClickListener {
if (view == composeButton) { if (view == composeButton) {
Intent i = new Intent(this, WriteForumPostActivity.class); Intent i = new Intent(this, WriteForumPostActivity.class);
i.putExtra("briar.GROUP_ID", groupId.getBytes()); i.putExtra("briar.GROUP_ID", groupId.getBytes());
i.putExtra("briar.FORUM_NAME", group.getName()); i.putExtra("briar.FORUM_NAME", forum.getName());
i.putExtra("briar.MIN_TIMESTAMP", getMinTimestampForNewMessage()); i.putExtra("briar.MIN_TIMESTAMP", getMinTimestampForNewMessage());
startActivity(i); startActivity(i);
} else if (view == shareButton) { } else if (view == shareButton) {
Intent i = new Intent(this, ShareForumActivity.class); Intent i = new Intent(this, ShareForumActivity.class);
i.putExtra("briar.GROUP_ID", groupId.getBytes()); i.putExtra("briar.GROUP_ID", groupId.getBytes());
i.putExtra("briar.FORUM_NAME", group.getName()); i.putExtra("briar.FORUM_NAME", forum.getName());
startActivity(i); startActivity(i);
} }
} }
@@ -361,7 +361,7 @@ OnClickListener, OnItemClickListener {
MessageHeader item = adapter.getItem(position).getHeader(); MessageHeader item = adapter.getItem(position).getHeader();
Intent i = new Intent(this, ReadForumPostActivity.class); Intent i = new Intent(this, ReadForumPostActivity.class);
i.putExtra("briar.GROUP_ID", groupId.getBytes()); i.putExtra("briar.GROUP_ID", groupId.getBytes());
i.putExtra("briar.FORUM_NAME", group.getName()); i.putExtra("briar.FORUM_NAME", forum.getName());
i.putExtra("briar.MESSAGE_ID", item.getId().getBytes()); i.putExtra("briar.MESSAGE_ID", item.getId().getBytes());
Author author = item.getAuthor(); Author author = item.getAuthor();
if (author != null) i.putExtra("briar.AUTHOR_NAME", author.getName()); if (author != null) i.putExtra("briar.AUTHOR_NAME", author.getName());

View File

@@ -1,22 +1,22 @@
package org.briarproject.android.forum; package org.briarproject.android.forum;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.sync.Group; import org.briarproject.api.forum.Forum;
import java.util.Collection; import java.util.Collection;
class ForumContacts { class ForumContacts {
private final Group group; private final Forum forum;
private final Collection<Contact> contacts; private final Collection<Contact> contacts;
ForumContacts(Group group, Collection<Contact> contacts) { ForumContacts(Forum forum, Collection<Contact> contacts) {
this.group = group; this.forum = forum;
this.contacts = contacts; this.contacts = contacts;
} }
Group getGroup() { Forum getForum() {
return group; return forum;
} }
Collection<Contact> getContacts() { Collection<Contact> getContacts() {

View File

@@ -32,6 +32,7 @@ import org.briarproject.api.event.MessageAddedEvent;
import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent; import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent;
import org.briarproject.api.event.SubscriptionAddedEvent; import org.briarproject.api.event.SubscriptionAddedEvent;
import org.briarproject.api.event.SubscriptionRemovedEvent; import org.briarproject.api.event.SubscriptionRemovedEvent;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
@@ -153,16 +154,16 @@ OnCreateContextMenuListener {
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
for (Group g : forumManager.getGroups()) { for (Forum f : forumManager.getForums()) {
try { try {
Collection<MessageHeader> headers = Collection<MessageHeader> headers =
forumManager.getMessageHeaders(g.getId()); forumManager.getMessageHeaders(f.getId());
displayHeaders(g, headers); displayHeaders(f, headers);
} catch (NoSuchSubscriptionException e) { } catch (NoSuchSubscriptionException e) {
// Continue // Continue
} }
} }
int available = forumManager.getAvailableGroups().size(); int available = forumManager.getAvailableForums().size();
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Full load took " + duration + " ms"); LOG.info("Full load took " + duration + " ms");
@@ -189,11 +190,11 @@ OnCreateContextMenuListener {
}); });
} }
private void displayHeaders(final Group g, private void displayHeaders(final Forum f,
final Collection<MessageHeader> headers) { final Collection<MessageHeader> headers) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
GroupId id = g.getId(); GroupId id = f.getId();
groupIds.put(id, id); groupIds.put(id, id);
list.setVisibility(VISIBLE); list.setVisibility(VISIBLE);
loading.setVisibility(GONE); loading.setVisibility(GONE);
@@ -201,7 +202,7 @@ OnCreateContextMenuListener {
ForumListItem item = findForum(id); ForumListItem item = findForum(id);
if (item != null) adapter.remove(item); if (item != null) adapter.remove(item);
// Add a new item // Add a new item
adapter.add(new ForumListItem(g, headers)); adapter.add(new ForumListItem(f, headers));
adapter.sort(ForumListItemComparator.INSTANCE); adapter.sort(ForumListItemComparator.INSTANCE);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
selectFirstUnread(); selectFirstUnread();
@@ -230,7 +231,7 @@ OnCreateContextMenuListener {
int count = adapter.getCount(); int count = adapter.getCount();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
ForumListItem item = adapter.getItem(i); ForumListItem item = adapter.getItem(i);
if (item.getGroup().getId().equals(g)) return item; if (item.getForum().getId().equals(g)) return item;
} }
return null; // Not found return null; // Not found
} }
@@ -255,8 +256,8 @@ OnCreateContextMenuListener {
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof MessageAddedEvent) { if (e instanceof MessageAddedEvent) {
Group g = ((MessageAddedEvent) e).getGroup(); GroupId g = ((MessageAddedEvent) e).getGroupId();
if (groupIds.containsKey(g.getId())) { if (groupIds.containsKey(g)) {
LOG.info("Message added, reloading"); LOG.info("Message added, reloading");
loadHeaders(g); loadHeaders(g);
} }
@@ -275,19 +276,20 @@ OnCreateContextMenuListener {
} }
} }
private void loadHeaders(final Group g) { private void loadHeaders(final GroupId g) {
runOnDbThread(new Runnable() { runOnDbThread(new Runnable() {
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
Forum f = forumManager.getForum(g);
Collection<MessageHeader> headers = Collection<MessageHeader> headers =
forumManager.getMessageHeaders(g.getId()); forumManager.getMessageHeaders(g);
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(f, headers);
} catch (NoSuchSubscriptionException e) { } catch (NoSuchSubscriptionException e) {
removeForum(g.getId()); removeForum(g);
} 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);
@@ -320,7 +322,7 @@ OnCreateContextMenuListener {
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
int available = forumManager.getAvailableGroups().size(); int available = forumManager.getAvailableForums().size();
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Loading available took " + duration + " ms"); LOG.info("Loading available took " + duration + " ms");
@@ -344,9 +346,9 @@ OnCreateContextMenuListener {
public void onItemClick(AdapterView<?> parent, View view, int position, public void onItemClick(AdapterView<?> parent, View view, int position,
long id) { long id) {
Intent i = new Intent(this, ForumActivity.class); Intent i = new Intent(this, ForumActivity.class);
Group g = adapter.getItem(position).getGroup(); Forum f = adapter.getItem(position).getForum();
i.putExtra("briar.GROUP_ID", g.getId().getBytes()); i.putExtra("briar.GROUP_ID", f.getId().getBytes());
i.putExtra("briar.FORUM_NAME", g.getName()); i.putExtra("briar.FORUM_NAME", f.getName());
startActivity(i); startActivity(i);
} }
@@ -363,19 +365,19 @@ OnCreateContextMenuListener {
ContextMenuInfo info = menuItem.getMenuInfo(); ContextMenuInfo info = menuItem.getMenuInfo();
int position = ((AdapterContextMenuInfo) info).position; int position = ((AdapterContextMenuInfo) info).position;
ForumListItem item = adapter.getItem(position); ForumListItem item = adapter.getItem(position);
removeSubscription(item.getGroup()); removeSubscription(item.getForum());
String unsubscribed = getString(R.string.unsubscribed_toast); String unsubscribed = getString(R.string.unsubscribed_toast);
Toast.makeText(this, unsubscribed, LENGTH_SHORT).show(); Toast.makeText(this, unsubscribed, LENGTH_SHORT).show();
} }
return true; return true;
} }
private void removeSubscription(final Group g) { private void removeSubscription(final Forum f) {
runOnDbThread(new Runnable() { runOnDbThread(new Runnable() {
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
forumManager.removeGroup(g); forumManager.removeForum(f);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Removing group took " + duration + " ms"); LOG.info("Removing group took " + duration + " ms");

View File

@@ -46,7 +46,7 @@ class ForumListAdapter extends ArrayAdapter<ForumListItem> {
name.setSingleLine(); name.setSingleLine();
name.setEllipsize(END); name.setEllipsize(END);
name.setPadding(pad, pad, pad, pad); name.setPadding(pad, pad, pad, pad);
String forumName = item.getGroup().getName(); String forumName = item.getForum().getName();
if (unread > 0) name.setText(forumName + " (" + unread + ")"); if (unread > 0) name.setText(forumName + " (" + unread + ")");
else name.setText(forumName); else name.setText(forumName);
layout.addView(name); layout.addView(name);

View File

@@ -1,19 +1,19 @@
package org.briarproject.android.forum; package org.briarproject.android.forum;
import org.briarproject.api.sync.Group; import org.briarproject.api.forum.Forum;
import org.briarproject.api.sync.MessageHeader; import org.briarproject.api.sync.MessageHeader;
import java.util.Collection; import java.util.Collection;
class ForumListItem { class ForumListItem {
private final Group group; private final Forum forum;
private final boolean empty; private final boolean empty;
private final long timestamp; private final long timestamp;
private final int unread; private final int unread;
ForumListItem(Group group, Collection<MessageHeader> headers) { ForumListItem(Forum forum, Collection<MessageHeader> headers) {
this.group = group; this.forum = forum;
empty = headers.isEmpty(); empty = headers.isEmpty();
if (empty) { if (empty) {
timestamp = 0; timestamp = 0;
@@ -34,8 +34,8 @@ class ForumListItem {
} }
} }
Group getGroup() { Forum getForum() {
return group; return forum;
} }
boolean isEmpty() { boolean isEmpty() {

View File

@@ -9,13 +9,13 @@ class ForumListItemComparator implements Comparator<ForumListItem> {
public int compare(ForumListItem a, ForumListItem b) { public int compare(ForumListItem a, ForumListItem b) {
if (a == b) return 0; if (a == b) return 0;
// The item with the newest message comes first // The forum with the newest message comes first
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;
// Break ties by group name // Break ties by forum name
String aName = a.getGroup().getName(); String aName = a.getForum().getName();
String bName = b.getGroup().getName(); String bName = b.getForum().getName();
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName); return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
} }
} }

View File

@@ -28,14 +28,14 @@ import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.KeyParser; import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
@@ -79,11 +79,11 @@ implements OnItemSelectedListener, OnClickListener {
@Inject private volatile IdentityManager identityManager; @Inject private volatile IdentityManager identityManager;
@Inject private volatile ForumManager forumManager; @Inject private volatile ForumManager forumManager;
@Inject private volatile CryptoComponent crypto; @Inject private volatile CryptoComponent crypto;
@Inject private volatile MessageFactory messageFactory; @Inject private volatile ForumPostFactory forumPostFactory;
private volatile MessageId parentId = null; private volatile MessageId parentId = null;
private volatile long minTimestamp = -1; private volatile long minTimestamp = -1;
private volatile LocalAuthor localAuthor = null; private volatile LocalAuthor localAuthor = null;
private volatile Group group = null; private volatile Forum forum = null;
@Override @Override
public void onCreate(Bundle state) { public void onCreate(Bundle state) {
@@ -138,7 +138,7 @@ implements OnItemSelectedListener, OnClickListener {
sendButton.setId(3); sendButton.setId(3);
sendButton.setBackgroundResource(0); sendButton.setBackgroundResource(0);
sendButton.setImageResource(R.drawable.social_send_now); sendButton.setImageResource(R.drawable.social_send_now);
sendButton.setEnabled(false); // Enabled after loading the group sendButton.setEnabled(false); // Enabled after loading the forum
sendButton.setOnClickListener(this); sendButton.setOnClickListener(this);
RelativeLayout.LayoutParams right = CommonLayoutParams.relative(); RelativeLayout.LayoutParams right = CommonLayoutParams.relative();
right.addRule(ALIGN_PARENT_RIGHT); right.addRule(ALIGN_PARENT_RIGHT);
@@ -170,7 +170,7 @@ implements OnItemSelectedListener, OnClickListener {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
Collection<LocalAuthor> localAuthors = Collection<LocalAuthor> localAuthors =
identityManager.getLocalAuthors(); identityManager.getLocalAuthors();
group = forumManager.getGroup(groupId); forum = forumManager.getForum(groupId);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Load took " + duration + " ms"); LOG.info("Load took " + duration + " ms");
@@ -204,7 +204,7 @@ implements OnItemSelectedListener, OnClickListener {
break; break;
} }
} }
setTitle(group.getName()); setTitle(forum.getName());
sendButton.setEnabled(true); sendButton.setEnabled(true);
} }
}); });
@@ -253,7 +253,7 @@ implements OnItemSelectedListener, OnClickListener {
} }
public void onClick(View view) { public void onClick(View view) {
if (group == null) throw new IllegalStateException(); if (forum == null) throw new IllegalStateException();
String message = content.getText().toString(); String message = content.getText().toString();
if (message.equals("")) return; if (message.equals("")) return;
createMessage(StringUtils.toUtf8(message)); createMessage(StringUtils.toUtf8(message));
@@ -270,14 +270,14 @@ implements OnItemSelectedListener, OnClickListener {
Message m; Message m;
try { try {
if (localAuthor == null) { if (localAuthor == null) {
m = messageFactory.createAnonymousMessage(parentId, m = forumPostFactory.createAnonymousPost(parentId,
group, "text/plain", timestamp, body); forum, "text/plain", timestamp, body);
} else { } else {
KeyParser keyParser = crypto.getSignatureKeyParser(); KeyParser keyParser = crypto.getSignatureKeyParser();
byte[] b = localAuthor.getPrivateKey(); byte[] b = localAuthor.getPrivateKey();
PrivateKey authorKey = keyParser.parsePrivateKey(b); PrivateKey authorKey = keyParser.parsePrivateKey(b);
m = messageFactory.createPseudonymousMessage(parentId, m = forumPostFactory.createPseudonymousPost(parentId,
group, localAuthor, authorKey, "text/plain", forum, localAuthor, authorKey, "text/plain",
timestamp, body); timestamp, body);
} }
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {

View File

@@ -1,22 +1,22 @@
package org.briarproject.api.event; package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.GroupId;
/** An event that is broadcast when a message is added to the database. */ /** An event that is broadcast when a message is added to the database. */
public class MessageAddedEvent extends Event { public class MessageAddedEvent extends Event {
private final Group group; private final GroupId groupId;
private final ContactId contactId; private final ContactId contactId;
public MessageAddedEvent(Group group, ContactId contactId) { public MessageAddedEvent(GroupId groupId, ContactId contactId) {
this.group = group; this.groupId = groupId;
this.contactId = contactId; this.contactId = contactId;
} }
/** Returns the group to which the message belongs. */ /** Returns the ID of the group to which the message belongs. */
public Group getGroup() { public GroupId getGroupId() {
return group; return groupId;
} }
/** /**

View File

@@ -0,0 +1,10 @@
package org.briarproject.api.forum;
import org.briarproject.api.sync.GroupId;
public interface Forum {
GroupId getId();
String getName();
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.api.forum;
public interface ForumFactory {
/** Creates a forum with the given name and a random salt. */
Forum createForum(String name);
}

View File

@@ -3,7 +3,6 @@ package org.briarproject.api.forum;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageHeader; import org.briarproject.api.sync.MessageHeader;
@@ -14,56 +13,54 @@ import java.util.Collection;
public interface ForumManager { public interface ForumManager {
/** /**
* Subscribes to a group, or returns false if the user already has the * Subscribes to a forum, or returns false if the user already has the
* maximum number of public subscriptions. * maximum number of forum subscriptions.
*/ */
boolean addGroup(Group g) throws DbException; boolean addForum(Forum f) throws DbException;
/** Stores a local message. */ /** Stores a local message. */
void addLocalMessage(Message m) throws DbException; void addLocalMessage(Message m) throws DbException;
/** Returns all groups to which the user could subscribe. */ /** Returns all forums to which the user could subscribe. */
Collection<Group> getAvailableGroups() throws DbException; Collection<Forum> getAvailableForums() throws DbException;
/** Returns the group with the given ID, if the user subscribes to it. */ /** Returns the forum with the given ID, if the user subscribes to it. */
Group getGroup(GroupId g) throws DbException; Forum getForum(GroupId g) throws DbException;
/** Returns all groups to which the user subscribes, excluding inboxes. */ /** Returns all forums to which the user subscribes. */
Collection<Group> getGroups() throws DbException; Collection<Forum> getForums() throws DbException;
/** Returns the body of the message with the given ID. */ /** Returns the body of the message with the given ID. */
byte[] getMessageBody(MessageId m) throws DbException; byte[] getMessageBody(MessageId m) throws DbException;
/** Returns the headers of all messages in the given group. */ /** Returns the headers of all messages in the given forum. */
Collection<MessageHeader> getMessageHeaders(GroupId g) Collection<MessageHeader> getMessageHeaders(GroupId g)
throws DbException; throws DbException;
/** Returns all contacts who subscribe to the given group. */ /** Returns all contacts who subscribe to the given forum. */
Collection<Contact> getSubscribers(GroupId g) throws DbException; Collection<Contact> getSubscribers(GroupId g) throws DbException;
/** Returns the IDs of all contacts to which the given group is visible. */ /** Returns the IDs of all contacts to which the given forum is visible. */
Collection<ContactId> getVisibility(GroupId g) throws DbException; Collection<ContactId> getVisibility(GroupId g) throws DbException;
/** /**
* Unsubscribes from a group. Any messages belonging to the group * Unsubscribes from a forum. Any messages belonging to the forum are
* are deleted. * deleted.
*/ */
void removeGroup(Group g) throws DbException; void removeForum(Forum f) throws DbException;
/** /** Marks a message as read or unread. */
* Marks a message as read or unread.
*/
void setReadFlag(MessageId m, boolean read) throws DbException; void setReadFlag(MessageId m, boolean read) throws DbException;
/** /**
* Makes a group visible to the given set of contacts and invisible to any * Makes a forum visible to the given set of contacts and invisible to any
* other current or future contacts. * other current or future contacts.
*/ */
void setVisibility(GroupId g, Collection<ContactId> visible) void setVisibility(GroupId g, Collection<ContactId> visible)
throws DbException; throws DbException;
/** /**
* Makes a group visible to all current and future contacts, or invisible * Makes a forum visible to all current and future contacts, or invisible
* to future contacts. * to future contacts.
*/ */
void setVisibleToAll(GroupId g, boolean all) throws DbException; void setVisibleToAll(GroupId g, boolean all) throws DbException;

View File

@@ -0,0 +1,21 @@
package org.briarproject.api.forum;
import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.identity.Author;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import java.io.IOException;
import java.security.GeneralSecurityException;
public interface ForumPostFactory {
Message createAnonymousPost(MessageId parent, Forum forum,
String contentType, long timestamp, byte[] body) throws IOException,
GeneralSecurityException;
Message createPseudonymousPost(MessageId parent, Forum forum,
Author author, PrivateKey privateKey, String contentType,
long timestamp, byte[] body) throws IOException,
GeneralSecurityException;
}

View File

@@ -222,8 +222,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} finally { } finally {
lock.writeLock().unlock(); lock.writeLock().unlock();
} }
if (!duplicate && subscribed) if (!duplicate && subscribed) {
eventBus.broadcast(new MessageAddedEvent(m.getGroup(), null)); GroupId g = m.getGroup().getId();
eventBus.broadcast(new MessageAddedEvent(g, null));
}
} }
/** /**
@@ -1050,8 +1052,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
lock.writeLock().unlock(); lock.writeLock().unlock();
} }
if (visible) { if (visible) {
if (!duplicate) if (!duplicate) {
eventBus.broadcast(new MessageAddedEvent(m.getGroup(), c)); GroupId g = m.getGroup().getId();
eventBus.broadcast(new MessageAddedEvent(g, c));
}
eventBus.broadcast(new MessageToAckEvent(c)); eventBus.broadcast(new MessageToAckEvent(c));
} }
} }

View File

@@ -0,0 +1,22 @@
package org.briarproject.forum;
import com.google.inject.Inject;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumFactory;
import org.briarproject.api.sync.GroupFactory;
// Temporary facade during sync protocol refactoring
class ForumFactoryImpl implements ForumFactory {
private final GroupFactory groupFactory;
@Inject
ForumFactoryImpl(GroupFactory groupFactory) {
this.groupFactory = groupFactory;
}
public Forum createForum(String name) {
return new ForumImpl(groupFactory.createGroup(name));
}
}

View File

@@ -0,0 +1,37 @@
package org.briarproject.forum;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId;
// Temporary facade during sync protocol refactoring
class ForumImpl implements Forum {
private final Group group;
ForumImpl(Group group) {
this.group = group;
}
public GroupId getId() {
return group.getId();
}
public String getName() {
return group.getName();
}
Group getGroup() {
return group;
}
@Override
public int hashCode() {
return group.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof ForumImpl && group.equals(((ForumImpl) o).group);
}
}

View File

@@ -6,6 +6,7 @@ import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
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.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
@@ -13,8 +14,12 @@ import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageHeader; import org.briarproject.api.sync.MessageHeader;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List;
// Temporary facade during sync protocol refactoring
class ForumManagerImpl implements ForumManager { class ForumManagerImpl implements ForumManager {
private final DatabaseComponent db; private final DatabaseComponent db;
@@ -25,8 +30,8 @@ class ForumManagerImpl implements ForumManager {
} }
@Override @Override
public boolean addGroup(Group g) throws DbException { public boolean addForum(Forum f) throws DbException {
return db.addGroup(g); return db.addGroup(((ForumImpl) f).getGroup());
} }
@Override @Override
@@ -35,18 +40,24 @@ class ForumManagerImpl implements ForumManager {
} }
@Override @Override
public Collection<Group> getAvailableGroups() throws DbException { public Collection<Forum> getAvailableForums() throws DbException {
return db.getAvailableGroups(); Collection<Group> groups = db.getAvailableGroups();
List<Forum> forums = new ArrayList<Forum>(groups.size());
for (Group g : groups) forums.add(new ForumImpl(g));
return Collections.unmodifiableList(forums);
} }
@Override @Override
public Group getGroup(GroupId g) throws DbException { public Forum getForum(GroupId g) throws DbException {
return db.getGroup(g); return new ForumImpl(db.getGroup(g));
} }
@Override @Override
public Collection<Group> getGroups() throws DbException { public Collection<Forum> getForums() throws DbException {
return db.getGroups(); Collection<Group> groups = db.getGroups();
List<Forum> forums = new ArrayList<Forum>(groups.size());
for (Group g : groups) forums.add(new ForumImpl(g));
return Collections.unmodifiableList(forums);
} }
@Override @Override
@@ -71,8 +82,8 @@ class ForumManagerImpl implements ForumManager {
} }
@Override @Override
public void removeGroup(Group g) throws DbException { public void removeForum(Forum f) throws DbException {
db.removeGroup(g); db.removeGroup(((ForumImpl) f).getGroup());
} }
@Override @Override

View File

@@ -2,12 +2,16 @@ package org.briarproject.forum;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import org.briarproject.api.forum.ForumFactory;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPostFactory;
public class ForumModule extends AbstractModule { public class ForumModule extends AbstractModule {
@Override @Override
protected void configure() { protected void configure() {
bind(ForumFactory.class).to(ForumFactoryImpl.class);
bind(ForumManager.class).to(ForumManagerImpl.class); bind(ForumManager.class).to(ForumManagerImpl.class);
bind(ForumPostFactory.class).to(ForumPostFactoryImpl.class);
} }
} }

View File

@@ -0,0 +1,43 @@
package org.briarproject.forum;
import com.google.inject.Inject;
import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.identity.Author;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory;
import org.briarproject.api.sync.MessageId;
import java.io.IOException;
import java.security.GeneralSecurityException;
// Temporary facade during sync protocol refactoring
class ForumPostFactoryImpl implements ForumPostFactory {
private final MessageFactory messageFactory;
@Inject
ForumPostFactoryImpl(MessageFactory messageFactory) {
this.messageFactory = messageFactory;
}
@Override
public Message createAnonymousPost(MessageId parent, Forum forum,
String contentType, long timestamp, byte[] body)
throws IOException, GeneralSecurityException {
return messageFactory.createAnonymousMessage(parent,
((ForumImpl) forum).getGroup(), contentType, timestamp, body);
}
@Override
public Message createPseudonymousPost(MessageId parent, Forum forum,
Author author, PrivateKey privateKey, String contentType,
long timestamp, byte[] body)
throws IOException, GeneralSecurityException {
return messageFactory.createPseudonymousMessage(parent,
((ForumImpl) forum).getGroup(), author, privateKey, contentType,
timestamp, body);
}
}