mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +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.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<ForumPostItem, ForumPostHeader, ForumPost, ForumListener>
|
||||
class ForumControllerImpl extends ThreadListControllerImpl<ForumPostItem>
|
||||
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<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) {
|
||||
private ForumPostItem buildItem(ForumPostHeader header, String 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.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<ForumPostItem> {
|
||||
List<ForumPostHeader> headers =
|
||||
forumManager.getPostHeaders(txn, groupId);
|
||||
logDuration(LOG, "Loading headers", start);
|
||||
List<ForumPostItem> 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);
|
||||
}
|
||||
|
||||
@@ -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<GroupMessageItem, GroupMessageHeader, GroupMessage, GroupListener>
|
||||
class GroupControllerImpl extends ThreadListControllerImpl<GroupMessageItem>
|
||||
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<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) {
|
||||
private GroupMessageItem buildItem(GroupMessageHeader header, String text) {
|
||||
if (header instanceof JoinMessageHeader) {
|
||||
return new JoinMessageItem((JoinMessageHeader) header, text);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
|
||||
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<GroupMessageItem> {
|
||||
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.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<GroupMessageItem> {
|
||||
List<GroupMessageHeader> headers =
|
||||
privateGroupManager.getHeaders(txn, groupId);
|
||||
logDuration(LOG, "Loading headers", start);
|
||||
List<GroupMessageItem> 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<GroupMessageItem> {
|
||||
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 {
|
||||
|
||||
@@ -66,16 +66,11 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -136,6 +136,12 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
loadSharingContacts();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
getViewModel().storeMessageId(getFirstVisibleMessageId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public MessageId getFirstVisibleMessageId() {
|
||||
@@ -154,21 +160,29 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
if (items.isEmpty()) {
|
||||
list.showData();
|
||||
} else {
|
||||
adapter.submitList(items);
|
||||
// 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);
|
||||
}
|
||||
adapter.submitList(items, this::scrollAfterListCommitted);
|
||||
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() {
|
||||
getController().loadSharingContacts(
|
||||
new UiResultExceptionHandler<Collection<ContactId>, DbException>(
|
||||
@@ -206,10 +220,6 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (layoutManager != null) {
|
||||
layoutManagerState = layoutManager.onSaveInstanceState();
|
||||
outState.putParcelable("layoutManager", layoutManagerState);
|
||||
}
|
||||
if (replyId != null) {
|
||||
outState.putByteArray(KEY_REPLY_ID, replyId.getBytes());
|
||||
}
|
||||
@@ -218,7 +228,6 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
layoutManagerState = savedInstanceState.getParcelable("layoutManager");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,11 +256,11 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
updateTextInput();
|
||||
// FIXME This does not work for a hardware keyboard
|
||||
if (textInput.isKeyboardOpen()) {
|
||||
scrollToItemAtTop(item);
|
||||
scrollToItemAtTop(item.getId());
|
||||
} else {
|
||||
// wait with scrolling until keyboard opened
|
||||
textInput.setOnKeyboardShownListener(() -> {
|
||||
scrollToItemAtTop(item);
|
||||
scrollToItemAtTop(item.getId());
|
||||
textInput.setOnKeyboardShownListener(null);
|
||||
});
|
||||
}
|
||||
@@ -277,11 +286,10 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
}
|
||||
}
|
||||
|
||||
private void scrollToItemAtTop(I item) {
|
||||
int position = NO_POSITION;// adapter.findItemPosition(item);
|
||||
private void scrollToItemAtTop(MessageId messageId) {
|
||||
int position = adapter.findItemPosition(messageId);
|
||||
if (position != NO_POSITION) {
|
||||
layoutManager
|
||||
.scrollToPositionWithOffset(position, 0);
|
||||
layoutManager.scrollToPositionWithOffset(position, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,19 +315,7 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
if (isNullOrEmpty(text)) throw new AssertionError();
|
||||
|
||||
I replyItem = adapter.getHighlightedItem();
|
||||
UiResultExceptionHandler<I, DbException> handler =
|
||||
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);
|
||||
getViewModel().createAndStoreMessage(text, replyItem);
|
||||
textInput.hideSoftKeyboard();
|
||||
textInput.clearText();
|
||||
replyId = null;
|
||||
@@ -330,7 +326,7 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
|
||||
@Override
|
||||
public void onItemReceived(I item) {
|
||||
addItem(item, false);
|
||||
getViewModel().addItem(item, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -338,21 +334,4 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
|
||||
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 createAndStoreMessage(String text, @Nullable I parentItem,
|
||||
ResultExceptionHandler<I, DbException> handler);
|
||||
|
||||
interface ThreadListListener<I> extends ThreadListDataSource {
|
||||
|
||||
@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.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<I extends ThreadItem, H extends PostHeader, M extends ThreadedMessage, L extends ThreadListListener<I>>
|
||||
public abstract class ThreadListControllerImpl<I extends ThreadItem>
|
||||
extends DbControllerImpl
|
||||
implements ThreadListController<I>, EventListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
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 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<I> 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<I extends ThreadItem, H extends P
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onActivityCreate(Activity activity) {
|
||||
listener = (L) activity;
|
||||
listener = (ThreadListListener<I>) activity;
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@@ -103,16 +91,7 @@ public abstract class ThreadListControllerImpl<I extends ThreadItem, H extends P
|
||||
|
||||
@Override
|
||||
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
|
||||
@@ -150,27 +129,6 @@ public abstract class ThreadListControllerImpl<I extends ThreadItem, H extends P
|
||||
@DatabaseExecutor
|
||||
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() {
|
||||
checkGroupId();
|
||||
return groupId;
|
||||
|
||||
@@ -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<I extends ThreadItem> extends DbViewModel
|
||||
public abstract class ThreadListViewModel<I extends ThreadItem>
|
||||
extends DbViewModel
|
||||
implements EventListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
@@ -55,11 +63,18 @@ public abstract class ThreadListViewModel<I extends ThreadItem> extends DbViewMo
|
||||
private final MessageTracker messageTracker;
|
||||
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 =
|
||||
new MutableLiveData<>();
|
||||
private final AtomicReference<MessageId> scrollToItem =
|
||||
new AtomicReference<>();
|
||||
|
||||
protected volatile GroupId groupId;
|
||||
private final AtomicReference<MessageId> storedMessageId =
|
||||
new AtomicReference<>();
|
||||
|
||||
public ThreadListViewModel(Application application,
|
||||
@DatabaseExecutor Executor dbExecutor,
|
||||
@@ -95,18 +110,37 @@ public abstract class ThreadListViewModel<I extends ThreadItem> 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<List<I>> items) {
|
||||
this.items.setValue(items);
|
||||
}
|
||||
|
||||
@DatabaseExecutor
|
||||
protected <H extends PostHeader> List<I> buildItems(
|
||||
protected <H extends PostHeader> List<I> recreateItems(
|
||||
Transaction txn, Collection<H> headers, ItemGetter<H, I> itemGetter)
|
||||
throws DbException {
|
||||
long start = now();
|
||||
@@ -122,23 +156,45 @@ public abstract class ThreadListViewModel<I extends ThreadItem> 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<LiveResult<List<I>>> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
MessageId getAndResetScrollToItem() {
|
||||
return scrollToItem.getAndSet(null);
|
||||
}
|
||||
|
||||
public interface ItemGetter<H extends PostHeader, I> {
|
||||
I getItem(H header, String text);
|
||||
}
|
||||
|
||||
@@ -13,15 +13,12 @@ public interface MessageTree<T extends MessageTree.MessageNode> {
|
||||
|
||||
void add(Collection<T> nodes);
|
||||
|
||||
@Deprecated
|
||||
void add(T node);
|
||||
|
||||
@Deprecated
|
||||
void clear();
|
||||
|
||||
List<T> depthFirstOrder();
|
||||
|
||||
@Deprecated
|
||||
boolean contains(MessageId m);
|
||||
|
||||
@NotNullByDefault
|
||||
|
||||
@@ -109,7 +109,6 @@ public interface ForumManager {
|
||||
/**
|
||||
* Returns the group count for the given forum.
|
||||
*/
|
||||
@Deprecated
|
||||
GroupCount getGroupCount(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,11 +33,6 @@ public class MessageTreeImpl<T extends MessageTree.MessageNode>
|
||||
private final Comparator<T> comparator = (o1, o2) ->
|
||||
Long.valueOf(o1.getTimestamp()).compareTo(o2.getTimestamp());
|
||||
|
||||
public MessageTreeImpl(Collection<T> collection) {
|
||||
super();
|
||||
add(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clear() {
|
||||
roots.clear();
|
||||
|
||||
Reference in New Issue
Block a user