Merge branch '1024-message-tree-npe' into 'master'

Don't add threaded messages to the UI before their parents

Closes #1024

See merge request !585
This commit is contained in:
akwizgran
2017-09-19 15:37:58 +00:00
20 changed files with 130 additions and 145 deletions

View File

@@ -28,7 +28,6 @@ import org.briarproject.briar.android.threaded.ThreadItemAdapter;
import org.briarproject.briar.android.threaded.ThreadListActivity; import org.briarproject.briar.android.threaded.ThreadListActivity;
import org.briarproject.briar.android.threaded.ThreadListController; import org.briarproject.briar.android.threaded.ThreadListController;
import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.Forum;
import org.briarproject.briar.api.forum.ForumPostHeader;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
@@ -41,7 +40,7 @@ import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_POST_BOD
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class ForumActivity extends public class ForumActivity extends
ThreadListActivity<Forum, ThreadItemAdapter<ForumItem>, ForumItem, ForumPostHeader> ThreadListActivity<Forum, ForumItem, ThreadItemAdapter<ForumItem>>
implements ForumListener { implements ForumListener {
@Inject @Inject
@@ -53,7 +52,7 @@ public class ForumActivity extends
} }
@Override @Override
protected ThreadListController<Forum, ForumItem, ForumPostHeader> getController() { protected ThreadListController<Forum, ForumItem> getController() {
return forumController; return forumController;
} }

View File

@@ -6,13 +6,11 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.android.threaded.ThreadListController; import org.briarproject.briar.android.threaded.ThreadListController;
import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.Forum;
import org.briarproject.briar.api.forum.ForumPostHeader;
@NotNullByDefault @NotNullByDefault
interface ForumController interface ForumController extends ThreadListController<Forum, ForumItem> {
extends ThreadListController<Forum, ForumItem, ForumPostHeader> {
interface ForumListener extends ThreadListListener<ForumPostHeader> { interface ForumListener extends ThreadListListener<ForumItem> {
@UiThread @UiThread
void onForumLeft(ContactId c); void onForumLeft(ContactId c);
} }

View File

@@ -75,10 +75,10 @@ class ForumControllerImpl extends
super.eventOccurred(e); super.eventOccurred(e);
if (e instanceof ForumPostReceivedEvent) { if (e instanceof ForumPostReceivedEvent) {
ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e; ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
if (pe.getGroupId().equals(getGroupId())) { if (f.getGroupId().equals(getGroupId())) {
LOG.info("Forum post received, adding..."); LOG.info("Forum post received, adding...");
onForumPostHeaderReceived(pe.getForumPostHeader()); onForumPostReceived(f.getHeader(), f.getBody());
} }
} else if (e instanceof ForumInvitationResponseReceivedEvent) { } else if (e instanceof ForumInvitationResponseReceivedEvent) {
ForumInvitationResponseReceivedEvent f = ForumInvitationResponseReceivedEvent f =
@@ -90,10 +90,10 @@ class ForumControllerImpl extends
onForumInvitationAccepted(r.getContactId()); onForumInvitationAccepted(r.getContactId());
} }
} else if (e instanceof ContactLeftShareableEvent) { } else if (e instanceof ContactLeftShareableEvent) {
ContactLeftShareableEvent s = (ContactLeftShareableEvent) e; ContactLeftShareableEvent c = (ContactLeftShareableEvent) e;
if (s.getGroupId().equals(getGroupId())) { if (c.getGroupId().equals(getGroupId())) {
LOG.info("Forum left by contact"); LOG.info("Forum left by contact");
onForumLeft(s.getContactId()); onForumLeft(c.getContactId());
} }
} }
} }
@@ -195,11 +195,12 @@ class ForumControllerImpl extends
return new ForumItem(header, body); return new ForumItem(header, body);
} }
private void onForumPostHeaderReceived(final ForumPostHeader h) { private void onForumPostReceived(ForumPostHeader h, String body) {
final ForumItem item = buildItem(h, body);
listener.runOnUiThreadUnlessDestroyed(new Runnable() { listener.runOnUiThreadUnlessDestroyed(new Runnable() {
@Override @Override
public void run() { public void run() {
listener.onHeaderReceived(h); listener.onItemReceived(item);
} }
}); });
} }

