Commit 4e523c5f authored by akwizgran's avatar akwizgran

Merge branch '1242-display-image-attachments' into 'master'

[android] refactor conversation items and view holders

See merge request !984
parents 50cc0a68 3bfa5e20
Pipeline #2743 passed with stage
in 11 minutes and 27 seconds
......@@ -51,7 +51,6 @@ import org.briarproject.briar.R;
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.conversation.ConversationAdapter.ConversationListener;
import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache;
import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.introduction.IntroductionActivity;
......@@ -388,8 +387,8 @@ public class ConversationActivity extends BriarActivity
private void displayMessageText(MessageId m, String text) {
runOnUiThreadUnlessDestroyed(() -> {
textCache.put(m, text);
SparseArray<ConversationItem> messages =
adapter.getPrivateMessages();
SparseArray<ConversationMessageItem> messages =
adapter.getMessageItems();
for (int i = 0; i < messages.size(); i++) {
ConversationItem item = messages.valueAt(i);
if (item.getId().equals(m)) {
......@@ -472,10 +471,9 @@ public class ConversationActivity extends BriarActivity
runOnUiThreadUnlessDestroyed(() -> {
adapter.incrementRevision();
Set<MessageId> messages = new HashSet<>(messageIds);
SparseArray<ConversationOutItem> list =
adapter.getOutgoingMessages();
SparseArray<ConversationItem> list = adapter.getOutgoingMessages();
for (int i = 0; i < list.size(); i++) {
ConversationOutItem item = list.valueAt(i);
ConversationItem item = list.valueAt(i);
if (messages.contains(item.getId())) {
item.setSent(sent);
item.setSeen(seen);
......
......@@ -2,7 +2,6 @@ package org.briarproject.briar.android.conversation;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.UiThread;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
......@@ -14,12 +13,14 @@ import org.briarproject.briar.android.util.BriarAdapter;
import javax.annotation.Nullable;
@NotNullByDefault
class ConversationAdapter
extends BriarAdapter<ConversationItem, ConversationItemViewHolder> {
private ConversationListener listener;
ConversationAdapter(Context ctx, ConversationListener conversationListener) {
ConversationAdapter(Context ctx,
ConversationListener conversationListener) {
super(ctx, ConversationItem.class);
listener = conversationListener;
}
......@@ -38,15 +39,15 @@ class ConversationAdapter
type, viewGroup, false);
switch (type) {
case R.layout.list_item_conversation_msg_in:
return new ConversationItemViewHolder(v);
return new ConversationMessageViewHolder(v, true);
case R.layout.list_item_conversation_msg_out:
return new ConversationMessageOutViewHolder(v);
return new ConversationMessageViewHolder(v, false);
case R.layout.list_item_conversation_notice_in:
return new ConversationNoticeInViewHolder(v);
return new ConversationNoticeViewHolder(v, true);
case R.layout.list_item_conversation_notice_out:
return new ConversationNoticeOutViewHolder(v);
return new ConversationNoticeViewHolder(v, false);
case R.layout.list_item_conversation_request:
return new ConversationRequestViewHolder(v);
return new ConversationRequestViewHolder(v, true);
default:
throw new IllegalArgumentException("Unknown ConversationItem");
}
......@@ -55,22 +56,13 @@ class ConversationAdapter
@Override
public void onBindViewHolder(ConversationItemViewHolder ui, int position) {
ConversationItem item = items.get(position);
if (item instanceof ConversationRequestItem) {
((ConversationRequestViewHolder) ui).bind(item, listener);
} else {
ui.bind(item);
}
ui.bind(item, listener);
listener.onItemVisible(item);
}
@Override
public int compare(ConversationItem c1,
ConversationItem c2) {
long time1 = c1.getTime();
long time2 = c2.getTime();
if (time1 < time2) return -1;
if (time1 > time2) return 1;
return 0;
public int compare(ConversationItem c1, ConversationItem c2) {
return Long.compare(c1.getTime(), c2.getTime());
}
@Override
......@@ -94,54 +86,28 @@ class ConversationAdapter
}
}
SparseArray<ConversationItem> getIncomingMessages() {
SparseArray<ConversationItem> getOutgoingMessages() {
SparseArray<ConversationItem> messages = new SparseArray<>();
for (int i = 0; i < items.size(); i++) {
ConversationItem item = items.get(i);
if (item.isIncoming()) {
if (!item.isIncoming()) {
messages.put(i, item);
}
}
return messages;
}
SparseArray<ConversationOutItem> getOutgoingMessages() {
SparseArray<ConversationOutItem> messages = new SparseArray<>();
for (int i = 0; i < items.size(); i++) {
ConversationItem item = items.get(i);
if (item instanceof ConversationOutItem) {
messages.put(i, (ConversationOutItem) item);
}
}
return messages;
}
SparseArray<ConversationItem> getPrivateMessages() {
SparseArray<ConversationItem> messages = new SparseArray<>();
SparseArray<ConversationMessageItem> getMessageItems() {
SparseArray<ConversationMessageItem> messages = new SparseArray<>();
for (int i = 0; i < items.size(); i++) {
ConversationItem item = items.get(i);
if (item instanceof ConversationMessageInItem) {
messages.put(i, item);
} else if (item instanceof ConversationMessageOutItem) {
messages.put(i, item);
if (item instanceof ConversationMessageItem) {
messages.put(i, (ConversationMessageItem) item);
}
}
return messages;
}
@UiThread
@NotNullByDefault
interface ConversationListener {
void onItemVisible(ConversationItem item);
void respondToRequest(ConversationRequestItem item, boolean accept);
void openRequestedShareable(ConversationRequestItem item);
}
}
......@@ -5,6 +5,7 @@ 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.conversation.ConversationMessageHeader;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
......@@ -13,20 +14,31 @@ import javax.annotation.concurrent.NotThreadSafe;
@NotNullByDefault
abstract class ConversationItem {
@LayoutRes
private final int layoutRes;
@Nullable
protected String text;
private final MessageId id;
private final GroupId groupId;
private final long time;
private boolean read;
private final boolean isIncoming;
private boolean read, sent, seen;
ConversationItem(MessageId id, GroupId groupId, @Nullable String text,
long time, boolean read) {
this.id = id;
this.groupId = groupId;
this.text = text;
this.time = time;
this.read = read;
ConversationItem(@LayoutRes int layoutRes, ConversationMessageHeader h) {
this.layoutRes = layoutRes;
this.text = null;
this.id = h.getId();
this.groupId = h.getGroupId();
this.time = h.getTimestamp();
this.read = h.isRead();
this.sent = h.isSent();
this.seen = h.isSeen();
this.isIncoming = !h.isLocal();
}
@LayoutRes
int getLayout() {
return layoutRes;
}
MessageId getId() {
......@@ -42,7 +54,7 @@ abstract class ConversationItem {
}
@Nullable
public String getText() {
String getText() {
return text;
}
......@@ -50,12 +62,43 @@ abstract class ConversationItem {
return time;
}
public boolean isRead() {
/**
* Only useful for incoming messages.
*/
boolean isRead() {
return read;
}
abstract public boolean isIncoming();
/**
* Only useful for outgoing messages.
*/
boolean isSent() {
return sent;
}
/**
* Only useful for outgoing messages.
*/
void setSent(boolean sent) {
this.sent = sent;
}
/**
* Only useful for outgoing messages.
*/
boolean isSeen() {
return seen;
}
/**
* Only useful for outgoing messages.
*/
void setSeen(boolean seen) {
this.seen = seen;
}
boolean isIncoming() {
return isIncoming;
}
@LayoutRes
abstract public int getLayout();
}
package org.briarproject.briar.android.conversation;
import android.support.annotation.CallSuper;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
......@@ -8,35 +9,45 @@ import android.view.ViewGroup;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.util.UiUtils;
import static org.briarproject.bramble.util.StringUtils.trim;
import static org.briarproject.briar.android.util.UiUtils.formatDate;
@UiThread
@NotNullByDefault
class ConversationItemViewHolder extends ViewHolder {
abstract class ConversationItemViewHolder extends ViewHolder {
protected final ViewGroup layout;
@Nullable
private final OutItemViewHolder outViewHolder;
private final TextView text;
private final TextView time;
ConversationItemViewHolder(View v) {
ConversationItemViewHolder(View v, boolean isIncoming) {
super(v);
this.outViewHolder = isIncoming ? null : new OutItemViewHolder(v);
layout = v.findViewById(R.id.layout);
text = v.findViewById(R.id.text);
time = v.findViewById(R.id.time);
}
@CallSuper
void bind(ConversationItem item) {
void bind(ConversationItem item, ConversationListener listener) {
if (item.getText() == null) {
text.setText("\u2026");
} else {
text.setText(StringUtils.trim(item.getText()));
text.setText(trim(item.getText()));
}
long timestamp = item.getTime();
time.setText(UiUtils.formatDate(time.getContext(), timestamp));
time.setText(formatDate(time.getContext(), timestamp));
if (outViewHolder != null) outViewHolder.bind(item);
}
boolean isIncoming() {
return outViewHolder == null;
}
}
package org.briarproject.briar.android.conversation;
import android.support.annotation.UiThread;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@UiThread
@NotNullByDefault
interface ConversationListener {
void onItemVisible(ConversationItem item);
void respondToRequest(ConversationRequestItem item, boolean accept);
void openRequestedShareable(ConversationRequestItem item);
}
......@@ -3,28 +3,26 @@ package org.briarproject.briar.android.conversation;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.api.messaging.AttachmentHeader;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationMessageInItem extends ConversationItem {
class ConversationMessageItem extends ConversationItem {
ConversationMessageInItem(PrivateMessageHeader h) {
super(h.getId(), h.getGroupId(), null, h.getTimestamp(), h.isRead());
}
private final List<AttachmentHeader> attachments;
@Override
public boolean isIncoming() {
return true;
ConversationMessageItem(@LayoutRes int layoutRes, PrivateMessageHeader h) {
super(layoutRes, h);
this.attachments = h.getAttachmentHeaders();
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_msg_in;
List<AttachmentHeader> getAttachments() {
return attachments;
}
}
package org.briarproject.briar.android.conversation;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationMessageOutItem extends ConversationOutItem {
ConversationMessageOutItem(PrivateMessageHeader h) {
super(h.getId(), h.getGroupId(), null, h.getTimestamp(), h.isSent(),
h.isSeen());
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_msg_out;
}
}
package org.briarproject.briar.android.conversation;
import android.view.View;
class ConversationMessageOutViewHolder extends ConversationOutItemViewHolder {
ConversationMessageOutViewHolder(View v) {
super(v);
}
@Override
protected boolean hasDarkBackground() {
return true;
}
}
package org.briarproject.briar.android.conversation;
import android.support.annotation.UiThread;
import android.view.View;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@UiThread
@NotNullByDefault
class ConversationMessageViewHolder extends ConversationItemViewHolder {
// image support will be added here (#1242)
ConversationMessageViewHolder(View v, boolean isIncoming) {
super(v, isIncoming);
}
}
package org.briarproject.briar.android.conversation;
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.R;
import org.briarproject.briar.api.conversation.ConversationResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationNoticeInItem extends ConversationItem {
@Nullable
private final String msgText;
ConversationNoticeInItem(MessageId id, GroupId groupId, String text,
@Nullable String msgText, long time, boolean read) {
super(id, groupId, text, time, read);
this.msgText = msgText;
}
ConversationNoticeInItem(String text, ConversationResponse r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isRead());
this.msgText = null;
}
@Nullable
String getMsgText() {
return msgText;
}
@Override
public boolean isIncoming() {
return true;
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_notice_in;
}
}
package org.briarproject.briar.android.conversation;
import android.support.annotation.UiThread;
import android.view.View;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@UiThread
@NotNullByDefault
class ConversationNoticeInViewHolder extends ConversationItemViewHolder {
private final TextView msgText;
ConversationNoticeInViewHolder(View v) {
super(v);
msgText = v.findViewById(R.id.msgText);
}
@Override
void bind(ConversationItem conversationItem) {
super.bind(conversationItem);
ConversationNoticeInItem item =
(ConversationNoticeInItem) conversationItem;
String text = item.getMsgText();
if (StringUtils.isNullOrEmpty(text)) {
msgText.setVisibility(GONE);
layout.setBackgroundResource(R.drawable.notice_in);
} else {
msgText.setVisibility(VISIBLE);
msgText.setText(StringUtils.trim(text));
layout.setBackgroundResource(R.drawable.notice_in_bottom);
}
}
}
......@@ -3,7 +3,6 @@ package org.briarproject.briar.android.conversation;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.api.conversation.ConversationRequest;
import org.briarproject.briar.api.conversation.ConversationResponse;
......@@ -12,20 +11,22 @@ import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class ConversationNoticeOutItem extends ConversationOutItem {
class ConversationNoticeItem extends ConversationItem {
@Nullable
private final String msgText;
ConversationNoticeOutItem(String text, ConversationRequest r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
r.isSeen());
ConversationNoticeItem(@LayoutRes int layoutRes, String text,
ConversationRequest r) {
super(layoutRes, r);
this.text = text;
this.msgText = r.getText();
}
ConversationNoticeOutItem(String text, ConversationResponse r) {
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
r.isSeen());
ConversationNoticeItem(@LayoutRes int layoutRes, String text,
ConversationResponse r) {
super(layoutRes, r);
this.text = text;
this.msgText = null;
}
......@@ -34,9 +35,4 @@ class ConversationNoticeOutItem extends ConversationOutItem {
return msgText;
}
@LayoutRes
@Override
public int getLayout() {
return R.layout.list_item_conversation_notice_out;
}
}
package org.briarproject.briar.android.conversation;
import android.support.annotation.CallSuper;
import android.support.annotation.UiThread;
import android.view.View;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
import static org.briarproject.bramble.util.StringUtils.trim;
@UiThread
@NotNullByDefault
class ConversationNoticeOutViewHolder extends ConversationOutItemViewHolder {
class ConversationNoticeViewHolder extends ConversationItemViewHolder {
private final TextView msgText;
ConversationNoticeOutViewHolder(View v) {
super(v);
ConversationNoticeViewHolder(View v, boolean isIncoming) {
super(v, isIncoming);
msgText = v.findViewById(R.id.msgText);
}
@Override
void bind(ConversationItem conversationItem) {
super.bind(conversationItem);
@CallSuper
void bind(ConversationItem item, ConversationListener listener) {
ConversationNoticeItem notice = (ConversationNoticeItem) item;
super.bind(notice, listener);
ConversationNoticeOutItem item =
(ConversationNoticeOutItem) conversationItem;
String text = item.getMsgText();
if (StringUtils.isNullOrEmpty(text)) {
String text = notice.getMsgText();
if (isNullOrEmpty(text)) {
msgText.setVisibility(GONE);
layout.setBackgroundResource(R.drawable.notice_out);
layout.setBackgroundResource(isIncoming() ? R.drawable.notice_in :
R.drawable.notice_out);
} else {
msgText.setVisibility(VISIBLE);
msgText.setText(StringUtils.trim(text));
layout.setBackgroundResource(R.drawable.notice_out_bottom);
msgText.setText(trim(text));
layout.setBackgroundResource(isIncoming() ?
R.drawable.notice_in_bottom : R.drawable.notice_out_bottom);
}
}