mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 11:19:04 +01:00
Forum Sharing Client UI
This changes `ShareForumActivity` to use two fragments to facilitate forum sharing with the new Forum Sharing Client backend. The `ContactSelectorFragment` allows the user to select a number of contacts. If there is an ongoing sharing session or the forum is already shared with the contact, it is disabled in the list. If there is at least one contact selected, a button appears in the toolbar that brings the user to the `ShareForumMessageFragment` where the user can write an optional message to be send along with the invitation. After sending an invitation, the user is brought back to the forum that she shared and there is a snackbar showing up briefly to indicate the successful invitation. The invitation is shown along with the message within the private conversation of each contact. The person who shares the forum also sees the invitation and the message as outgoing messages that also display the current status of the messages. A notification is shown like for other private messages as well. Please note that this commit does not include a way for users to respond to invitations.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.format.DateUtils;
|
||||
@@ -13,8 +14,10 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.api.introduction.IntroductionRequest;
|
||||
import org.briarproject.android.forum.AvailableForumsActivity;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||
import org.briarproject.api.introduction.IntroductionRequest;
|
||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
@@ -22,6 +25,8 @@ import java.util.List;
|
||||
|
||||
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||
import static android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import static org.briarproject.android.contact.ConversationItem.FORUM_INVITATION_IN;
|
||||
import static org.briarproject.android.contact.ConversationItem.FORUM_INVITATION_OUT;
|
||||
import static org.briarproject.android.contact.ConversationItem.INTRODUCTION_IN;
|
||||
import static org.briarproject.android.contact.ConversationItem.INTRODUCTION_OUT;
|
||||
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
|
||||
@@ -35,50 +40,7 @@ import static org.briarproject.android.contact.ConversationItem.OutgoingItem;
|
||||
class ConversationAdapter extends RecyclerView.Adapter {
|
||||
|
||||
private final SortedList<ConversationItem> items =
|
||||
new SortedList<ConversationItem>(ConversationItem.class,
|
||||
new SortedList.Callback<ConversationItem>() {
|
||||
@Override
|
||||
public void onInserted(int position, int count) {
|
||||
notifyItemRangeInserted(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(int position, int count) {
|
||||
notifyItemRangeChanged(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoved(int fromPosition, int toPosition) {
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(int position, int count) {
|
||||
notifyItemRangeRemoved(position, count);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(ConversationItem c1,
|
||||
ConversationItem c2) {
|
||||
return c1.getId().equals(c2.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(ConversationItem c1,
|
||||
ConversationItem c2) {
|
||||
return c1.equals(c2);
|
||||
}
|
||||
});
|
||||
new SortedList<>(ConversationItem.class, new ListCallbacks());
|
||||
private Context ctx;
|
||||
private IntroductionHandler intro;
|
||||
private String contactName;
|
||||
@@ -129,6 +91,16 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
.inflate(R.layout.list_item_notice_out, viewGroup, false);
|
||||
return new NoticeHolder(v, type);
|
||||
}
|
||||
else if (type == FORUM_INVITATION_IN) {
|
||||
v = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.list_item_forum_invitation_in, viewGroup, false);
|
||||
return new InvitationHolder(v, type);
|
||||
}
|
||||
else if (type == FORUM_INVITATION_OUT) {
|
||||
v = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.list_item_forum_invitation_out, viewGroup, false);
|
||||
return new InvitationHolder(v, type);
|
||||
}
|
||||
// incoming message (non-local)
|
||||
else {
|
||||
v = LayoutInflater.from(viewGroup.getContext())
|
||||
@@ -152,6 +124,12 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
bindNotice((NoticeHolder) ui, (ConversationNoticeOutItem) item);
|
||||
} else if (item instanceof ConversationNoticeInItem) {
|
||||
bindNotice((NoticeHolder) ui, (ConversationNoticeInItem) item);
|
||||
} else if (item instanceof ConversationForumInvitationOutItem) {
|
||||
bindInvitation((InvitationHolder) ui,
|
||||
(ConversationForumInvitationOutItem) item, position);
|
||||
} else if (item instanceof ConversationForumInvitationInItem) {
|
||||
bindInvitation((InvitationHolder) ui,
|
||||
(ConversationForumInvitationInItem) item, position);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unhandled Conversation Item");
|
||||
}
|
||||
@@ -204,7 +182,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
|
||||
final IntroductionRequest ir = item.getIntroductionRequest();
|
||||
|
||||
final String message = ir.getMessage();
|
||||
String message = ir.getMessage();
|
||||
if (StringUtils.isNullOrEmpty(message)) {
|
||||
ui.messageLayout.setVisibility(View.GONE);
|
||||
} else {
|
||||
@@ -300,6 +278,63 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void bindInvitation(InvitationHolder ui,
|
||||
final ConversationForumInvitationItem item, final int position) {
|
||||
|
||||
ForumInvitationMessage fim = item.getForumInvitationMessage();
|
||||
|
||||
String message = fim.getMessage();
|
||||
if (StringUtils.isNullOrEmpty(message)) {
|
||||
ui.messageLayout.setVisibility(View.GONE);
|
||||
} else {
|
||||
ui.messageLayout.setVisibility(View.VISIBLE);
|
||||
ui.message.body.setText(message);
|
||||
ui.message.date.setText(
|
||||
DateUtils.getRelativeTimeSpanString(ctx, item.getTime()));
|
||||
}
|
||||
|
||||
// Outgoing Invitation
|
||||
if (item instanceof ConversationForumInvitationOutItem) {
|
||||
ui.text.setText(ctx.getString(R.string.forum_invitation_sent,
|
||||
fim.getForumName(), contactName));
|
||||
ConversationForumInvitationOutItem i =
|
||||
(ConversationForumInvitationOutItem) item;
|
||||
if (i.isSeen()) {
|
||||
ui.status.setImageResource(R.drawable.message_delivered);
|
||||
ui.message.status.setImageResource(R.drawable.message_delivered_white);
|
||||
} else if (i.isSent()) {
|
||||
ui.status.setImageResource(R.drawable.message_sent);
|
||||
ui.message.status.setImageResource(R.drawable.message_sent_white);
|
||||
} else {
|
||||
ui.status.setImageResource(R.drawable.message_stored);
|
||||
ui.message.status.setImageResource(R.drawable.message_stored_white);
|
||||
}
|
||||
}
|
||||
// Incoming Invitation
|
||||
else {
|
||||
ui.text.setText(ctx.getString(R.string.forum_invitation_received,
|
||||
contactName, fim.getForumName()));
|
||||
|
||||
if (fim.isAvailable()) {
|
||||
ui.showForumsButton.setVisibility(View.VISIBLE);
|
||||
ui.showForumsButton
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent =
|
||||
new Intent(ctx,
|
||||
AvailableForumsActivity.class);
|
||||
ctx.startActivity(intent);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ui.showForumsButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
ui.date.setText(
|
||||
DateUtils.getRelativeTimeSpanString(ctx, item.getTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
@@ -321,8 +356,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
|
||||
public SparseArray<IncomingItem> getIncomingMessages() {
|
||||
SparseArray<IncomingItem> messages =
|
||||
new SparseArray<IncomingItem>();
|
||||
SparseArray<IncomingItem> messages = new SparseArray<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
ConversationItem item = items.get(i);
|
||||
@@ -334,8 +368,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
|
||||
public SparseArray<OutgoingItem> getOutgoingMessages() {
|
||||
SparseArray<OutgoingItem> messages =
|
||||
new SparseArray<OutgoingItem>();
|
||||
SparseArray<OutgoingItem> messages = new SparseArray<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
ConversationItem item = items.get(i);
|
||||
@@ -347,8 +380,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
|
||||
public SparseArray<ConversationMessageItem> getPrivateMessages() {
|
||||
SparseArray<ConversationMessageItem> messages =
|
||||
new SparseArray<ConversationMessageItem>();
|
||||
SparseArray<ConversationMessageItem> messages = new SparseArray<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
ConversationItem item = items.get(i);
|
||||
@@ -394,14 +426,14 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
|
||||
private static class IntroductionHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public ViewGroup layout;
|
||||
public View messageLayout;
|
||||
public MessageHolder message;
|
||||
public TextView text;
|
||||
public Button acceptButton;
|
||||
public Button declineButton;
|
||||
public TextView date;
|
||||
public ImageView status;
|
||||
final private ViewGroup layout;
|
||||
final private View messageLayout;
|
||||
final private MessageHolder message;
|
||||
final private TextView text;
|
||||
final private Button acceptButton;
|
||||
final private Button declineButton;
|
||||
final private TextView date;
|
||||
final private ImageView status;
|
||||
|
||||
public IntroductionHolder(View v, int type) {
|
||||
super(v);
|
||||
@@ -417,16 +449,18 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
|
||||
if (type == INTRODUCTION_OUT) {
|
||||
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
||||
} else {
|
||||
status = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoticeHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public ViewGroup layout;
|
||||
public TextView text;
|
||||
public TextView date;
|
||||
public ImageView status;
|
||||
final private ViewGroup layout;
|
||||
final private TextView text;
|
||||
final private TextView date;
|
||||
final private ImageView status;
|
||||
|
||||
public NoticeHolder(View v, int type) {
|
||||
super(v);
|
||||
@@ -437,10 +471,85 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
|
||||
if (type == NOTICE_OUT) {
|
||||
status = (ImageView) v.findViewById(R.id.noticeStatus);
|
||||
} else {
|
||||
status = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class InvitationHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
final private ViewGroup layout;
|
||||
final private View messageLayout;
|
||||
final private MessageHolder message;
|
||||
final private TextView text;
|
||||
final private Button showForumsButton;
|
||||
final private TextView date;
|
||||
final private ImageView status;
|
||||
|
||||
public InvitationHolder(View v, int type) {
|
||||
super(v);
|
||||
|
||||
layout = (ViewGroup) v.findViewById(R.id.introductionLayout);
|
||||
messageLayout = v.findViewById(R.id.messageLayout);
|
||||
message = new MessageHolder(messageLayout,
|
||||
type == FORUM_INVITATION_IN ? MSG_IN : MSG_OUT);
|
||||
text = (TextView) v.findViewById(R.id.introductionText);
|
||||
showForumsButton = (Button) v.findViewById(R.id.showForumsButton);
|
||||
date = (TextView) v.findViewById(R.id.introductionTime);
|
||||
|
||||
if (type == FORUM_INVITATION_OUT) {
|
||||
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
||||
} else {
|
||||
status = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ListCallbacks extends SortedList.Callback<ConversationItem> {
|
||||
@Override
|
||||
public void onInserted(int position, int count) {
|
||||
notifyItemRangeInserted(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(int position, int count) {
|
||||
notifyItemRangeChanged(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoved(int fromPosition, int toPosition) {
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(int position, int count) {
|
||||
notifyItemRangeRemoved(position, count);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(ConversationItem c1,
|
||||
ConversationItem c2) {
|
||||
return c1.getId().equals(c2.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(ConversationItem c1,
|
||||
ConversationItem c2) {
|
||||
return c1.equals(c2);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IntroductionHandler {
|
||||
void respondToIntroduction(final SessionId sessionId,
|
||||
final boolean accept);
|
||||
|
||||
Reference in New Issue
Block a user