Commit 0491c3ca authored by akwizgran's avatar akwizgran

Use a visitor to create ConversationItems.

parent 2e120f75
package org.briarproject.briar.android.contact;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
......@@ -48,6 +47,7 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static android.os.Build.VERSION.SDK_INT;
import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAnimation;
import static android.support.v4.view.ViewCompat.getTransitionName;
import static java.util.logging.Level.WARNING;
......@@ -113,7 +113,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
ContactId contactId = item.getContact().getId();
i.putExtra(CONTACT_ID, contactId.getInt());
if (Build.VERSION.SDK_INT >= 23) {
if (SDK_INT >= 23) {
ContactListItemViewHolder holder =
(ContactListItemViewHolder) list
.getRecyclerView()
......@@ -256,8 +256,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
int position = adapter.findItemPosition(c);
ContactListItem item = adapter.getItemAt(position);
if (item != null) {
ConversationItem i = ConversationItem.from(getContext(), "", h);
item.addMessage(i);
item.addMessage(h);
adapter.updateItemAt(position, item);
}
});
......
......@@ -3,6 +3,7 @@ package org.briarproject.briar.android.contact;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import javax.annotation.concurrent.NotThreadSafe;
......@@ -22,11 +23,10 @@ public class ContactListItem extends ContactItem {
this.timestamp = count.getLatestMsgTime();
}
void addMessage(ConversationItem message) {
void addMessage(PrivateMessageHeader h) {
empty = false;
if (message.getTime() > timestamp) timestamp = message.getTime();
if (!message.isRead())
unread++;
if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp();
if (!h.isRead()) unread++;
}
boolean isEmpty() {
......
......@@ -53,6 +53,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.blog.BlogActivity;
import org.briarproject.briar.android.contact.ConversationAdapter.ConversationListener;
import org.briarproject.briar.android.contact.ConversationVisitor.BodyCache;
import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.introduction.IntroductionActivity;
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
......@@ -111,7 +112,8 @@ import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.S
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class ConversationActivity extends BriarActivity
implements EventListener, ConversationListener, TextInputListener {
implements EventListener, ConversationListener, TextInputListener,
BodyCache {
public static final String CONTACT_ID = "briar.CONTACT_ID";
......@@ -131,6 +133,7 @@ public class ConversationActivity extends BriarActivity
private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
private final MutableLiveData<String> contactName = new MutableLiveData<>();
private ConversationVisitor visitor;
private ConversationAdapter adapter;
private Toolbar toolbar;
private CircleImageView toolbarAvatar;
......@@ -191,6 +194,7 @@ public class ConversationActivity extends BriarActivity
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
visitor = new ConversationVisitor(this, this, contactName);
adapter = new ConversationAdapter(this, this);
list = findViewById(R.id.conversationView);
list.setLayoutManager(new LinearLayoutManager(this));
......@@ -362,18 +366,7 @@ public class ConversationActivity extends BriarActivity
private List<ConversationItem> createItems(
Collection<PrivateMessageHeader> headers) {
List<ConversationItem> items = new ArrayList<>(headers.size());
for (PrivateMessageHeader h : headers) {
ConversationItem item;
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
item = ConversationItem.from(this, contactName.getValue(), h);
} else {
item = ConversationItem.from(h);
String body = bodyCache.get(h.getId());
if (body == null) loadMessageBody(h.getId());
else item.setBody(body);
}
items.add(item);
}
for (PrivateMessageHeader h : headers) items.add(h.accept(visitor));
return items;
}
......@@ -467,27 +460,21 @@ public class ConversationActivity extends BriarActivity
@Override
public void onChanged(@Nullable String cName) {
if (cName != null) {
onNewPrivateRequestOrResponse(h, cName);
addConversationItem(h.accept(visitor));
contactName.removeObserver(this);
}
}
});
} else {
onNewPrivateRequestOrResponse(h, cName);
addConversationItem(h.accept(visitor));
}
} else {
addConversationItem(ConversationItem.from(h));
addConversationItem(h.accept(visitor));
loadMessageBody(h.getId());
}
});
}
@UiThread
private void onNewPrivateRequestOrResponse(PrivateMessageHeader h,
String cName) {
addConversationItem(ConversationItem.from(this, cName, h));
}
private void markMessages(Collection<MessageId> messageIds, boolean sent,
boolean seen) {
runOnUiThreadUnlessDestroyed(() -> {
......@@ -558,10 +545,8 @@ public class ConversationActivity extends BriarActivity
PrivateMessageHeader h = new PrivateMessageHeader(
message.getId(), message.getGroupId(),
message.getTimestamp(), true, false, false, false);
ConversationItem item = ConversationItem.from(h);
item.setBody(body);
bodyCache.put(message.getId(), body);
addConversationItem(item);
addConversationItem(h.accept(visitor));
} catch (DbException e) {
logException(LOG, WARNING, e);
}
......@@ -773,4 +758,12 @@ public class ConversationActivity extends BriarActivity
throws DbException {
groupInvitationManager.respondToInvitation(contactId, id, accept);
}
@Nullable
@Override
public String getBody(MessageId m) {
String body = bodyCache.get(m);
if (body == null) loadMessageBody(m);
return body;
}
}
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
......@@ -62,48 +58,4 @@ abstract class ConversationItem {
@LayoutRes
abstract public int getLayout();
static ConversationItem from(PrivateMessageHeader h) {
if (h.isLocal()) {
return new ConversationMessageOutItem(h);
} else {
return new ConversationMessageInItem(h);
}
}
static ConversationItem from(Context ctx, String contactName,
PrivateMessageHeader h) {
if (h.isLocal()) {
return fromLocal(ctx, contactName, h);
} else {
return fromRemote(ctx, contactName, h);
}
}
private static ConversationItem fromLocal(Context ctx, String contactName,
PrivateMessageHeader h) {
if (h instanceof PrivateRequest) {
PrivateRequest r = (PrivateRequest) h;
return new ConversationNoticeOutItem(ctx, contactName, r);
} else if (h instanceof PrivateResponse) {
PrivateResponse r = (PrivateResponse) h;
return new ConversationNoticeOutItem(ctx, contactName, r);
} else {
return new ConversationMessageOutItem(h);
}
}
private static ConversationItem fromRemote(Context ctx, String contactName,
PrivateMessageHeader h) {
if (h instanceof PrivateRequest) {
PrivateRequest r = (PrivateRequest) h;
return new ConversationRequestItem(ctx, contactName, r);
} else if (h instanceof PrivateResponse) {
PrivateResponse r = (PrivateResponse) h;
return new ConversationNoticeInItem(ctx, contactName, r);
} else {
return new ConversationMessageInItem(h);
}
}
}
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
......@@ -24,17 +18,14 @@ class ConversationNoticeInItem extends ConversationItem {
@Nullable
private final String msgText;
ConversationNoticeInItem(MessageId id, GroupId groupId,
String text, @Nullable String msgText, long time,
boolean read) {
ConversationNoticeInItem(MessageId id, GroupId groupId, String text,
@Nullable String msgText, long time, boolean read) {
super(id, groupId, text, time, read);
this.msgText = msgText;
}
public ConversationNoticeInItem(Context ctx, String contactName,
PrivateResponse r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isRead());
ConversationNoticeInItem(String text, PrivateResponse r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isRead());
this.msgText = null;
}
......@@ -53,55 +44,4 @@ class ConversationNoticeInItem extends ConversationItem {
public int getLayout() {
return R.layout.list_item_conversation_notice_in;
}
private static String getText(Context ctx, String contactName,
PrivateResponse r) {
if (r.wasAccepted()) {
if (r instanceof IntroductionResponse) {
IntroductionResponse ir = (IntroductionResponse) r;
return ctx.getString(
R.string.introduction_response_accepted_received,
contactName, ir.getIntroducedAuthor().getName());
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(
R.string.forum_invitation_response_accepted_received,
contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(
R.string.blogs_sharing_response_accepted_received,
contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(
R.string.groups_invitations_response_accepted_received,
contactName);
}
} else {
if (r instanceof IntroductionResponse) {
IntroductionResponse ir = (IntroductionResponse) r;
@StringRes int res;
if (ir.isIntroducer()) {
res = R.string.introduction_response_declined_received;
} else {
res =
R.string.introduction_response_declined_received_by_introducee;
}
return ctx.getString(res, contactName,
ir.getIntroducedAuthor().getName());
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(
R.string.forum_invitation_response_declined_received,
contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(
R.string.blogs_sharing_response_declined_received,
contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(
R.string.groups_invitations_response_declined_received,
contactName);
}
}
throw new IllegalArgumentException("Unknown PrivateResponse");
}
}
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
......@@ -26,17 +17,15 @@ class ConversationNoticeOutItem extends ConversationOutItem {
@Nullable
private final String msgText;
ConversationNoticeOutItem(Context ctx, String contactName,
PrivateRequest r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isSent(), r.isSeen());
ConversationNoticeOutItem(String text, PrivateRequest r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
r.isSeen());
this.msgText = r.getMessage();
}
ConversationNoticeOutItem(Context ctx, String contactName,
PrivateResponse r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isSent(), r.isSeen());
ConversationNoticeOutItem(String text, PrivateResponse r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
r.isSeen());
this.msgText = null;
}
......@@ -50,58 +39,4 @@ class ConversationNoticeOutItem extends ConversationOutItem {
public int getLayout() {
return R.layout.list_item_conversation_notice_out;
}
private static String getText(Context ctx, String contactName,
PrivateRequest r) {
if (r instanceof IntroductionRequest) {
return ctx.getString(R.string.introduction_request_sent,
contactName, r.getName());
} else if (r instanceof ForumInvitationRequest) {
return ctx.getString(R.string.forum_invitation_sent,
r.getName(), contactName);
} else if (r instanceof BlogInvitationRequest) {
return ctx.getString(R.string.blogs_sharing_invitation_sent,
r.getName(), contactName);
} else if (r instanceof GroupInvitationRequest) {
return ctx.getString(R.string.groups_invitations_invitation_sent,
contactName, r.getName());
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
private static String getText(Context ctx, String contactName,
PrivateResponse r) {
if (r.wasAccepted()) {
if (r instanceof IntroductionResponse) {
String name = ((IntroductionResponse) r).getIntroducedAuthor()
.getName();
return ctx.getString(
R.string.introduction_response_accepted_sent,
name) + "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
name);
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(R.string.forum_invitation_response_accepted_sent, contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(R.string.blogs_sharing_response_accepted_sent, contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(R.string.groups_invitations_response_accepted_sent, contactName);
}
} else {
if (r instanceof IntroductionResponse) {
String name = ((IntroductionResponse) r).getIntroducedAuthor()
.getName();
return ctx.getString(
R.string.introduction_response_declined_sent, name);
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(R.string.forum_invitation_response_declined_sent, contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(R.string.blogs_sharing_response_declined_sent, contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(R.string.groups_invitations_response_declined_sent, contactName);
}
}
throw new IllegalArgumentException("Unknown PrivateResponse");
}
}
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.Shareable;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
@NotThreadSafe
@NotNullByDefault
class ConversationRequestItem extends ConversationNoticeInItem {
enum RequestType { INTRODUCTION, FORUM, BLOG, GROUP }
enum RequestType {INTRODUCTION, FORUM, BLOG, GROUP}
@Nullable
private final GroupId requestedGroupId;
......@@ -36,11 +26,10 @@ class ConversationRequestItem extends ConversationNoticeInItem {
private final boolean canBeOpened;
private boolean answered;
ConversationRequestItem(Context ctx, String contactName,
PrivateRequest r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getMessage(), r.getTimestamp(), r.isRead());
this.requestType = getType(r);
ConversationRequestItem(String text, RequestType type, PrivateRequest r) {
super(r.getId(), r.getGroupId(), text, r.getMessage(),
r.getTimestamp(), r.isRead());
this.requestType = type;
this.sessionId = r.getSessionId();
this.answered = r.wasAnswered();
if (r instanceof InvitationRequest) {
......@@ -82,47 +71,4 @@ class ConversationRequestItem extends ConversationNoticeInItem {
public int getLayout() {
return R.layout.list_item_conversation_request;
}
private static String getText(Context ctx, String contactName,
PrivateRequest r) {
if (r instanceof IntroductionRequest) {
if (r.wasAnswered()) {
return ctx.getString(
R.string.introduction_request_answered_received,
contactName, r.getName());
} else if (((IntroductionRequest) r).isContact()) {
return ctx.getString(
R.string.introduction_request_exists_received,
contactName, r.getName());
} else {
return ctx.getString(R.string.introduction_request_received,
contactName, r.getName());
}
} else if (r instanceof ForumInvitationRequest) {
return ctx.getString(R.string.forum_invitation_received,
contactName, r.getName());
} else if (r instanceof BlogInvitationRequest) {
return ctx.getString(R.string.blogs_sharing_invitation_received,
contactName, r.getName());
} else if (r instanceof GroupInvitationRequest) {
return ctx.getString(
R.string.groups_invitations_invitation_received,
contactName, r.getName());
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
private static RequestType getType(PrivateRequest r) {
if (r instanceof IntroductionRequest) {
return INTRODUCTION;
} else if (r instanceof ForumInvitationRequest) {
return FORUM;
} else if (r instanceof BlogInvitationRequest) {
return BLOG;
} else if (r instanceof GroupInvitationRequest) {
return GROUP;
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
}
package org.briarproject.briar.android.contact;
import android.arch.lifecycle.LiveData;
import android.content.Context;
import android.support.annotation.UiThread;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
@UiThread
@NotNullByDefault
class ConversationVisitor implements PrivateMessageVisitor<ConversationItem> {
private final Context ctx;
private final BodyCache bodyCache;
private final LiveData<String> contactName;
ConversationVisitor(Context ctx, BodyCache bodyCache,
LiveData<String> contactName) {
this.ctx = ctx;
this.bodyCache = bodyCache;
this.contactName = contactName;
}
@Override
public ConversationItem visitPrivateMessageHeader(PrivateMessageHeader h) {
ConversationItem item;
if (h.isLocal()) item = new ConversationMessageOutItem(h);
else item = new ConversationMessageInItem(h);
String body = bodyCache.getBody(h.getId());
if (body != null) item.setBody(body);
return item;
}
@Override
public ConversationItem visitBlogInvitationRequest(
BlogInvitationRequest r) {
if (r.isLocal()) {
String text = ctx.getString(R.string.blogs_sharing_invitation_sent,
r.getName(), contactName.getValue());
return new ConversationNoticeOutItem(text, r);
} else {
String text = ctx.getString(
R.string.blogs_sharing_invitation_received,
contactName.getValue(), r.getName());
return new ConversationRequestItem(text, BLOG, r);
}
}
@Override
public ConversationItem visitBlogInvitationResponse(
BlogInvitationResponse r) {
if (r.isLocal()) {
String text;
if (r.wasAccepted()) {
text = ctx.getString(
R.string.blogs_sharing_response_accepted_sent,
contactName.getValue());
} else {
text = ctx.getString(
R.string.blogs_sharing_response_declined_sent,
contactName.getValue());
}
return new ConversationNoticeOutItem(text, r);
} else {
String text;
if (r.wasAccepted()) {
text = ctx.getString(
R.string.blogs_sharing_response_accepted_received,
contactName.getValue());
} else {
text = ctx.getString(
R.string.blogs_sharing_response_declined_received,
contactName.getValue());
}
return new ConversationNoticeInItem(text, r);
}
}
@Override
public ConversationItem visitForumInvitationRequest(
ForumInvitationRequest r) {
if (r.isLocal()) {
String text = ctx.getString(R.string.forum_invitation_sent,
r.getName(), contactName.getValue());
return new ConversationNoticeOutItem(text, r);
} else {
String text = ctx.getString(
R.string.forum_invitation_received,
contactName.getValue(), r.getName());
return new ConversationRequestItem(text, FORUM, r);
}
}
@Override
public ConversationItem visitForumInvitationResponse(
ForumInvitationResponse r) {
if (r.isLocal()) {
String text;
if (r.wasAccepted()) {
text = ctx.getString(
R.string.forum_invitation_response_accepted_sent,
contactName.getValue());
} else {
text = ctx.getString(
R.string.forum_invitation_response_declined_sent,
contactName.getValue());
}
return new ConversationNoticeOutItem(text, r);
} else {
String text;
if (r.wasAccepted()) {
text = ctx.getString(
R.string.forum_invitation_response_accepted_received,
contactName.getValue());
} else {