Introduce client layer events for forums

The forum UI depended on sync layer events such as MessageStateChangedEvent.
Now, the forum client broadcasts its own high-level event (`ForumPostReceivedEvent`)
with the information the UI needs (`ForumPostHeader`).

Closes #310
This commit is contained in:
Torsten Grote
2016-07-08 16:12:52 -03:00
parent 9ff4758683
commit e1bdede4f5
12 changed files with 229 additions and 149 deletions

View File

@@ -21,18 +21,17 @@ import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.ForumInvitationReceivedEvent;
import org.briarproject.api.event.ForumPostReceivedEvent;
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.event.IntroductionSucceededEvent;
import org.briarproject.api.event.MessageStateChangedEvent;
import org.briarproject.api.event.PrivateMessageReceivedEvent;
import org.briarproject.api.event.SettingsUpdatedEvent;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.lifecycle.ServiceException;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.settings.SettingsManager;
import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.util.StringUtils;
@@ -59,7 +58,6 @@ import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
import static java.util.logging.Level.WARNING;
import static org.briarproject.android.BriarActivity.GROUP_ID;
import static org.briarproject.android.fragment.SettingsFragment.SETTINGS_NAMESPACE;
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
class AndroidNotificationManagerImpl implements AndroidNotificationManager,
Service, EventListener {
@@ -78,7 +76,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
private final Executor dbExecutor;
private final SettingsManager settingsManager;
private final MessagingManager messagingManager;
private final ForumManager forumManager;
private final AndroidExecutor androidExecutor;
private final Context appContext;
@@ -94,14 +91,12 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
private volatile Settings settings = new Settings();
@Inject
public AndroidNotificationManagerImpl(@DatabaseExecutor Executor dbExecutor,
AndroidNotificationManagerImpl(@DatabaseExecutor Executor dbExecutor,
SettingsManager settingsManager, MessagingManager messagingManager,
ForumManager forumManager, AndroidExecutor androidExecutor,
Application app) {
AndroidExecutor androidExecutor, Application app) {
this.dbExecutor = dbExecutor;
this.settingsManager = settingsManager;
this.messagingManager = messagingManager;
this.forumManager = forumManager;
this.androidExecutor = androidExecutor;
appContext = app.getApplicationContext();
}
@@ -157,15 +152,12 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(SETTINGS_NAMESPACE)) loadSettings();
} else if (e instanceof MessageStateChangedEvent) {
MessageStateChangedEvent m = (MessageStateChangedEvent) e;
if (!m.isLocal() && m.getState() == DELIVERED) {
ClientId c = m.getClientId();
if (c.equals(messagingManager.getClientId()))
showPrivateMessageNotification(m.getMessage().getGroupId());
else if (c.equals(forumManager.getClientId()))
showForumPostNotification(m.getMessage().getGroupId());
}
} else if (e instanceof PrivateMessageReceivedEvent) {
PrivateMessageReceivedEvent m = (PrivateMessageReceivedEvent) e;
showPrivateMessageNotification(m.getGroupId());
} else if (e instanceof ForumPostReceivedEvent) {
ForumPostReceivedEvent m = (ForumPostReceivedEvent) e;
showForumPostNotification(m.getGroupId());
} else if (e instanceof IntroductionRequestReceivedEvent) {
ContactId c = ((IntroductionRequestReceivedEvent) e).getContactId();
showNotificationForPrivateConversation(c);

View File

@@ -65,7 +65,6 @@ public class ForumActivity extends BriarActivity implements
private static final Logger LOG =
Logger.getLogger(ForumActivity.class.getName());
public static final String MIN_TIMESTAMP = "briar.MIN_TIMESTAMP";
static final String FORUM_NAME = "briar.FORUM_NAME";
private static final int REQUEST_FORUM_SHARED = 3;
@@ -341,7 +340,6 @@ public class ForumActivity extends BriarActivity implements
final View chevron, replyButton;
final ViewGroup cell;
final View topDivider;
public ValueAnimator highlightAnimator;
ForumViewHolder(View v) {
super(v);
@@ -438,7 +436,7 @@ public class ForumActivity extends BriarActivity implements
// TODO This loop doesn't really loop. @ernir please review!
for (int i = visiblePos + 1; i < getItemCount(); i++) {
ForumEntry entry = getVisibleEntry(i);
if (entry.getLevel() <= levelLimit)
if (entry != null && entry.getLevel() <= levelLimit)
break;
return true;
}
@@ -486,7 +484,7 @@ public class ForumActivity extends BriarActivity implements
for (int i = pos + 1; i < getItemCount(); i++) {
ForumEntry entry = getVisibleEntry(i);
if (entry.getLevel() > levelLimit) {
if (entry != null && entry.getLevel() > levelLimit) {
indexList.add(i);
} else {
break;
@@ -613,6 +611,8 @@ public class ForumActivity extends BriarActivity implements
public void onBindViewHolder(
final ForumViewHolder ui, final int position) {
final ForumEntry data = getVisibleEntry(position);
if (data == null) return;
if (!data.isRead()) {
data.setRead(true);
forumController.entryRead(data);

View File

@@ -19,7 +19,7 @@ public interface ForumController extends ActivityLifecycleController {
void createPost(byte[] body);
void createPost(byte[] body, MessageId parentId);
public interface ForumPostListener {
interface ForumPostListener {
void addLocalEntry(int index, ForumEntry entry);
void addForeignEntry(int index, ForumEntry entry);
}

View File

@@ -13,12 +13,13 @@ import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.ForumPostReceivedEvent;
import org.briarproject.api.event.GroupRemovedEvent;
import org.briarproject.api.event.MessageStateChangedEvent;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.forum.ForumPostHeader;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.GroupId;
@@ -38,7 +39,7 @@ import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.api.identity.Author.Status.VERIFIED;
public class ForumControllerImpl extends DbControllerImpl
implements ForumController, EventListener {
@@ -52,7 +53,7 @@ public class ForumControllerImpl extends DbControllerImpl
@CryptoExecutor
protected Executor cryptoExecutor;
@Inject
protected volatile ForumPostFactory forumPostFactory;
volatile ForumPostFactory forumPostFactory;
@Inject
protected volatile CryptoComponent crypto;
@Inject
@@ -65,7 +66,6 @@ public class ForumControllerImpl extends DbControllerImpl
protected ForumPersistentData data;
private ForumPostListener listener;
private MessageId localAdd = null;
@Inject
ForumControllerImpl() {
@@ -100,51 +100,13 @@ public class ForumControllerImpl extends DbControllerImpl
}
}
private void findSingleNewEntry() {
runOnDbThread(new Runnable() {
@Override
public void run() {
List<ForumEntry> oldEntries = getForumEntries();
data.clearHeaders();
try {
loadPosts();
List<ForumEntry> allEntries = getForumEntries();
int i = 0;
for (ForumEntry entry : allEntries) {
boolean isNew = true;
for (ForumEntry oldEntry : oldEntries) {
if (entry.getMessageId()
.equals(oldEntry.getMessageId())) {
isNew = false;
break;
}
}
if (isNew) {
if (localAdd != null &&
entry.getMessageId().equals(localAdd)) {
addLocalEntry(i, entry);
} else {
addForeignEntry(i, entry);
}
break;
}
i++;
}
} catch (DbException e) {
e.printStackTrace();
}
}
});
}
@Override
public void eventOccurred(Event e) {
if (e instanceof MessageStateChangedEvent) {
MessageStateChangedEvent m = (MessageStateChangedEvent) e;
if (m.getState() == DELIVERED &&
m.getMessage().getGroupId().equals(data.getGroupId())) {
LOG.info("Message added, reloading");
findSingleNewEntry();
if (e instanceof ForumPostReceivedEvent) {
ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e;
if (pe.getGroupId().equals(data.getGroupId())) {
LOG.info("Forum Post received, adding...");
addNewPost(pe.getForumPostHeader());
}
} else if (e instanceof GroupRemovedEvent) {
GroupRemovedEvent s = (GroupRemovedEvent) e;
@@ -160,6 +122,40 @@ public class ForumControllerImpl extends DbControllerImpl
}
}
private void addNewPost(final ForumPostHeader h) {
if (data == null) return;
runOnDbThread(new Runnable() {
@Override
public void run() {
data.addHeader(h);
data.clearForumEntries();
try {
byte[] body = forumManager.getPostBody(h.getId());
data.addBody(h.getId(), body);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
Author a = data.getLocalAuthor();
// FIXME we should not need to calculate the index here
// the index is essentially stored in two different locations
int i = 0;
for (ForumEntry entry : getForumEntries()) {
if (entry.getMessageId().equals(h.getId())) {
if (a != null && a.equals(h.getAuthor())) {
addLocalEntry(i, entry);
} else {
addForeignEntry(i, entry);
}
}
i++;
}
}
});
}
private void loadAuthor() throws DbException {
Collection<LocalAuthor> localAuthors =
identityManager.getLocalAuthors();
@@ -343,6 +339,7 @@ public class ForumControllerImpl extends DbControllerImpl
throw new RuntimeException(e);
}
storePost(p);
addNewPost(p);
}
});
}
@@ -369,7 +366,6 @@ public class ForumControllerImpl extends DbControllerImpl
runOnDbThread(new Runnable() {
public void run() {
try {
localAdd = p.getMessage().getId();
long now = System.currentTimeMillis();
forumManager.addLocalPost(p);
long duration = System.currentTimeMillis() - now;
@@ -384,4 +380,12 @@ public class ForumControllerImpl extends DbControllerImpl
});
}
private void addNewPost(final ForumPost p) {
ForumPostHeader h =
new ForumPostHeader(p.getMessage().getId(), p.getParent(),
p.getMessage().getTimestamp(), p.getAuthor(), VERIFIED,
p.getContentType(), false);
addNewPost(h);
}
}

View File

@@ -17,7 +17,7 @@ public class ForumEntry {
private boolean isShowingDescendants = true;
private boolean isRead = true;
public ForumEntry(ForumPostHeader h, String text, int level) {
ForumEntry(ForumPostHeader h, String text, int level) {
this(h.getId(), text, level, h.getTimestamp(), h.getAuthor().getName(),
h.getAuthor().getId(), h.getAuthorStatus());
this.isRead = h.isRead();
@@ -50,7 +50,7 @@ public class ForumEntry {
return author;
}
public AuthorId getAuthorId() {
AuthorId getAuthorId() {
return authorId;
}
@@ -58,15 +58,15 @@ public class ForumEntry {
return status;
}
public boolean isShowingDescendants() {
boolean isShowingDescendants() {
return isShowingDescendants;
}
public void setShowingDescendants(boolean showingDescendants) {
void setShowingDescendants(boolean showingDescendants) {
this.isShowingDescendants = showingDescendants;
}
public MessageId getMessageId() {
MessageId getMessageId() {
return messageId;
}
@@ -74,7 +74,7 @@ public class ForumEntry {
return isRead;
}
public void setRead(boolean read) {
void setRead(boolean read) {
isRead = read;
}
}

View File

@@ -22,14 +22,13 @@ import org.briarproject.api.db.NoSuchGroupException;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.ForumInvitationReceivedEvent;
import org.briarproject.api.event.ForumPostReceivedEvent;
import org.briarproject.api.event.GroupAddedEvent;
import org.briarproject.api.event.GroupRemovedEvent;
import org.briarproject.api.event.MessageStateChangedEvent;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPostHeader;
import org.briarproject.api.forum.ForumSharingManager;
import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId;
import java.util.ArrayList;
@@ -41,7 +40,6 @@ import javax.inject.Inject;
import static android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
public class ForumListFragment extends BaseEventFragment implements
View.OnClickListener {
@@ -234,14 +232,10 @@ public class ForumListFragment extends BaseEventFragment implements
LOG.info("Forum removed, removing from list");
removeForum(g.getGroup().getId());
}
} else if (e instanceof MessageStateChangedEvent) {
MessageStateChangedEvent m = (MessageStateChangedEvent) e;
ClientId c = m.getClientId();
if (m.getState() == DELIVERED &&
c.equals(forumManager.getClientId())) {
LOG.info("Forum post added, reloading");
loadForumHeaders(m.getMessage().getGroupId());
}
} else if (e instanceof ForumPostReceivedEvent) {
ForumPostReceivedEvent m = (ForumPostReceivedEvent) e;
LOG.info("Forum post added, reloading");
loadForumHeaders(m.getGroupId());
} else if (e instanceof ForumInvitationReceivedEvent) {
loadAvailableForums();
}

View File

@@ -12,7 +12,6 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
* This class is a singleton that defines the data that should persist, i.e.
@@ -21,7 +20,7 @@ import java.util.logging.Logger;
*/
public class ForumPersistentData {
protected volatile MessageTree<ForumPostHeader> tree =
private volatile MessageTree<ForumPostHeader> tree =
new MessageTreeImpl<>();
private volatile Map<MessageId, byte[]> bodyCache = new HashMap<>();
private volatile LocalAuthor localAuthor;
@@ -29,36 +28,36 @@ public class ForumPersistentData {
private volatile GroupId groupId;
private List<ForumEntry> forumEntries;
private static final Logger LOG =
Logger.getLogger(ForumControllerImpl.class.getName());
public void clearAll() {
clearHeaders();
void clearAll() {
clearForumEntries();
tree.clear();
bodyCache.clear();
localAuthor = null;
forum = null;
groupId = null;
}
public void clearHeaders() {
tree.clear();
void clearForumEntries() {
forumEntries = null;
}
public void addHeaders(Collection<ForumPostHeader> headers) {
void addHeaders(Collection<ForumPostHeader> headers) {
tree.add(headers);
}
void addHeader(ForumPostHeader header) {
tree.add(header);
}
public Collection<ForumPostHeader> getHeaders() {
return tree.depthFirstOrder();
}
public void addBody(MessageId messageId, byte[] body) {
void addBody(MessageId messageId, byte[] body) {
bodyCache.put(messageId, body);
}
public byte[] getBody(MessageId messageId) {
byte[] getBody(MessageId messageId) {
return bodyCache.get(messageId);
}
@@ -87,11 +86,11 @@ public class ForumPersistentData {
this.groupId = groupId;
}
public List<ForumEntry> getForumEntries() {
List<ForumEntry> getForumEntries() {
return forumEntries;
}
public void setForumEntries(List<ForumEntry> forumEntries) {
void setForumEntries(List<ForumEntry> forumEntries) {
this.forumEntries = forumEntries;
}
}