View File

@@ -254,7 +254,7 @@ public class ForumListFragment extends BaseEventFragment implements
} else if (e instanceof ForumPostReceivedEvent) { } else if (e instanceof ForumPostReceivedEvent) {
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e; ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
LOG.info("Forum post added, updating item"); LOG.info("Forum post added, updating item");
updateItem(f.getGroupId(), f.getForumPostHeader()); updateItem(f.getGroupId(), f.getHeader());
} else if (e instanceof ForumInvitationRequestReceivedEvent) { } else if (e instanceof ForumInvitationRequestReceivedEvent) {
LOG.info("Forum invitation received, reloading available forums"); LOG.info("Forum invitation received, reloading available forums");
loadAvailableForums(); loadAvailableForums();

View File

@@ -29,7 +29,6 @@ import org.briarproject.briar.android.privategroup.memberlist.GroupMemberListAct
import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity; import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity;
import org.briarproject.briar.android.threaded.ThreadListActivity; import org.briarproject.briar.android.threaded.ThreadListActivity;
import org.briarproject.briar.android.threaded.ThreadListController; import org.briarproject.briar.android.threaded.ThreadListController;
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.Visibility; import org.briarproject.briar.api.privategroup.Visibility;
@@ -44,7 +43,7 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class GroupActivity extends public class GroupActivity extends
ThreadListActivity<PrivateGroup, GroupMessageAdapter, GroupMessageItem, GroupMessageHeader> ThreadListActivity<PrivateGroup, GroupMessageItem, GroupMessageAdapter>
implements GroupListener, OnClickListener { implements GroupListener, OnClickListener {
@Inject @Inject
@@ -60,7 +59,7 @@ public class GroupActivity extends
} }
@Override @Override
protected ThreadListController<PrivateGroup, GroupMessageItem, GroupMessageHeader> getController() { protected ThreadListController<PrivateGroup, GroupMessageItem> getController() {
return controller; return controller;
} }
@@ -276,7 +275,7 @@ public class GroupActivity extends
public void onGroupDissolved() { public void onGroupDissolved() {
setGroupEnabled(false); setGroupEnabled(false);
AlertDialog.Builder builder = AlertDialog.Builder builder =
new AlertDialog.Builder(this, R.style.BriarDialogTheme); new AlertDialog.Builder(this, R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.groups_dissolved_dialog_title)); builder.setTitle(getString(R.string.groups_dissolved_dialog_title));
builder.setMessage(getString(R.string.groups_dissolved_dialog_message)); builder.setMessage(getString(R.string.groups_dissolved_dialog_message));
builder.setNeutralButton(R.string.ok, null); builder.setNeutralButton(R.string.ok, null);

View File

@@ -8,13 +8,11 @@ import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
import org.briarproject.briar.android.threaded.ThreadListController; import org.briarproject.briar.android.threaded.ThreadListController;
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.Visibility; import org.briarproject.briar.api.privategroup.Visibility;
public interface GroupController public interface GroupController
extends extends ThreadListController<PrivateGroup, GroupMessageItem> {
ThreadListController<PrivateGroup, GroupMessageItem, GroupMessageHeader> {
void loadLocalAuthor( void loadLocalAuthor(
ResultExceptionHandler<LocalAuthor, DbException> handler); ResultExceptionHandler<LocalAuthor, DbException> handler);
@@ -22,7 +20,8 @@ public interface GroupController
void isDissolved( void isDissolved(
ResultExceptionHandler<Boolean, DbException> handler); ResultExceptionHandler<Boolean, DbException> handler);
interface GroupListener extends ThreadListListener<GroupMessageHeader> { interface GroupListener extends ThreadListListener<GroupMessageItem> {
@UiThread @UiThread
void onContactRelationshipRevealed(AuthorId memberId, void onContactRelationshipRevealed(AuthorId memberId,
ContactId contactId, Visibility v); ContactId contactId, Visibility v);

View File

@@ -80,14 +80,15 @@ class GroupControllerImpl extends
super.eventOccurred(e); super.eventOccurred(e);
if (e instanceof GroupMessageAddedEvent) { if (e instanceof GroupMessageAddedEvent) {
GroupMessageAddedEvent gmae = (GroupMessageAddedEvent) e; GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
if (!gmae.isLocal() && gmae.getGroupId().equals(getGroupId())) { if (!g.isLocal() && g.getGroupId().equals(getGroupId())) {
LOG.info("Group message received, adding..."); LOG.info("Group message received, adding...");
final GroupMessageHeader h = gmae.getHeader(); final GroupMessageItem item =
buildItem(g.getHeader(), g.getBody());
listener.runOnUiThreadUnlessDestroyed(new Runnable() { listener.runOnUiThreadUnlessDestroyed(new Runnable() {
@Override @Override
public void run() { public void run() {
listener.onHeaderReceived(h); listener.onItemReceived(item);
} }
}); });
} }

View File

@@ -3,7 +3,9 @@ package org.briarproject.briar.android.threaded;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.MessageTree; import org.briarproject.briar.api.client.MessageTree;
import org.briarproject.briar.api.client.MessageTree.MessageNode;
import org.briarproject.briar.client.MessageTreeImpl; import org.briarproject.briar.client.MessageTreeImpl;
import java.util.ArrayList; import java.util.ArrayList;
@@ -13,8 +15,7 @@ import java.util.List;
@UiThread @UiThread
@NotNullByDefault @NotNullByDefault
public class NestedTreeList<T extends MessageTree.MessageNode> public class NestedTreeList<T extends MessageNode> implements Iterable<T> {
implements Iterable<T> {
private final MessageTree<T> tree = new MessageTreeImpl<>(); private final MessageTree<T> tree = new MessageTreeImpl<>();
private List<T> depthFirstCollection = new ArrayList<>(); private List<T> depthFirstCollection = new ArrayList<>();
@@ -38,14 +39,14 @@ public class NestedTreeList<T extends MessageTree.MessageNode>
return depthFirstCollection.get(index); return depthFirstCollection.get(index);
} }
public int indexOf(T elem) {
return depthFirstCollection.indexOf(elem);
}
public int size() { public int size() {
return depthFirstCollection.size(); return depthFirstCollection.size();
} }
public boolean contains(MessageId m) {
return tree.contains(m);
}
@Override @Override
public Iterator<T> iterator() { public Iterator<T> iterator() {
return depthFirstCollection.iterator(); return depthFirstCollection.iterator();

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.android.threaded; package org.briarproject.briar.android.threaded;
import android.os.Handler;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
@@ -28,7 +27,6 @@ public class ThreadItemAdapter<I extends ThreadItem>
protected final NestedTreeList<I> items = new NestedTreeList<>(); protected final NestedTreeList<I> items = new NestedTreeList<>();
private final ThreadItemListener<I> listener; private final ThreadItemListener<I> listener;
private final LinearLayoutManager layoutManager; private final LinearLayoutManager layoutManager;
private final Handler handler = new Handler();
private volatile int revision = 0; private volatile int revision = 0;
@@ -104,6 +102,10 @@ public class ThreadItemAdapter<I extends ThreadItem>
return NO_POSITION; // Not found return NO_POSITION; // Not found
} }
boolean contains(MessageId m) {
return items.contains(m);
}
/** /**
* Highlights the item with the given {@link MessageId} * Highlights the item with the given {@link MessageId}
* and disables the highlight for a previously highlighted item, if any. * and disables the highlight for a previously highlighted item, if any.
@@ -184,6 +186,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
} }
static class UnreadCount { static class UnreadCount {
final int top, bottom; final int top, bottom;
private UnreadCount(int top, int bottom) { private UnreadCount(int top, int bottom) {
@@ -193,6 +196,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
} }
public interface ThreadItemListener<I> { public interface ThreadItemListener<I> {
void onUnreadItemVisible(I item); void onUnreadItemVisible(I item);
void onReplyClick(I item); void onReplyClick(I item);

View File

@@ -16,6 +16,7 @@ public class ThreadItemListImpl<I extends ThreadItem> extends ArrayList<I>
return bottomVisibleItemId; return bottomVisibleItemId;
} }
@Override
public void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId) { public void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId) {
this.bottomVisibleItemId = bottomVisibleItemId; this.bottomVisibleItemId = bottomVisibleItemId;
} }

View File

@@ -32,7 +32,6 @@ import org.briarproject.briar.android.view.TextInputView;
import org.briarproject.briar.android.view.TextInputView.TextInputListener; import org.briarproject.briar.android.view.TextInputView.TextInputListener;
import org.briarproject.briar.android.view.UnreadMessageButton; import org.briarproject.briar.android.view.UnreadMessageButton;
import org.briarproject.briar.api.client.NamedGroup; import org.briarproject.briar.api.client.NamedGroup;
import org.briarproject.briar.api.client.PostHeader;
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout; import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
import java.util.Collection; import java.util.Collection;
@@ -49,9 +48,9 @@ import static org.briarproject.briar.android.threaded.ThreadItemAdapter.UnreadCo
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader> public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadItem, A extends ThreadItemAdapter<I>>
extends BriarActivity extends BriarActivity
implements ThreadListListener<H>, TextInputListener, SharingListener, implements ThreadListListener<I>, TextInputListener, SharingListener,
ThreadItemListener<I>, ThreadListDataSource { ThreadItemListener<I>, ThreadListDataSource {
protected static final String KEY_REPLY_ID = "replyId"; protected static final String KEY_REPLY_ID = "replyId";
@@ -68,7 +67,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
@Nullable @Nullable
private MessageId replyId; private MessageId replyId;
protected abstract ThreadListController<G, I, H> getController(); protected abstract ThreadListController<G, I> getController();
@Inject @Inject
protected SharingController sharingController; protected SharingController sharingController;
@@ -190,7 +189,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
if (items.isEmpty()) { if (items.isEmpty()) {
list.showData(); list.showData();
} else { } else {
initList(items); displayItems(items);
updateTextInput(); updateTextInput();
} }
} else { } else {
@@ -206,7 +205,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
}); });
} }
private void initList(final ThreadItemList<I> items) { private void displayItems(final ThreadItemList<I> items) {
adapter.setItems(items); adapter.setItems(items);
MessageId messageId = items.getFirstVisibleItemId(); MessageId messageId = items.getFirstVisibleItemId();
if (messageId != null) if (messageId != null)
@@ -383,19 +382,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
protected abstract int getMaxBodyLength(); protected abstract int getMaxBodyLength();
@Override @Override
public void onHeaderReceived(H header) { public void onItemReceived(I item) {
getController().loadItem(header, addItem(item, false);
new UiResultExceptionHandler<I, DbException>(this) {
@Override
public void onResultUi(final I result) {
addItem(result, false);
}
@Override
public void onExceptionUi(DbException exception) {
handleDbException(exception);
}
});
} }
@Override @Override
@@ -403,8 +391,15 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
supportFinishAfterTransition(); supportFinishAfterTransition();
} }
protected void addItem(I item, boolean isLocal) { private void addItem(I item, boolean isLocal) {
adapter.incrementRevision(); adapter.incrementRevision();
MessageId parent = item.getParentId();
if (parent != null && !adapter.contains(parent)) {
// We've incremented the adapter's revision, so the item will be
// loaded when its parent has been loaded
LOG.info("Ignoring item with missing parent");
return;
}
adapter.add(item); adapter.add(item);
if (isLocal) { if (isLocal) {

View File

@@ -12,14 +12,13 @@ import org.briarproject.briar.android.controller.ActivityLifecycleController;
import org.briarproject.briar.android.controller.handler.ExceptionHandler; import org.briarproject.briar.android.controller.handler.ExceptionHandler;
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
import org.briarproject.briar.api.client.NamedGroup; import org.briarproject.briar.api.client.NamedGroup;
import org.briarproject.briar.api.client.PostHeader;
import java.util.Collection; import java.util.Collection;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@NotNullByDefault @NotNullByDefault
public interface ThreadListController<G extends NamedGroup, I extends ThreadItem, H extends PostHeader> public interface ThreadListController<G extends NamedGroup, I extends ThreadItem>
extends ActivityLifecycleController { extends ActivityLifecycleController {
void setGroupId(GroupId groupId); void setGroupId(GroupId groupId);
@@ -29,9 +28,8 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
void loadSharingContacts( void loadSharingContacts(
ResultExceptionHandler<Collection<ContactId>, DbException> handler); ResultExceptionHandler<Collection<ContactId>, DbException> handler);
void loadItem(H header, ResultExceptionHandler<I, DbException> handler); void loadItems(
ResultExceptionHandler<ThreadItemList<I>, DbException> handler);
void loadItems(ResultExceptionHandler<ThreadItemList<I>, DbException> handler);
void markItemRead(I item); void markItemRead(I item);
@@ -42,9 +40,10 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
void deleteNamedGroup(ExceptionHandler<DbException> handler); void deleteNamedGroup(ExceptionHandler<DbException> handler);
interface ThreadListListener<H> extends ThreadListDataSource { interface ThreadListListener<I> extends ThreadListDataSource {
@UiThread @UiThread
void onHeaderReceived(H header); void onItemReceived(I item);
@UiThread @UiThread
void onGroupRemoved(); void onGroupRemoved();

View File

@@ -39,9 +39,9 @@ import static java.util.logging.Level.WARNING;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends ThreadItem, H extends PostHeader, M extends ThreadedMessage, L extends ThreadListListener<H>> public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends ThreadItem, H extends PostHeader, M extends ThreadedMessage, L extends ThreadListListener<I>>
extends DbControllerImpl extends DbControllerImpl
implements ThreadListController<G, I, H>, EventListener { implements ThreadListController<G, I>, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ThreadListControllerImpl.class.getName()); Logger.getLogger(ThreadListControllerImpl.class.getName());
@@ -203,35 +203,6 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
@DatabaseExecutor @DatabaseExecutor
protected abstract String loadMessageBody(H header) throws DbException; protected abstract String loadMessageBody(H header) throws DbException;
@Override
public void loadItem(final H header,
final ResultExceptionHandler<I, DbException> handler) {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
long now = System.currentTimeMillis();
String body;
if (!bodyCache.containsKey(header.getId())) {
body = loadMessageBody(header);
bodyCache.put(header.getId(), body);
} else {
body = bodyCache.get(header.getId());
}
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading item took " + duration + " ms");
I item = buildItem(header, body);
handler.onResult(item);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
handler.onException(e);
}
}
});
}
@Override @Override
public void markItemRead(I item) { public void markItemRead(I item) {
markItemsRead(Collections.singletonList(item)); markItemsRead(Collections.singletonList(item));

View File

@@ -3,18 +3,18 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_group_member_list"
android:icon="@drawable/ic_group_white"
android:title="@string/groups_member_list"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/action_group_invite" android:id="@+id/action_group_invite"
android:icon="@drawable/social_share_white" android:icon="@drawable/social_share_white"
android:title="@string/groups_invite_members" android:title="@string/groups_invite_members"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_group_member_list"
android:icon="@drawable/ic_group_white"
android:title="@string/groups_member_list"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/action_group_reveal" android:id="@+id/action_group_reveal"
android:icon="@drawable/ic_visibility_white" android:icon="@drawable/ic_visibility_white"

View File

@@ -21,6 +21,8 @@ public interface MessageTree<T extends MessageTree.MessageNode> {
Collection<T> depthFirstOrder(); Collection<T> depthFirstOrder();
boolean contains(MessageId m);
@NotNullByDefault @NotNullByDefault
interface MessageNode { interface MessageNode {

View File

@@ -14,21 +14,26 @@ import javax.annotation.concurrent.Immutable;
@NotNullByDefault @NotNullByDefault
public class ForumPostReceivedEvent extends Event { public class ForumPostReceivedEvent extends Event {
private final ForumPostHeader forumPostHeader;
private final GroupId groupId; private final GroupId groupId;
private final ForumPostHeader header;
private final String body;
public ForumPostReceivedEvent(ForumPostHeader forumPostHeader, public ForumPostReceivedEvent(GroupId groupId, ForumPostHeader header,
GroupId groupId) { String body) {
this.forumPostHeader = forumPostHeader;
this.groupId = groupId; this.groupId = groupId;
} this.header = header;
this.body = body;
public ForumPostHeader getForumPostHeader() {
return forumPostHeader;
} }
public GroupId getGroupId() { public GroupId getGroupId() {
return groupId; return groupId;
} }
public ForumPostHeader getHeader() {
return header;
}
public String getBody() {
return body;
}
} }

View File

@@ -17,13 +17,14 @@ public class GroupMessageAddedEvent extends Event {
private final GroupId groupId; private final GroupId groupId;
private final GroupMessageHeader header; private final GroupMessageHeader header;
private final String body;
private final boolean local; private final boolean local;
public GroupMessageAddedEvent(GroupId groupId, GroupMessageHeader header, public GroupMessageAddedEvent(GroupId groupId, GroupMessageHeader header,
boolean local) { String body, boolean local) {
this.groupId = groupId; this.groupId = groupId;
this.header = header; this.header = header;
this.body = body;
this.local = local; this.local = local;
} }
@@ -35,6 +36,10 @@ public class GroupMessageAddedEvent extends Event {
return header; return header;
} }
public String getBody() {
return body;
}
public boolean isLocal() { public boolean isLocal() {
return local; return local;
} }

View File

@@ -107,4 +107,8 @@ public class MessageTreeImpl<T extends MessageTree.MessageNode>
return orderedList; return orderedList;
} }
@Override
public boolean contains(MessageId m) {
return nodeMap.containsKey(m);
}
} }

View File

@@ -45,7 +45,6 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.bramble.api.identity.Author.Status.ANONYMOUS;
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES; import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
import static org.briarproject.briar.api.forum.ForumConstants.KEY_AUTHOR; import static org.briarproject.briar.api.forum.ForumConstants.KEY_AUTHOR;
import static org.briarproject.briar.api.forum.ForumConstants.KEY_ID; import static org.briarproject.briar.api.forum.ForumConstants.KEY_ID;
@@ -85,9 +84,10 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
messageTracker.trackIncomingMessage(txn, m); messageTracker.trackIncomingMessage(txn, m);
ForumPostHeader post = getForumPostHeader(txn, m.getId(), meta); ForumPostHeader header = getForumPostHeader(txn, m.getId(), meta);
String postBody = getPostBody(body);
ForumPostReceivedEvent event = ForumPostReceivedEvent event =
new ForumPostReceivedEvent(post, m.getGroupId()); new ForumPostReceivedEvent(m.getGroupId(), header, postBody);
txn.attach(event); txn.attach(event);
// share message // share message
@@ -215,14 +215,19 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
public String getPostBody(MessageId m) throws DbException { public String getPostBody(MessageId m) throws DbException {
try { try {
// Parent ID, author, forum post body, signature // Parent ID, author, forum post body, signature
BdfList message = clientHelper.getMessageAsList(m); BdfList body = clientHelper.getMessageAsList(m);
if (message == null) throw new DbException(); if (body == null) throw new DbException();
return message.getString(2); return getPostBody(body);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
} }
private String getPostBody(BdfList body) throws FormatException {
// Parent ID, author, forum post body, signature
return body.getString(2);
}
@Override @Override
public Collection<ForumPostHeader> getPostHeaders(GroupId g) public Collection<ForumPostHeader> getPostHeaders(GroupId g)
throws DbException { throws DbException {
@@ -294,24 +299,17 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
throws DbException, FormatException { throws DbException, FormatException {
long timestamp = meta.getLong(KEY_TIMESTAMP); long timestamp = meta.getLong(KEY_TIMESTAMP);
Author author = null;
Status status = ANONYMOUS;
MessageId parentId = null; MessageId parentId = null;
if (meta.containsKey(KEY_PARENT)) if (meta.containsKey(KEY_PARENT))
parentId = new MessageId(meta.getRaw(KEY_PARENT)); parentId = new MessageId(meta.getRaw(KEY_PARENT));
// TODO: Remove support for anonymous forum posts BdfDictionary authorDict = meta.getDictionary(KEY_AUTHOR);
BdfDictionary d1 = meta.getDictionary(KEY_AUTHOR, null); AuthorId authorId = new AuthorId(authorDict.getRaw(KEY_ID));
if (d1 != null) { String name = authorDict.getString(KEY_NAME);
AuthorId authorId = new AuthorId(d1.getRaw(KEY_ID)); byte[] publicKey = authorDict.getRaw(KEY_PUBLIC_NAME);
String name = d1.getString(KEY_NAME); Author author = new Author(authorId, name, publicKey);
byte[] publicKey = d1.getRaw(KEY_PUBLIC_NAME); Status status = statuses.get(authorId);
author = new Author(authorId, name, publicKey); if (status == null)
if (statuses.containsKey(authorId)) { status = identityManager.getAuthorStatus(txn, author.getId());
status = statuses.get(authorId);
} else {
status = identityManager.getAuthorStatus(txn, author.getId());
}
}
boolean read = meta.getBoolean(MSG_KEY_READ); boolean read = meta.getBoolean(MSG_KEY_READ);
return new ForumPostHeader(id, parentId, timestamp, author, status, return new ForumPostHeader(id, parentId, timestamp, author, status,

View File

@@ -307,16 +307,20 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
@Override @Override
public String getMessageBody(MessageId m) throws DbException { public String getMessageBody(MessageId m) throws DbException {
try { try {
// type(0), member_name(1), member_public_key(2), parent_id(3),
// previous_message_id(4), content(5), signature(6)
BdfList body = clientHelper.getMessageAsList(m); BdfList body = clientHelper.getMessageAsList(m);
if (body == null) throw new DbException(); if (body == null) throw new DbException();
return body.getString(5); return getMessageBody(body);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
} }
private String getMessageBody(BdfList body) throws FormatException {
// type(0), member_name(1), member_public_key(2), parent_id(3),
// previous_message_id(4), content(5), signature(6)
return body.getString(5);
}
@Override @Override
public Collection<GroupMessageHeader> getHeaders(GroupId g) public Collection<GroupMessageHeader> getHeaders(GroupId g)
throws DbException { throws DbException {
@@ -579,21 +583,20 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
private void attachGroupMessageAddedEvent(Transaction txn, Message m, private void attachGroupMessageAddedEvent(Transaction txn, Message m,
BdfDictionary meta, boolean local) BdfDictionary meta, boolean local)
throws DbException, FormatException { throws DbException, FormatException {
GroupMessageHeader h = GroupMessageHeader header = getGroupMessageHeader(txn, m.getGroupId(),
getGroupMessageHeader(txn, m.getGroupId(), m.getId(), meta, m.getId(), meta, Collections.<AuthorId, Status>emptyMap());
Collections.<AuthorId, Status>emptyMap()); String body = getMessageBody(clientHelper.toList(m));
Event e = new GroupMessageAddedEvent(m.getGroupId(), h, local); txn.attach(new GroupMessageAddedEvent(m.getGroupId(), header, body,
txn.attach(e); local));
} }
private void attachJoinMessageAddedEvent(Transaction txn, Message m, private void attachJoinMessageAddedEvent(Transaction txn, Message m,
BdfDictionary meta, boolean local, Visibility v) BdfDictionary meta, boolean local, Visibility v)
throws DbException, FormatException { throws DbException, FormatException {
JoinMessageHeader h = JoinMessageHeader header = getJoinMessageHeader(txn, m.getGroupId(),
getJoinMessageHeader(txn, m.getGroupId(), m.getId(), meta, m.getId(), meta, Collections.<AuthorId, Status>emptyMap(), v);
Collections.<AuthorId, Status>emptyMap(), v); txn.attach(new GroupMessageAddedEvent(m.getGroupId(), header, "",
Event e = new GroupMessageAddedEvent(m.getGroupId(), h, local); local));
txn.attach(e);
} }
private void addMember(Transaction txn, GroupId g, Author a, Visibility v) private void addMember(Transaction txn, GroupId g, Author a, Visibility v)