diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java index fb4d4dfed..6cb17a40f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java @@ -12,6 +12,7 @@ import android.support.v7.widget.LinearLayoutManager; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.View; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.identity.AuthorId; @@ -72,6 +73,21 @@ public class GroupActivity extends if (groupName != null) setTitle(groupName); loadNamedGroup(); + // Open member list on ActionBar click + View actionBar = findViewById(R.id.action_bar); + if (actionBar != null) { + actionBar.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(GroupActivity.this, + GroupMemberListActivity.class); + i.putExtra(GROUP_ID, groupId.getBytes()); + startActivity(i); + } + }); + } + setGroupEnabled(false); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/GroupMemberListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/GroupMemberListControllerImpl.java index 4acd6b458..69bc9ac51 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/GroupMemberListControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/GroupMemberListControllerImpl.java @@ -1,8 +1,10 @@ package org.briarproject.briar.android.privategroup.memberlist; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.plugin.ConnectionRegistry; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.briar.android.controller.DbControllerImpl; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; @@ -24,13 +26,16 @@ class GroupMemberListControllerImpl extends DbControllerImpl private static final Logger LOG = Logger.getLogger(GroupMemberListControllerImpl.class.getName()); + private final ConnectionRegistry connectionRegistry; private final PrivateGroupManager privateGroupManager; @Inject GroupMemberListControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, + ConnectionRegistry connectionRegistry, PrivateGroupManager privateGroupManager) { super(dbExecutor, lifecycleManager); + this.connectionRegistry = connectionRegistry; this.privateGroupManager = privateGroupManager; } @@ -45,7 +50,11 @@ class GroupMemberListControllerImpl extends DbControllerImpl Collection members = privateGroupManager.getMembers(groupId); for (GroupMember m : members) { - items.add(new MemberListItem(m)); + ContactId c = m.getContactId(); + boolean online = false; + if (c != null) + online = connectionRegistry.isConnected(c); + items.add(new MemberListItem(m, online)); } handler.onResult(items); } catch (DbException e) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListAdapter.java index 5eddb41e3..0d8910245 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListAdapter.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListAdapter.java @@ -35,7 +35,9 @@ class MemberListAdapter extends @Override public boolean areContentsTheSame(MemberListItem m1, MemberListItem m2) { + if (m1.isOnline() != m2.isOnline()) return false; if (m1.getVisibility() != m2.getVisibility()) return false; + if (m1.getContactId() != m2.getContactId()) return false; if (m1.getStatus() != m2.getStatus()) return false; return true; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java index b05507536..11235ddbe 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java @@ -1,37 +1,55 @@ package org.briarproject.briar.android.privategroup.memberlist; +import android.support.annotation.Nullable; + +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author.Status; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.api.privategroup.GroupMember; import org.briarproject.briar.api.privategroup.Visibility; -import javax.annotation.concurrent.Immutable; +import javax.annotation.concurrent.NotThreadSafe; -@Immutable +@NotThreadSafe @NotNullByDefault class MemberListItem { - private final Author member; - private final Status status; - private final Visibility visibility; + private final GroupMember groupMember; + private boolean online; - MemberListItem(GroupMember groupMember) { - this.member = groupMember.getAuthor(); - this.visibility = groupMember.getVisibility(); - this.status = groupMember.getStatus(); + MemberListItem(GroupMember groupMember, boolean online) { + this.groupMember = groupMember; + this.online = online; } Author getMember() { - return member; - } - - Visibility getVisibility() { - return visibility; + return groupMember.getAuthor(); } Status getStatus() { - return status; + return groupMember.getStatus(); + } + + boolean isCreator() { + return groupMember.isCreator(); + } + + @Nullable + ContactId getContactId() { + return groupMember.getContactId(); + } + + Visibility getVisibility() { + return groupMember.getVisibility(); + } + + boolean isOnline() { + return online; + } + + void setOnline(boolean online) { + this.online = online; } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItemHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItemHolder.java index 5b82c5e8b..725898edc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItemHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItemHolder.java @@ -20,19 +20,52 @@ import static org.briarproject.briar.android.privategroup.VisibilityHelper.getVi class MemberListItemHolder extends RecyclerView.ViewHolder { private final AuthorView author; + private final ImageView bulb; + private final TextView creator; private final ImageView icon; private final TextView info; MemberListItemHolder(View v) { super(v); author = (AuthorView) v.findViewById(R.id.authorView); + bulb = (ImageView) v.findViewById(R.id.bulbView); + creator = (TextView) v.findViewById(R.id.creatorView); icon = (ImageView) v.findViewById(R.id.icon); info = (TextView) v.findViewById(R.id.info); } protected void bind(MemberListItem item) { + // member name, avatar and status author.setAuthor(item.getMember()); author.setAuthorStatus(item.getStatus()); + + // online status of visible contacts + if (item.getContactId() != null) { + bulb.setVisibility(View.VISIBLE); + if (item.isOnline()) { + bulb.setImageResource(R.drawable.contact_connected); + } else { + bulb.setImageResource(R.drawable.contact_disconnected); + } + } else { + bulb.setVisibility(View.GONE); + } + + // text shown for creator + if (item.isCreator()) { + creator.setVisibility(View.VISIBLE); + if (item.getStatus() == OURSELVES) { + creator.setText(R.string.groups_member_created_you); + } else { + creator.setText(creator.getContext() + .getString(R.string.groups_member_created, + item.getMember().getName())); + } + } else { + creator.setVisibility(View.GONE); + } + + // visibility information if (item.getStatus() == OURSELVES || item.getStatus() == UNKNOWN) { icon.setVisibility(View.GONE); info.setVisibility(View.GONE); diff --git a/briar-android/src/main/res/layout/list_item_group_member.xml b/briar-android/src/main/res/layout/list_item_group_member.xml index f02ed68c7..13591d00f 100644 --- a/briar-android/src/main/res/layout/list_item_group_member.xml +++ b/briar-android/src/main/res/layout/list_item_group_member.xml @@ -13,17 +13,41 @@ android:id="@+id/authorView" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginBottom="@dimen/margin_small" android:layout_marginEnd="@dimen/listitem_horizontal_margin" android:layout_marginRight="@dimen/listitem_horizontal_margin" + android:layout_toLeftOf="@+id/bulbView" app:persona="list"/> + + + + hooks; @@ -87,9 +93,11 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook PrivateGroupManagerImpl(ClientHelper clientHelper, MetadataParser metadataParser, DatabaseComponent db, PrivateGroupFactory privateGroupFactory, - IdentityManager identityManager, MessageTracker messageTracker) { + ContactManager contactManager, IdentityManager identityManager, + MessageTracker messageTracker) { super(db, clientHelper, metadataParser); this.privateGroupFactory = privateGroupFactory; + this.contactManager = contactManager; this.identityManager = identityManager; this.messageTracker = messageTracker; hooks = new CopyOnWriteArrayList(); @@ -394,10 +402,20 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook try { Collection members = new ArrayList(); Map authors = getMembers(txn, g); + LocalAuthor la = identityManager.getLocalAuthor(); + PrivateGroup privateGroup = getPrivateGroup(txn, g); for (Entry m : authors.entrySet()) { - Status status = identityManager - .getAuthorStatus(txn, m.getKey().getId()); - members.add(new GroupMember(m.getKey(), status, m.getValue())); + Author a = m.getKey(); + Status status = identityManager.getAuthorStatus(txn, a.getId()); + Visibility v = m.getValue(); + ContactId c = null; + if (v != INVISIBLE && + (status == VERIFIED || status == UNVERIFIED)) { + c = contactManager.getContact(txn, a.getId(), la.getId()) + .getId(); + } + boolean isCreator = privateGroup.getCreator().equals(a); + members.add(new GroupMember(a, status, isCreator, c, v)); } db.commitTransaction(txn); return members;