mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Move adding new ThreadList items to ViewModel
This commit is contained in:
@@ -8,20 +8,15 @@ import org.briarproject.bramble.api.db.DbException;
|
|||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
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.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
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.android.threaded.ThreadListControllerImpl;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
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.ForumInvitationResponse;
|
||||||
import org.briarproject.briar.api.forum.ForumManager;
|
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.ForumPostHeader;
|
||||||
import org.briarproject.briar.api.forum.ForumSharingManager;
|
import org.briarproject.briar.api.forum.ForumSharingManager;
|
||||||
import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent;
|
import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent;
|
||||||
@@ -33,16 +28,13 @@ import java.util.Collection;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class ForumControllerImpl extends
|
class ForumControllerImpl extends ThreadListControllerImpl<ForumPostItem>
|
||||||
ThreadListControllerImpl<ForumPostItem, ForumPostHeader, ForumPost, ForumListener>
|
|
||||||
implements ForumController {
|
implements ForumController {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -56,10 +48,10 @@ class ForumControllerImpl extends
|
|||||||
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
||||||
@CryptoExecutor Executor cryptoExecutor,
|
@CryptoExecutor Executor cryptoExecutor,
|
||||||
ForumManager forumManager, ForumSharingManager forumSharingManager,
|
ForumManager forumManager, ForumSharingManager forumSharingManager,
|
||||||
EventBus eventBus, Clock clock, MessageTracker messageTracker,
|
EventBus eventBus, Clock clock,
|
||||||
AndroidNotificationManager notificationManager) {
|
AndroidNotificationManager notificationManager) {
|
||||||
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
||||||
eventBus, clock, notificationManager, messageTracker);
|
eventBus, clock, notificationManager);
|
||||||
this.forumManager = forumManager;
|
this.forumManager = forumManager;
|
||||||
this.forumSharingManager = forumSharingManager;
|
this.forumSharingManager = forumSharingManager;
|
||||||
}
|
}
|
||||||
@@ -74,6 +66,8 @@ class ForumControllerImpl extends
|
|||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
super.eventOccurred(e);
|
super.eventOccurred(e);
|
||||||
|
|
||||||
|
ForumListener listener = (ForumListener) this.listener;
|
||||||
|
|
||||||
if (e instanceof ForumPostReceivedEvent) {
|
if (e instanceof ForumPostReceivedEvent) {
|
||||||
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
|
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
|
||||||
if (f.getGroupId().equals(getGroupId())) {
|
if (f.getGroupId().equals(getGroupId())) {
|
||||||
@@ -120,44 +114,7 @@ class ForumControllerImpl extends
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private ForumPostItem buildItem(ForumPostHeader header, String text) {
|
||||||
public void createAndStoreMessage(String text,
|
|
||||||
@Nullable ForumPostItem parentItem,
|
|
||||||
ResultExceptionHandler<ForumPostItem, DbException> 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<ForumPostItem, DbException> 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) {
|
|
||||||
return new ForumPostItem(header, text);
|
return new ForumPostItem(header, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,32 +11,37 @@ import org.briarproject.bramble.api.db.TransactionManager;
|
|||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
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.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
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.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.threaded.ThreadListViewModel;
|
import org.briarproject.briar.android.threaded.ThreadListViewModel;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
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.client.PostHeader;
|
||||||
import org.briarproject.briar.api.forum.Forum;
|
import org.briarproject.briar.api.forum.Forum;
|
||||||
import org.briarproject.briar.api.forum.ForumManager;
|
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.ForumPostHeader;
|
||||||
import org.briarproject.briar.api.forum.ForumSharingManager;
|
import org.briarproject.briar.api.forum.ForumSharingManager;
|
||||||
import org.briarproject.briar.client.MessageTreeImpl;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
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.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
@@ -98,12 +103,52 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
|
|||||||
List<ForumPostHeader> headers =
|
List<ForumPostHeader> headers =
|
||||||
forumManager.getPostHeaders(txn, groupId);
|
forumManager.getPostHeaders(txn, groupId);
|
||||||
logDuration(LOG, "Loading headers", start);
|
logDuration(LOG, "Loading headers", start);
|
||||||
List<ForumPostItem> items =
|
return recreateItems(txn, headers, this::buildItem);
|
||||||
buildItems(txn, headers, this::buildItem);
|
|
||||||
return new MessageTreeImpl<>(items).depthFirstOrder();
|
|
||||||
}, this::setItems);
|
}, 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) {
|
private ForumPostItem buildItem(ForumPostHeader header, String text) {
|
||||||
return new ForumPostItem(header, text);
|
return new ForumPostItem(header, text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,21 +7,15 @@ import org.briarproject.bramble.api.db.DbException;
|
|||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
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.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
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.android.threaded.ThreadListControllerImpl;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
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.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.GroupMessageHeader;
|
||||||
import org.briarproject.briar.api.privategroup.JoinMessageHeader;
|
import org.briarproject.briar.api.privategroup.JoinMessageHeader;
|
||||||
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
|
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
|
||||||
@@ -36,37 +30,32 @@ import java.util.Collection;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class GroupControllerImpl extends
|
class GroupControllerImpl extends ThreadListControllerImpl<GroupMessageItem>
|
||||||
ThreadListControllerImpl<GroupMessageItem, GroupMessageHeader, GroupMessage, GroupListener>
|
|
||||||
implements GroupController {
|
implements GroupController {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(GroupControllerImpl.class.getName());
|
getLogger(GroupControllerImpl.class.getName());
|
||||||
|
|
||||||
private final PrivateGroupManager privateGroupManager;
|
private final PrivateGroupManager privateGroupManager;
|
||||||
private final GroupMessageFactory groupMessageFactory;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
GroupControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
GroupControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||||
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
||||||
@CryptoExecutor Executor cryptoExecutor,
|
@CryptoExecutor Executor cryptoExecutor,
|
||||||
PrivateGroupManager privateGroupManager,
|
PrivateGroupManager privateGroupManager,
|
||||||
GroupMessageFactory groupMessageFactory, EventBus eventBus,
|
EventBus eventBus, Clock clock,
|
||||||
MessageTracker messageTracker, Clock clock,
|
|
||||||
AndroidNotificationManager notificationManager) {
|
AndroidNotificationManager notificationManager) {
|
||||||
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
||||||
eventBus, clock, notificationManager, messageTracker);
|
eventBus, clock, notificationManager);
|
||||||
this.privateGroupManager = privateGroupManager;
|
this.privateGroupManager = privateGroupManager;
|
||||||
this.groupMessageFactory = groupMessageFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -79,6 +68,8 @@ class GroupControllerImpl extends
|
|||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
super.eventOccurred(e);
|
super.eventOccurred(e);
|
||||||
|
|
||||||
|
GroupListener listener = (GroupListener) this.listener;
|
||||||
|
|
||||||
if (e instanceof GroupMessageAddedEvent) {
|
if (e instanceof GroupMessageAddedEvent) {
|
||||||
GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
|
GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
|
||||||
if (!g.isLocal() && g.getGroupId().equals(getGroupId())) {
|
if (!g.isLocal() && g.getGroupId().equals(getGroupId())) {
|
||||||
@@ -132,52 +123,7 @@ class GroupControllerImpl extends
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private GroupMessageItem buildItem(GroupMessageHeader header, String text) {
|
||||||
public void createAndStoreMessage(String text,
|
|
||||||
@Nullable GroupMessageItem parentItem,
|
|
||||||
ResultExceptionHandler<GroupMessageItem, DbException> 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<GroupMessageItem, DbException> 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) {
|
|
||||||
if (header instanceof JoinMessageHeader) {
|
if (header instanceof JoinMessageHeader) {
|
||||||
return new JoinMessageItem((JoinMessageHeader) header, text);
|
return new JoinMessageItem((JoinMessageHeader) header, text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
|
|||||||
GroupMessageItem item = getItem(position);
|
GroupMessageItem item = getItem(position);
|
||||||
if (item instanceof JoinMessageItem) {
|
if (item instanceof JoinMessageItem) {
|
||||||
((JoinMessageItem) item).setVisibility(v);
|
((JoinMessageItem) item).setVisibility(v);
|
||||||
notifyItemChanged(findItemPosition(item), item);
|
notifyItemChanged(findItemPosition(item.getId()), item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,12 +73,4 @@ class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
|
|||||||
return NO_POSITION; // Not found
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,32 +11,37 @@ import org.briarproject.bramble.api.event.Event;
|
|||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
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.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
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.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.android.threaded.ThreadListViewModel;
|
import org.briarproject.briar.android.threaded.ThreadListViewModel;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
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.client.PostHeader;
|
||||||
|
import org.briarproject.briar.api.privategroup.GroupMessage;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
|
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
|
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
|
||||||
import org.briarproject.briar.api.privategroup.JoinMessageHeader;
|
import org.briarproject.briar.api.privategroup.JoinMessageHeader;
|
||||||
import org.briarproject.briar.api.privategroup.PrivateGroup;
|
import org.briarproject.briar.api.privategroup.PrivateGroup;
|
||||||
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
|
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
|
||||||
import org.briarproject.briar.client.MessageTreeImpl;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
|
import static java.lang.Math.max;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
@@ -109,9 +114,7 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
|
|||||||
List<GroupMessageHeader> headers =
|
List<GroupMessageHeader> headers =
|
||||||
privateGroupManager.getHeaders(txn, groupId);
|
privateGroupManager.getHeaders(txn, groupId);
|
||||||
logDuration(LOG, "Loading headers", start);
|
logDuration(LOG, "Loading headers", start);
|
||||||
List<GroupMessageItem> items =
|
return recreateItems(txn, headers, this::buildItem);
|
||||||
buildItems(txn, headers, this::buildItem);
|
|
||||||
return new MessageTreeImpl<>(items).depthFirstOrder();
|
|
||||||
}, this::setItems);
|
}, this::setItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +135,52 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
|
|||||||
return privateGroupManager.getMessageText(txn, header.getId());
|
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() {
|
void deletePrivateGroup() {
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -66,16 +66,11 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
ui.bind(item, listener);
|
ui.bind(item, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setItemWithIdVisible(MessageId messageId) {
|
public int findItemPosition(MessageId id) {
|
||||||
int pos = 0;
|
|
||||||
for (int i = 0; i < getItemCount(); i++) {
|
for (int i = 0; i < getItemCount(); i++) {
|
||||||
I item = getItem(i);
|
if (id.equals(getItem(i).getId())) return i;
|
||||||
if (item.getId().equals(messageId)) {
|
|
||||||
layoutManager.scrollToPosition(pos);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
}
|
||||||
|
return NO_POSITION; // Not found
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -136,6 +136,12 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
loadSharingContacts();
|
loadSharingContacts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
getViewModel().storeMessageId(getFirstVisibleMessageId());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public MessageId getFirstVisibleMessageId() {
|
public MessageId getFirstVisibleMessageId() {
|
||||||
@@ -154,21 +160,29 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
if (items.isEmpty()) {
|
if (items.isEmpty()) {
|
||||||
list.showData();
|
list.showData();
|
||||||
} else {
|
} else {
|
||||||
adapter.submitList(items);
|
adapter.submitList(items, this::scrollAfterListCommitted);
|
||||||
// TODO get this ID from elsewhere
|
|
||||||
MessageId messageId = null; // items.getFirstVisibleItemId();
|
|
||||||
if (messageId != null)
|
|
||||||
adapter.setItemWithIdVisible(messageId);
|
|
||||||
list.showData();
|
|
||||||
if (layoutManagerState == null) {
|
|
||||||
list.scrollToPosition(0); // Scroll to the top
|
|
||||||
} else {
|
|
||||||
layoutManager.onRestoreInstanceState(layoutManagerState);
|
|
||||||
}
|
|
||||||
updateTextInput();
|
updateTextInput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scrolls to the first visible item last time the activity was open,
|
||||||
|
* if one exists and this is the first time, the list gets displayed.
|
||||||
|
* Or scrolls to a locally added item that has just been added to the list.
|
||||||
|
*/
|
||||||
|
private void scrollAfterListCommitted() {
|
||||||
|
MessageId restoredFirstVisibleItemId =
|
||||||
|
getViewModel().getAndResetRestoredMessageId();
|
||||||
|
MessageId scrollToItem =
|
||||||
|
getViewModel().getAndResetScrollToItem();
|
||||||
|
if (restoredFirstVisibleItemId != null) {
|
||||||
|
scrollToItemAtTop(restoredFirstVisibleItemId);
|
||||||
|
} else if (scrollToItem != null) {
|
||||||
|
scrollToItemAtTop(scrollToItem);
|
||||||
|
}
|
||||||
|
scrollListener.updateUnreadButtons(layoutManager);
|
||||||
|
}
|
||||||
|
|
||||||
protected void loadSharingContacts() {
|
protected void loadSharingContacts() {
|
||||||
getController().loadSharingContacts(
|
getController().loadSharingContacts(
|
||||||
new UiResultExceptionHandler<Collection<ContactId>, DbException>(
|
new UiResultExceptionHandler<Collection<ContactId>, DbException>(
|
||||||
@@ -206,10 +220,6 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
if (layoutManager != null) {
|
|
||||||
layoutManagerState = layoutManager.onSaveInstanceState();
|
|
||||||
outState.putParcelable("layoutManager", layoutManagerState);
|
|
||||||
}
|
|
||||||
if (replyId != null) {
|
if (replyId != null) {
|
||||||
outState.putByteArray(KEY_REPLY_ID, replyId.getBytes());
|
outState.putByteArray(KEY_REPLY_ID, replyId.getBytes());
|
||||||
}
|
}
|
||||||
@@ -218,7 +228,6 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
layoutManagerState = savedInstanceState.getParcelable("layoutManager");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -247,11 +256,11 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
updateTextInput();
|
updateTextInput();
|
||||||
// FIXME This does not work for a hardware keyboard
|
// FIXME This does not work for a hardware keyboard
|
||||||
if (textInput.isKeyboardOpen()) {
|
if (textInput.isKeyboardOpen()) {
|
||||||
scrollToItemAtTop(item);
|
scrollToItemAtTop(item.getId());
|
||||||
} else {
|
} else {
|
||||||
// wait with scrolling until keyboard opened
|
// wait with scrolling until keyboard opened
|
||||||
textInput.setOnKeyboardShownListener(() -> {
|
textInput.setOnKeyboardShownListener(() -> {
|
||||||
scrollToItemAtTop(item);
|
scrollToItemAtTop(item.getId());
|
||||||
textInput.setOnKeyboardShownListener(null);
|
textInput.setOnKeyboardShownListener(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -277,11 +286,10 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollToItemAtTop(I item) {
|
private void scrollToItemAtTop(MessageId messageId) {
|
||||||
int position = NO_POSITION;// adapter.findItemPosition(item);
|
int position = adapter.findItemPosition(messageId);
|
||||||
if (position != NO_POSITION) {
|
if (position != NO_POSITION) {
|
||||||
layoutManager
|
layoutManager.scrollToPositionWithOffset(position, 0);
|
||||||
.scrollToPositionWithOffset(position, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,19 +315,7 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
if (isNullOrEmpty(text)) throw new AssertionError();
|
if (isNullOrEmpty(text)) throw new AssertionError();
|
||||||
|
|
||||||
I replyItem = adapter.getHighlightedItem();
|
I replyItem = adapter.getHighlightedItem();
|
||||||
UiResultExceptionHandler<I, DbException> handler =
|
getViewModel().createAndStoreMessage(text, replyItem);
|
||||||
new UiResultExceptionHandler<I, DbException>(this) {
|
|
||||||
@Override
|
|
||||||
public void onResultUi(I result) {
|
|
||||||
addItem(result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onExceptionUi(DbException exception) {
|
|
||||||
handleException(exception);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
getController().createAndStoreMessage(text, replyItem, handler);
|
|
||||||
textInput.hideSoftKeyboard();
|
textInput.hideSoftKeyboard();
|
||||||
textInput.clearText();
|
textInput.clearText();
|
||||||
replyId = null;
|
replyId = null;
|
||||||
@@ -330,7 +326,7 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemReceived(I item) {
|
public void onItemReceived(I item) {
|
||||||
addItem(item, false);
|
getViewModel().addItem(item, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -338,21 +334,4 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
|||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addItem(I item, boolean isLocal) {
|
|
||||||
MessageId parent = item.getParentId();
|
|
||||||
if (parent != null) {
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
// TODO submit new list
|
|
||||||
|
|
||||||
if (isLocal) {
|
|
||||||
scrollToItemAtTop(item);
|
|
||||||
} else {
|
|
||||||
scrollListener.updateUnreadButtons(layoutManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ public interface ThreadListController<I extends ThreadItem>
|
|||||||
|
|
||||||
void markItemsRead(Collection<I> items);
|
void markItemsRead(Collection<I> items);
|
||||||
|
|
||||||
void createAndStoreMessage(String text, @Nullable I parentItem,
|
|
||||||
ResultExceptionHandler<I, DbException> handler);
|
|
||||||
|
|
||||||
interface ThreadListListener<I> extends ThreadListDataSource {
|
interface ThreadListListener<I> extends ThreadListDataSource {
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -17,17 +17,10 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.android.controller.DbControllerImpl;
|
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.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.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -40,39 +33,34 @@ import static org.briarproject.bramble.util.LogUtils.now;
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public abstract class ThreadListControllerImpl<I extends ThreadItem, H extends PostHeader, M extends ThreadedMessage, L extends ThreadListListener<I>>
|
public abstract class ThreadListControllerImpl<I extends ThreadItem>
|
||||||
extends DbControllerImpl
|
extends DbControllerImpl
|
||||||
implements ThreadListController<I>, EventListener {
|
implements ThreadListController<I>, EventListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ThreadListControllerImpl.class.getName());
|
Logger.getLogger(ThreadListControllerImpl.class.getName());
|
||||||
|
|
||||||
private final EventBus eventBus;
|
|
||||||
private final MessageTracker messageTracker;
|
|
||||||
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private volatile GroupId groupId;
|
private volatile GroupId groupId;
|
||||||
|
|
||||||
|
private final EventBus eventBus;
|
||||||
protected final IdentityManager identityManager;
|
protected final IdentityManager identityManager;
|
||||||
protected final AndroidNotificationManager notificationManager;
|
protected final AndroidNotificationManager notificationManager;
|
||||||
protected final Executor cryptoExecutor;
|
protected final Executor cryptoExecutor;
|
||||||
protected final Clock clock;
|
protected final Clock clock;
|
||||||
|
|
||||||
// UI thread
|
// UI thread
|
||||||
protected L listener;
|
protected ThreadListListener<I> listener;
|
||||||
|
|
||||||
protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||||
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
||||||
@CryptoExecutor Executor cryptoExecutor, EventBus eventBus,
|
@CryptoExecutor Executor cryptoExecutor, EventBus eventBus,
|
||||||
Clock clock, AndroidNotificationManager notificationManager,
|
Clock clock, AndroidNotificationManager notificationManager) {
|
||||||
MessageTracker messageTracker) {
|
|
||||||
super(dbExecutor, lifecycleManager);
|
super(dbExecutor, lifecycleManager);
|
||||||
this.identityManager = identityManager;
|
this.identityManager = identityManager;
|
||||||
this.cryptoExecutor = cryptoExecutor;
|
this.cryptoExecutor = cryptoExecutor;
|
||||||
this.notificationManager = notificationManager;
|
this.notificationManager = notificationManager;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.messageTracker = messageTracker;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -84,7 +72,7 @@ public abstract class ThreadListControllerImpl<I extends ThreadItem, H extends P
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void onActivityCreate(Activity activity) {
|
public void onActivityCreate(Activity activity) {
|
||||||
listener = (L) activity;
|
listener = (ThreadListListener<I>) activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@@ -103,16 +91,7 @@ public abstract class ThreadListControllerImpl<I extends ThreadItem, H extends P
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityDestroy() {
|
public void onActivityDestroy() {
|
||||||
MessageId messageId = listener.getFirstVisibleMessageId();
|
|
||||||
if (messageId != null) {
|
|
||||||
dbExecutor.execute(() -> {
|
|
||||||
try {
|
|
||||||
messageTracker.storeMessageId(groupId, messageId);
|
|
||||||
} catch (DbException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@@ -150,27 +129,6 @@ public abstract class ThreadListControllerImpl<I extends ThreadItem, H extends P
|
|||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
protected abstract void markRead(MessageId id) throws DbException;
|
protected abstract void markRead(MessageId id) throws DbException;
|
||||||
|
|
||||||
protected void storePost(M msg, String text,
|
|
||||||
ResultExceptionHandler<I, DbException> 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() {
|
protected GroupId getGroupId() {
|
||||||
checkGroupId();
|
checkGroupId();
|
||||||
return groupId;
|
return groupId;
|
||||||
|
|||||||
@@ -21,28 +21,36 @@ import org.briarproject.briar.android.viewmodel.DbViewModel;
|
|||||||
import org.briarproject.briar.android.viewmodel.LiveResult;
|
import org.briarproject.briar.android.viewmodel.LiveResult;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
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.api.client.PostHeader;
|
||||||
|
import org.briarproject.briar.client.MessageTreeImpl;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public abstract class ThreadListViewModel<I extends ThreadItem> extends DbViewModel
|
public abstract class ThreadListViewModel<I extends ThreadItem>
|
||||||
|
extends DbViewModel
|
||||||
implements EventListener {
|
implements EventListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -55,11 +63,18 @@ public abstract class ThreadListViewModel<I extends ThreadItem> extends DbViewMo
|
|||||||
private final MessageTracker messageTracker;
|
private final MessageTracker messageTracker;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
|
||||||
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
@DatabaseExecutor
|
||||||
|
private final MessageTree<I> messageTree = new MessageTreeImpl<>();
|
||||||
|
protected final Map<MessageId, String> textCache =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
private final MutableLiveData<LiveResult<List<I>>> items =
|
private final MutableLiveData<LiveResult<List<I>>> items =
|
||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
|
private final AtomicReference<MessageId> scrollToItem =
|
||||||
|
new AtomicReference<>();
|
||||||
|
|
||||||
protected volatile GroupId groupId;
|
protected volatile GroupId groupId;
|
||||||
|
private final AtomicReference<MessageId> storedMessageId =
|
||||||
|
new AtomicReference<>();
|
||||||
|
|
||||||
public ThreadListViewModel(Application application,
|
public ThreadListViewModel(Application application,
|
||||||
@DatabaseExecutor Executor dbExecutor,
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
@@ -95,18 +110,37 @@ public abstract class ThreadListViewModel<I extends ThreadItem> extends DbViewMo
|
|||||||
@CallSuper
|
@CallSuper
|
||||||
public void setGroupId(GroupId groupId) {
|
public void setGroupId(GroupId groupId) {
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
|
loadStoredMessageId();
|
||||||
loadItems();
|
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 loadItems();
|
||||||
|
|
||||||
|
public abstract void createAndStoreMessage(String text,
|
||||||
|
@Nullable I parentItem);
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
protected void setItems(LiveResult<List<I>> items) {
|
protected void setItems(LiveResult<List<I>> items) {
|
||||||
this.items.setValue(items);
|
this.items.setValue(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
protected <H extends PostHeader> List<I> buildItems(
|
protected <H extends PostHeader> List<I> recreateItems(
|
||||||
Transaction txn, Collection<H> headers, ItemGetter<H, I> itemGetter)
|
Transaction txn, Collection<H> headers, ItemGetter<H, I> itemGetter)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
long start = now();
|
long start = now();
|
||||||
@@ -122,23 +156,45 @@ public abstract class ThreadListViewModel<I extends ThreadItem> extends DbViewMo
|
|||||||
}
|
}
|
||||||
logDuration(LOG, "Loading bodies and creating items", start);
|
logDuration(LOG, "Loading bodies and creating items", start);
|
||||||
|
|
||||||
MessageId msgId = messageTracker.loadStoredMessageId(txn, groupId);
|
messageTree.clear();
|
||||||
if (LOG.isLoggable(INFO)) {
|
messageTree.add(items);
|
||||||
LOG.info("Loaded last top visible message id " + msgId);
|
return messageTree.depthFirstOrder();
|
||||||
}
|
}
|
||||||
// TODO store this elsewhere
|
|
||||||
items.setFirstVisibleId(msgId);
|
protected void addItem(I item, boolean local) {
|
||||||
return items;
|
messageTree.add(item);
|
||||||
|
if (local) scrollToItem.set(item.getId());
|
||||||
|
items.postValue(new LiveResult<>(messageTree.depthFirstOrder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
protected abstract String loadMessageText(Transaction txn,
|
protected abstract String loadMessageText(Transaction txn,
|
||||||
PostHeader header) throws DbException;
|
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<LiveResult<List<I>>> getItems() {
|
LiveData<LiveResult<List<I>>> getItems() {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
MessageId getAndResetScrollToItem() {
|
||||||
|
return scrollToItem.getAndSet(null);
|
||||||
|
}
|
||||||
|
|
||||||
public interface ItemGetter<H extends PostHeader, I> {
|
public interface ItemGetter<H extends PostHeader, I> {
|
||||||
I getItem(H header, String text);
|
I getItem(H header, String text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,12 @@ public interface MessageTree<T extends MessageTree.MessageNode> {
|
|||||||
|
|
||||||
void add(Collection<T> nodes);
|
void add(Collection<T> nodes);
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
void add(T node);
|
void add(T node);
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
List<T> depthFirstOrder();
|
List<T> depthFirstOrder();
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
boolean contains(MessageId m);
|
boolean contains(MessageId m);
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ public interface ForumManager {
|
|||||||
/**
|
/**
|
||||||
* Returns the group count for the given forum.
|
* Returns the group count for the given forum.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
GroupCount getGroupCount(GroupId g) throws DbException;
|
GroupCount getGroupCount(GroupId g) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -33,11 +33,6 @@ public class MessageTreeImpl<T extends MessageTree.MessageNode>
|
|||||||
private final Comparator<T> comparator = (o1, o2) ->
|
private final Comparator<T> comparator = (o1, o2) ->
|
||||||
Long.valueOf(o1.getTimestamp()).compareTo(o2.getTimestamp());
|
Long.valueOf(o1.getTimestamp()).compareTo(o2.getTimestamp());
|
||||||
|
|
||||||
public MessageTreeImpl(Collection<T> collection) {
|
|
||||||
super();
|
|
||||||
add(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void clear() {
|
public synchronized void clear() {
|
||||||
roots.clear();
|
roots.clear();
|
||||||
|
|||||||
Reference in New Issue
Block a user