diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java index 8cc883166..5228d8763 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java @@ -8,20 +8,15 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; -import org.briarproject.briar.android.forum.ForumController.ForumListener; import org.briarproject.briar.android.threaded.ThreadListControllerImpl; import org.briarproject.briar.api.android.AndroidNotificationManager; -import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.forum.ForumInvitationResponse; import org.briarproject.briar.api.forum.ForumManager; -import org.briarproject.briar.api.forum.ForumPost; import org.briarproject.briar.api.forum.ForumPostHeader; import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent; @@ -33,16 +28,13 @@ import java.util.Collection; import java.util.concurrent.Executor; import java.util.logging.Logger; -import javax.annotation.Nullable; import javax.inject.Inject; -import static java.lang.Math.max; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.util.LogUtils.logException; @NotNullByDefault -class ForumControllerImpl extends - ThreadListControllerImpl +class ForumControllerImpl extends ThreadListControllerImpl implements ForumController { private static final Logger LOG = @@ -56,10 +48,10 @@ class ForumControllerImpl extends LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, ForumManager forumManager, ForumSharingManager forumSharingManager, - EventBus eventBus, Clock clock, MessageTracker messageTracker, + EventBus eventBus, Clock clock, AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, - eventBus, clock, notificationManager, messageTracker); + eventBus, clock, notificationManager); this.forumManager = forumManager; this.forumSharingManager = forumSharingManager; } @@ -74,6 +66,8 @@ class ForumControllerImpl extends public void eventOccurred(Event e) { super.eventOccurred(e); + ForumListener listener = (ForumListener) this.listener; + if (e instanceof ForumPostReceivedEvent) { ForumPostReceivedEvent f = (ForumPostReceivedEvent) e; if (f.getGroupId().equals(getGroupId())) { @@ -120,44 +114,7 @@ class ForumControllerImpl extends }); } - @Override - public void createAndStoreMessage(String text, - @Nullable ForumPostItem parentItem, - ResultExceptionHandler handler) { - runOnDbThread(() -> { - try { - LocalAuthor author = identityManager.getLocalAuthor(); - GroupCount count = forumManager.getGroupCount(getGroupId()); - long timestamp = max(count.getLatestMsgTime() + 1, - clock.currentTimeMillis()); - MessageId parentId = parentItem != null ? - parentItem.getId() : null; - createMessage(text, timestamp, parentId, author, handler); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); - } - - private void createMessage(String text, long timestamp, - @Nullable MessageId parentId, LocalAuthor author, - ResultExceptionHandler handler) { - cryptoExecutor.execute(() -> { - LOG.info("Creating forum post..."); - ForumPost msg = forumManager.createLocalPost(getGroupId(), text, - timestamp, parentId, author); - storePost(msg, text, handler); - }); - } - - @Override - protected ForumPostHeader addLocalMessage(ForumPost p) throws DbException { - return forumManager.addLocalPost(p); - } - - @Override - protected ForumPostItem buildItem(ForumPostHeader header, String text) { + private ForumPostItem buildItem(ForumPostHeader header, String text) { return new ForumPostItem(header, text); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumViewModel.java index a378f00db..b6b24f790 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumViewModel.java @@ -11,32 +11,37 @@ import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.R; import org.briarproject.briar.android.threaded.ThreadListViewModel; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.client.MessageTracker; +import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.PostHeader; import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.ForumManager; +import org.briarproject.briar.api.forum.ForumPost; import org.briarproject.briar.api.forum.ForumPostHeader; import org.briarproject.briar.api.forum.ForumSharingManager; -import org.briarproject.briar.client.MessageTreeImpl; import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import static android.widget.Toast.LENGTH_SHORT; +import static java.lang.Math.max; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logDuration; @@ -98,12 +103,52 @@ class ForumViewModel extends ThreadListViewModel { List headers = forumManager.getPostHeaders(txn, groupId); logDuration(LOG, "Loading headers", start); - List items = - buildItems(txn, headers, this::buildItem); - return new MessageTreeImpl<>(items).depthFirstOrder(); + return recreateItems(txn, headers, this::buildItem); }, this::setItems); } + @Override + public void createAndStoreMessage(String text, + @Nullable ForumPostItem parentItem) { + runOnDbThread(() -> { + try { + LocalAuthor author = identityManager.getLocalAuthor(); + GroupCount count = forumManager.getGroupCount(groupId); + long timestamp = max(count.getLatestMsgTime() + 1, + clock.currentTimeMillis()); + MessageId parentId = + parentItem != null ? parentItem.getId() : null; + createMessage(text, timestamp, parentId, author); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + private void createMessage(String text, long timestamp, + @Nullable MessageId parentId, LocalAuthor author) { + cryptoExecutor.execute(() -> { + LOG.info("Creating forum post..."); + ForumPost msg = forumManager.createLocalPost(groupId, text, + timestamp, parentId, author); + storePost(msg, text); + }); + } + + private void storePost(ForumPost msg, String text) { + runOnDbThread(() -> { + try { + long start = now(); + ForumPostHeader header = forumManager.addLocalPost(msg); + textCache.put(msg.getMessage().getId(), text); + addItem(buildItem(header, text), true); + logDuration(LOG, "Storing forum post", start); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + private ForumPostItem buildItem(ForumPostHeader header, String text) { return new ForumPostItem(header, text); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java index fa5c72a60..d83cd9b53 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java @@ -7,21 +7,15 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; -import org.briarproject.briar.android.privategroup.conversation.GroupController.GroupListener; import org.briarproject.briar.android.threaded.ThreadListControllerImpl; import org.briarproject.briar.api.android.AndroidNotificationManager; -import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.privategroup.GroupMember; -import org.briarproject.briar.api.privategroup.GroupMessage; -import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.GroupMessageHeader; import org.briarproject.briar.api.privategroup.JoinMessageHeader; import org.briarproject.briar.api.privategroup.PrivateGroupManager; @@ -36,37 +30,32 @@ import java.util.Collection; import java.util.concurrent.Executor; import java.util.logging.Logger; -import javax.annotation.Nullable; import javax.inject.Inject; -import static java.lang.Math.max; import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logException; @MethodsNotNullByDefault @ParametersNotNullByDefault -class GroupControllerImpl extends - ThreadListControllerImpl +class GroupControllerImpl extends ThreadListControllerImpl implements GroupController { private static final Logger LOG = - Logger.getLogger(GroupControllerImpl.class.getName()); + getLogger(GroupControllerImpl.class.getName()); private final PrivateGroupManager privateGroupManager; - private final GroupMessageFactory groupMessageFactory; @Inject GroupControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, PrivateGroupManager privateGroupManager, - GroupMessageFactory groupMessageFactory, EventBus eventBus, - MessageTracker messageTracker, Clock clock, + EventBus eventBus, Clock clock, AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, - eventBus, clock, notificationManager, messageTracker); + eventBus, clock, notificationManager); this.privateGroupManager = privateGroupManager; - this.groupMessageFactory = groupMessageFactory; } @Override @@ -79,6 +68,8 @@ class GroupControllerImpl extends public void eventOccurred(Event e) { super.eventOccurred(e); + GroupListener listener = (GroupListener) this.listener; + if (e instanceof GroupMessageAddedEvent) { GroupMessageAddedEvent g = (GroupMessageAddedEvent) e; if (!g.isLocal() && g.getGroupId().equals(getGroupId())) { @@ -132,52 +123,7 @@ class GroupControllerImpl extends }); } - @Override - public void createAndStoreMessage(String text, - @Nullable GroupMessageItem parentItem, - ResultExceptionHandler handler) { - runOnDbThread(() -> { - try { - LocalAuthor author = identityManager.getLocalAuthor(); - MessageId parentId = null; - MessageId previousMsgId = - privateGroupManager.getPreviousMsgId(getGroupId()); - GroupCount count = - privateGroupManager.getGroupCount(getGroupId()); - long timestamp = count.getLatestMsgTime(); - if (parentItem != null) parentId = parentItem.getId(); - timestamp = max(clock.currentTimeMillis(), timestamp + 1); - createMessage(text, timestamp, parentId, author, previousMsgId, - handler); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); - } - - private void createMessage(String text, long timestamp, - @Nullable MessageId parentId, LocalAuthor author, - MessageId previousMsgId, - ResultExceptionHandler handler) { - cryptoExecutor.execute(() -> { - LOG.info("Creating group message..."); - GroupMessage msg = groupMessageFactory - .createGroupMessage(getGroupId(), timestamp, - parentId, author, text, previousMsgId); - storePost(msg, text, handler); - }); - } - - @Override - protected GroupMessageHeader addLocalMessage(GroupMessage message) - throws DbException { - return privateGroupManager.addLocalMessage(message); - } - - @Override - protected GroupMessageItem buildItem(GroupMessageHeader header, - String text) { + private GroupMessageItem buildItem(GroupMessageHeader header, String text) { if (header instanceof JoinMessageHeader) { return new JoinMessageItem((JoinMessageHeader) header, text); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageAdapter.java index d418f6178..76c2dc564 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageAdapter.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageAdapter.java @@ -58,7 +58,7 @@ class GroupMessageAdapter extends ThreadItemAdapter { GroupMessageItem item = getItem(position); if (item instanceof JoinMessageItem) { ((JoinMessageItem) item).setVisibility(v); - notifyItemChanged(findItemPosition(item), item); + notifyItemChanged(findItemPosition(item.getId()), item); } } } @@ -73,12 +73,4 @@ class GroupMessageAdapter extends ThreadItemAdapter { return NO_POSITION; // Not found } - @Deprecated - private int findItemPosition(GroupMessageItem itemToFind) { - for (int i = 0; i < getItemCount(); i++) { - if (getItem(i).equals(itemToFind)) return i; - } - return NO_POSITION; // Not found - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupViewModel.java index 335889861..4e0e33db5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupViewModel.java @@ -11,32 +11,37 @@ import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.android.threaded.ThreadListViewModel; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.client.MessageTracker; +import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.PostHeader; +import org.briarproject.briar.api.privategroup.GroupMessage; import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.GroupMessageHeader; import org.briarproject.briar.api.privategroup.JoinMessageHeader; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupManager; -import org.briarproject.briar.client.MessageTreeImpl; import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; +import static java.lang.Math.max; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logDuration; @@ -109,9 +114,7 @@ class GroupViewModel extends ThreadListViewModel { List headers = privateGroupManager.getHeaders(txn, groupId); logDuration(LOG, "Loading headers", start); - List items = - buildItems(txn, headers, this::buildItem); - return new MessageTreeImpl<>(items).depthFirstOrder(); + return recreateItems(txn, headers, this::buildItem); }, this::setItems); } @@ -132,6 +135,52 @@ class GroupViewModel extends ThreadListViewModel { return privateGroupManager.getMessageText(txn, header.getId()); } + @Override + public void createAndStoreMessage(String text, + @Nullable GroupMessageItem parentItem) { + runOnDbThread(() -> { + try { + LocalAuthor author = identityManager.getLocalAuthor(); + MessageId parentId = null; + MessageId previousMsgId = + privateGroupManager.getPreviousMsgId(groupId); + GroupCount count = privateGroupManager.getGroupCount(groupId); + long timestamp = count.getLatestMsgTime(); + if (parentItem != null) parentId = parentItem.getId(); + timestamp = max(clock.currentTimeMillis(), timestamp + 1); + createMessage(text, timestamp, parentId, author, previousMsgId); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + private void createMessage(String text, long timestamp, + @Nullable MessageId parentId, LocalAuthor author, + MessageId previousMsgId) { + cryptoExecutor.execute(() -> { + LOG.info("Creating group message..."); + GroupMessage msg = groupMessageFactory.createGroupMessage(groupId, + timestamp, parentId, author, text, previousMsgId); + storePost(msg, text); + }); + } + + private void storePost(GroupMessage msg, String text) { + runOnDbThread(() -> { + try { + long start = now(); + GroupMessageHeader header = + privateGroupManager.addLocalMessage(msg); + textCache.put(msg.getMessage().getId(), text); + addItem(buildItem(header, text), true); + logDuration(LOG, "Storing group message", start); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + void deletePrivateGroup() { runOnDbThread(() -> { try { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java index 63db2770e..73865d875 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java @@ -66,16 +66,11 @@ public class ThreadItemAdapter ui.bind(item, listener); } - void setItemWithIdVisible(MessageId messageId) { - int pos = 0; + public int findItemPosition(MessageId id) { for (int i = 0; i < getItemCount(); i++) { - I item = getItem(i); - if (item.getId().equals(messageId)) { - layoutManager.scrollToPosition(pos); - break; - } - pos++; + if (id.equals(getItem(i).getId())) return i; } + return NO_POSITION; // Not found } /** diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java index 1b3e0d202..9aaee4dc0 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java @@ -136,6 +136,12 @@ public abstract class ThreadListActivity, DbException>( @@ -206,10 +220,6 @@ public abstract class ThreadListActivity { - scrollToItemAtTop(item); + scrollToItemAtTop(item.getId()); textInput.setOnKeyboardShownListener(null); }); } @@ -277,11 +286,10 @@ public abstract class ThreadListActivity handler = - new UiResultExceptionHandler(this) { - @Override - public void onResultUi(I result) { - addItem(result, true); - } - - @Override - public void onExceptionUi(DbException exception) { - handleException(exception); - } - }; - getController().createAndStoreMessage(text, replyItem, handler); + getViewModel().createAndStoreMessage(text, replyItem); textInput.hideSoftKeyboard(); textInput.clearText(); replyId = null; @@ -330,7 +326,7 @@ public abstract class ThreadListActivity void markItemsRead(Collection items); - void createAndStoreMessage(String text, @Nullable I parentItem, - ResultExceptionHandler handler); - interface ThreadListListener extends ThreadListDataSource { @UiThread diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java index 58e3f7d03..f998cf701 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java @@ -17,17 +17,10 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.event.GroupRemovedEvent; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.android.controller.DbControllerImpl; -import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; -import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener; import org.briarproject.briar.api.android.AndroidNotificationManager; -import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.PostHeader; -import org.briarproject.briar.api.client.ThreadedMessage; import java.util.Collection; import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -40,39 +33,34 @@ import static org.briarproject.bramble.util.LogUtils.now; @MethodsNotNullByDefault @ParametersNotNullByDefault -public abstract class ThreadListControllerImpl> +public abstract class ThreadListControllerImpl extends DbControllerImpl implements ThreadListController, EventListener { private static final Logger LOG = Logger.getLogger(ThreadListControllerImpl.class.getName()); - private final EventBus eventBus; - private final MessageTracker messageTracker; - private final Map textCache = new ConcurrentHashMap<>(); - private volatile GroupId groupId; + private final EventBus eventBus; protected final IdentityManager identityManager; protected final AndroidNotificationManager notificationManager; protected final Executor cryptoExecutor; protected final Clock clock; // UI thread - protected L listener; + protected ThreadListListener listener; protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, EventBus eventBus, - Clock clock, AndroidNotificationManager notificationManager, - MessageTracker messageTracker) { + Clock clock, AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager); this.identityManager = identityManager; this.cryptoExecutor = cryptoExecutor; this.notificationManager = notificationManager; this.clock = clock; this.eventBus = eventBus; - this.messageTracker = messageTracker; } @Override @@ -84,7 +72,7 @@ public abstract class ThreadListControllerImpl) activity; } @CallSuper @@ -103,16 +91,7 @@ public abstract class ThreadListControllerImpl { - try { - messageTracker.storeMessageId(groupId, messageId); - } catch (DbException e) { - logException(LOG, WARNING, e); - } - }); - } + } @CallSuper @@ -150,27 +129,6 @@ public abstract class ThreadListControllerImpl resultHandler) { - runOnDbThread(() -> { - try { - long start = now(); - H header = addLocalMessage(msg); - textCache.put(msg.getMessage().getId(), text); - logDuration(LOG, "Storing message", start); - resultHandler.onResult(buildItem(header, text)); - } catch (DbException e) { - logException(LOG, WARNING, e); - resultHandler.onException(e); - } - }); - } - - @DatabaseExecutor - protected abstract H addLocalMessage(M message) throws DbException; - - protected abstract I buildItem(H header, String text); - protected GroupId getGroupId() { checkGroupId(); return groupId; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListViewModel.java index 778796ce9..733f38b4b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListViewModel.java @@ -21,28 +21,36 @@ import org.briarproject.briar.android.viewmodel.DbViewModel; import org.briarproject.briar.android.viewmodel.LiveResult; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.client.MessageTracker; +import org.briarproject.briar.api.client.MessageTree; import org.briarproject.briar.api.client.PostHeader; +import org.briarproject.briar.client.MessageTreeImpl; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; +import javax.annotation.Nullable; + import androidx.annotation.CallSuper; import androidx.annotation.UiThread; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logDuration; +import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; @MethodsNotNullByDefault @ParametersNotNullByDefault -public abstract class ThreadListViewModel extends DbViewModel +public abstract class ThreadListViewModel + extends DbViewModel implements EventListener { private static final Logger LOG = @@ -55,11 +63,18 @@ public abstract class ThreadListViewModel extends DbViewMo private final MessageTracker messageTracker; private final EventBus eventBus; - private final Map textCache = new ConcurrentHashMap<>(); + @DatabaseExecutor + private final MessageTree messageTree = new MessageTreeImpl<>(); + protected final Map textCache = + new ConcurrentHashMap<>(); private final MutableLiveData>> items = new MutableLiveData<>(); + private final AtomicReference scrollToItem = + new AtomicReference<>(); protected volatile GroupId groupId; + private final AtomicReference storedMessageId = + new AtomicReference<>(); public ThreadListViewModel(Application application, @DatabaseExecutor Executor dbExecutor, @@ -95,18 +110,37 @@ public abstract class ThreadListViewModel extends DbViewMo @CallSuper public void setGroupId(GroupId groupId) { this.groupId = groupId; + loadStoredMessageId(); loadItems(); } + private void loadStoredMessageId() { + runOnDbThread(() -> { + try { + storedMessageId + .set(messageTracker.loadStoredMessageId(groupId)); + if (LOG.isLoggable(INFO)) { + LOG.info("Loaded last top visible message id " + + storedMessageId); + } + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + public abstract void loadItems(); + public abstract void createAndStoreMessage(String text, + @Nullable I parentItem); + @UiThread protected void setItems(LiveResult> items) { this.items.setValue(items); } @DatabaseExecutor - protected List buildItems( + protected List recreateItems( Transaction txn, Collection headers, ItemGetter itemGetter) throws DbException { long start = now(); @@ -122,23 +156,45 @@ public abstract class ThreadListViewModel extends DbViewMo } logDuration(LOG, "Loading bodies and creating items", start); - MessageId msgId = messageTracker.loadStoredMessageId(txn, groupId); - if (LOG.isLoggable(INFO)) { - LOG.info("Loaded last top visible message id " + msgId); - } - // TODO store this elsewhere - items.setFirstVisibleId(msgId); - return items; + messageTree.clear(); + messageTree.add(items); + return messageTree.depthFirstOrder(); + } + + protected void addItem(I item, boolean local) { + messageTree.add(item); + if (local) scrollToItem.set(item.getId()); + items.postValue(new LiveResult<>(messageTree.depthFirstOrder())); } @DatabaseExecutor protected abstract String loadMessageText(Transaction txn, PostHeader header) throws DbException; + void storeMessageId(@Nullable MessageId messageId) { + if (messageId != null) runOnDbThread(() -> { + try { + messageTracker.storeMessageId(groupId, messageId); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + @Nullable + MessageId getAndResetRestoredMessageId() { + return storedMessageId.getAndSet(null); + } + LiveData>> getItems() { return items; } + @Nullable + MessageId getAndResetScrollToItem() { + return scrollToItem.getAndSet(null); + } + public interface ItemGetter { I getItem(H header, String text); } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTree.java b/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTree.java index fabdd3308..579059a01 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTree.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTree.java @@ -13,15 +13,12 @@ public interface MessageTree { void add(Collection nodes); - @Deprecated void add(T node); - @Deprecated void clear(); List depthFirstOrder(); - @Deprecated boolean contains(MessageId m); @NotNullByDefault diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java index 30ee18e35..1c98c62ac 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumManager.java @@ -109,7 +109,6 @@ public interface ForumManager { /** * Returns the group count for the given forum. */ - @Deprecated GroupCount getGroupCount(GroupId g) throws DbException; /** diff --git a/briar-core/src/main/java/org/briarproject/briar/client/MessageTreeImpl.java b/briar-core/src/main/java/org/briarproject/briar/client/MessageTreeImpl.java index 49027d190..caca96b11 100644 --- a/briar-core/src/main/java/org/briarproject/briar/client/MessageTreeImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/client/MessageTreeImpl.java @@ -33,11 +33,6 @@ public class MessageTreeImpl private final Comparator comparator = (o1, o2) -> Long.valueOf(o1.getTimestamp()).compareTo(o2.getTimestamp()); - public MessageTreeImpl(Collection collection) { - super(); - add(collection); - } - @Override public synchronized void clear() { roots.clear();