diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java index bfbdf5c8c79d66a02f8695c2d40c685e59c1555b..87cfec0977269ba321f496c532fa72d616a56e7a 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java @@ -273,8 +273,9 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(forumManager1.getForums().contains(forum0)); // sharer shares forum with invitee + Contact c1 = contactManager0.getContact(contactId1); assertTrue(forumSharingManager0.getSharedWith(forum0.getId()) - .contains(contactId1)); + .contains(c1)); // invitee gets forum shared by sharer Contact contact0 = contactManager1.getContact(contactId1); assertTrue(forumSharingManager1.getSharedBy(forum0.getId()) @@ -292,12 +293,11 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // sharer no longer shares forum with invitee assertFalse(forumSharingManager0.getSharedWith(forum0.getId()) - .contains(contactId1)); + .contains(c1)); // invitee no longer gets forum shared by sharer assertFalse(forumSharingManager1.getSharedBy(forum0.getId()) .contains(contact0)); // forum can be shared again - Contact c1 = contactManager0.getContact(contactId1); assertTrue(forumSharingManager0.canBeShared(forum0.getId(), c1)); Contact c0 = contactManager1.getContact(contactId0); assertTrue(forumSharingManager1.canBeShared(forum0.getId(), c0)); @@ -333,8 +333,9 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(forumManager1.getForums().contains(forum0)); // sharer shares forum with invitee + Contact c1 = contactManager0.getContact(contactId1); assertTrue(forumSharingManager0.getSharedWith(forum0.getId()) - .contains(contactId1)); + .contains(c1)); // invitee gets forum shared by sharer Contact contact0 = contactManager1.getContact(contactId1); assertTrue(forumSharingManager1.getSharedBy(forum0.getId()) @@ -351,13 +352,13 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertEquals(1, forumManager1.getForums().size()); // invitee no longer shares forum with sharer + Contact c0 = contactManager1.getContact(contactId0); assertFalse(forumSharingManager1.getSharedWith(forum0.getId()) - .contains(contactId0)); + .contains(c0)); // sharer no longer gets forum shared by invitee assertFalse(forumSharingManager1.getSharedBy(forum0.getId()) .contains(contact0)); // forum can be shared again - Contact c0 = contactManager1.getContact(contactId0); assertTrue(forumSharingManager1.canBeShared(forum0.getId(), c0)); } finally { stopLifecycles(); diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index bce061cefdfd28eb77a1bc1ceb67ce0de0df07f2..025e452b2a2243482c0816a33547ce75269767eb 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -149,6 +149,16 @@ /> </activity> + <activity + android:name=".android.forum.ForumSharingStatusActivity" + android:label="@string/forum_sharing_status" + android:parentActivityName=".android.forum.ForumActivity"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".android.forum.ForumActivity" + /> + </activity> + <activity android:name=".android.forum.WriteForumPostActivity" android:label="@string/app_name" diff --git a/briar-android/res/layout/activity_forum_sharing_status.xml b/briar-android/res/layout/activity_forum_sharing_status.xml new file mode 100644 index 0000000000000000000000000000000000000000..efc4a8fc0890c75e89ca787d6de43e31f0a2e34d --- /dev/null +++ b/briar-android/res/layout/activity_forum_sharing_status.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/default_separator_inverted" + android:padding="@dimen/margin_medium" + android:text="@string/forum_shared_by" + android:textSize="@dimen/text_size_large"/> + + <View style="@style/Divider.ForumList"/> + + <org.briarproject.android.util.BriarRecyclerView + android:id="@+id/sharedByView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/margin_medium" + android:paddingTop="@dimen/margin_medium"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/default_separator_inverted" + android:padding="@dimen/margin_medium" + android:text="@string/forum_shared_with" + android:textSize="@dimen/text_size_large"/> + + <View style="@style/Divider.ForumList"/> + + <org.briarproject.android.util.BriarRecyclerView + android:id="@+id/sharedWithView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/margin_medium" + android:paddingTop="@dimen/margin_medium"/> + + </LinearLayout> + +</ScrollView> \ No newline at end of file diff --git a/briar-android/res/layout/list_item_contact_small.xml b/briar-android/res/layout/list_item_contact_small.xml new file mode 100644 index 0000000000000000000000000000000000000000..c6cdd0e97f5ece8e4ecc940f01dfd11533cf82ba --- /dev/null +++ b/briar-android/res/layout/list_item_contact_small.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingBottom="@dimen/margin_small" + android:paddingTop="@dimen/margin_small"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/avatarView" + style="@style/BriarAvatar" + android:layout_width="@dimen/listitem_picture_size_small" + android:layout_height="@dimen/listitem_picture_size_small" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + tools:src="@drawable/ic_launcher"/> + + <TextView + android:id="@+id/nameView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:maxLines="2" + android:textColor="@color/briar_text_primary" + android:textSize="@dimen/text_size_medium" + tools:text="This is a name of a contact"/> + +</LinearLayout> \ No newline at end of file diff --git a/briar-android/res/menu/forum_actions.xml b/briar-android/res/menu/forum_actions.xml index 292fe2b9cb42442520d3c08dd2f1ab542ffe98f0..599529b50b382db4df317d279ef01601c3b90a7c 100644 --- a/briar-android/res/menu/forum_actions.xml +++ b/briar-android/res/menu/forum_actions.xml @@ -15,6 +15,11 @@ android:title="@string/forum_share_button" app:showAsAction="ifRoom"/> + <item + android:id="@+id/action_forum_sharing_status" + android:title="@string/forum_sharing_status" + app:showAsAction="never"/> + <item android:id="@+id/action_forum_delete" android:icon="@drawable/action_delete_white" diff --git a/briar-android/res/values/color.xml b/briar-android/res/values/color.xml index a0d9584b26930de1b4a5f2d420f97d65a23835c0..3fb50397850e50e9d086b0b5f65a72353f1a131d 100644 --- a/briar-android/res/values/color.xml +++ b/briar-android/res/values/color.xml @@ -36,6 +36,7 @@ <!-- this is needed as preference_category_material layout uses this color as the text color --> <color name="preference_fallback_accent_color">@color/briar_accent</color> + <color name="divider">#c1c1c1</color> <color name="default_separator">#000000</color> <color name="default_separator_inverted">#ffffff</color> <color name="menu_background">#FFFFFF</color> diff --git a/briar-android/res/values/dimens.xml b/briar-android/res/values/dimens.xml index 392bb98852f1b4e289df904959b7614b442e23f3..5ca081c5687a1cf70a1568ac36609a73ddebbf0e 100644 --- a/briar-android/res/values/dimens.xml +++ b/briar-android/res/values/dimens.xml @@ -26,6 +26,7 @@ <dimen name="listitem_height_one_line_avatar">56dp</dimen> <dimen name="listitem_height_contact_selector">68dp</dimen> <dimen name="listitem_picture_size">48dp</dimen> + <dimen name="listitem_picture_size_small">23dp</dimen> <dimen name="listitem_picture_frame_size">50dp</dimen> <dimen name="listitem_selectable_picture_size">40dp</dimen> <dimen name="dropdown_picture_size">32dp</dimen> diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 447d3dc6a3373dfc330fac4167d2f3c4601780cc..0e01dde61aa790bafc32222181600420ae1f9018 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -80,6 +80,7 @@ <string name="show_forums">Show</string> <string name="forum_leave">Leave Forum</string> <string name="forum_left_toast">Left Forum</string> + <string name="forum_sharing_status">Sharing Status</string> <string name="no_forum_posts">No posts</string> <string name="no_unread_posts">no unread posts</string> <plurals name="unread_posts"> @@ -109,6 +110,9 @@ <string name="forum_joined_toast">Joined Forum</string> <string name="forum_declined_toast">Forum Invitation Declined</string> <string name="shared_by_format">Shared by %s</string> + <string name="forum_shared_by">Shared by</string> + <string name="forum_shared_with">Shared with</string> + <string name="nobody">Nobody</string> <string name="no_contacts_prompt">You don\'t have any contacts. Add a contact now?</string> <string name="add_button">Add</string> <string name="cancel_button">Cancel</string> diff --git a/briar-android/res/values/styles.xml b/briar-android/res/values/styles.xml index d0a190b9f802ddc0df736e682efbc332d6bfdb75..abb3e2457e35dc5cc6bee7f633b07a5a24b27235 100644 --- a/briar-android/res/values/styles.xml +++ b/briar-android/res/values/styles.xml @@ -93,7 +93,7 @@ </style> <style name="Divider"> - <item name="android:background">?android:attr/listDivider</item> + <item name="android:background">@color/divider</item> </style> <style name="Divider.Horizontal" parent="Divider"> diff --git a/briar-android/src/org/briarproject/android/ActivityComponent.java b/briar-android/src/org/briarproject/android/ActivityComponent.java index 6fec172b40ffe8ee4922ca850502f2d9c30fbed5..b777e38a43bebfc04627891e0b31d2cf9aec44ce 100644 --- a/briar-android/src/org/briarproject/android/ActivityComponent.java +++ b/briar-android/src/org/briarproject/android/ActivityComponent.java @@ -7,6 +7,7 @@ import org.briarproject.android.forum.AvailableForumsActivity; import org.briarproject.android.forum.ContactSelectorFragment; import org.briarproject.android.forum.CreateForumActivity; import org.briarproject.android.forum.ForumActivity; +import org.briarproject.android.forum.ForumSharingStatusActivity; import org.briarproject.android.forum.ReadForumPostActivity; import org.briarproject.android.forum.ShareForumActivity; import org.briarproject.android.forum.ShareForumMessageFragment; @@ -59,6 +60,8 @@ public interface ActivityComponent { void inject(ShareForumActivity activity); + void inject(ForumSharingStatusActivity activity); + void inject(ReadForumPostActivity activity); void inject(ForumActivity activity); diff --git a/briar-android/src/org/briarproject/android/contact/ContactListItem.java b/briar-android/src/org/briarproject/android/contact/ContactListItem.java index c152d20c8b3ffdf18b73a39adc217b1a10bad8d9..ab43b1ed5979d4cd1d9c4f050e969b2ab59e6165 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListItem.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListItem.java @@ -30,7 +30,7 @@ public class ContactListItem { } void setMessages(Collection<ConversationItem> messages) { - empty = messages.isEmpty(); + empty = messages == null || messages.isEmpty(); timestamp = 0; unread = 0; if (!empty) { diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index 1ea92c3c08b6c73d5c66def586d8796908042c0e..9aa469abbc4e185f3017a0092de993cfa9bf22f3 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -153,6 +153,9 @@ public class ForumActivity extends BriarActivity implements EventListener, @Override public boolean onOptionsItemSelected(final MenuItem item) { + ActivityOptionsCompat options = ActivityOptionsCompat + .makeCustomAnimation(this, android.R.anim.slide_in_left, + android.R.anim.slide_out_right); // Handle presses on the action bar items switch (item.getItemId()) { case R.id.action_forum_compose_post: @@ -166,13 +169,16 @@ public class ForumActivity extends BriarActivity implements EventListener, Intent i2 = new Intent(this, ShareForumActivity.class); i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); i2.putExtra(GROUP_ID, groupId.getBytes()); - ActivityOptionsCompat options = ActivityOptionsCompat - .makeCustomAnimation(this, android.R.anim.slide_in_left, - android.R.anim.slide_out_right); ActivityCompat .startActivityForResult(this, i2, REQUEST_FORUM_SHARED, options.toBundle()); return true; + case R.id.action_forum_sharing_status: + Intent i3 = new Intent(this, ForumSharingStatusActivity.class); + i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i3.putExtra(GROUP_ID, groupId.getBytes()); + ActivityCompat.startActivity(this, i3, options.toBundle()); + return true; case R.id.action_forum_delete: showUnsubscribeDialog(); return true; diff --git a/briar-android/src/org/briarproject/android/forum/ForumSharingStatusActivity.java b/briar-android/src/org/briarproject/android/forum/ForumSharingStatusActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..5da3d212c0f7262ae3b6fc7f196b19e0fd726ccc --- /dev/null +++ b/briar-android/src/org/briarproject/android/forum/ForumSharingStatusActivity.java @@ -0,0 +1,169 @@ +package org.briarproject.android.forum; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.view.MenuItem; + +import org.briarproject.R; +import org.briarproject.android.ActivityComponent; +import org.briarproject.android.BriarActivity; +import org.briarproject.android.contact.ContactListItem; +import org.briarproject.android.util.BriarRecyclerView; +import org.briarproject.api.contact.Contact; +import org.briarproject.api.db.DbException; +import org.briarproject.api.forum.ForumSharingManager; +import org.briarproject.api.identity.IdentityManager; +import org.briarproject.api.identity.LocalAuthor; +import org.briarproject.api.sync.GroupId; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; + +public class ForumSharingStatusActivity extends BriarActivity { + + private GroupId groupId; + private BriarRecyclerView sharedByList, sharedWithList; + private ForumSharingStatusAdapter sharedByAdapter, sharedWithAdapter; + + // Fields that are accessed from background threads must be volatile + @Inject + protected volatile ForumSharingManager forumSharingManager; + @Inject + protected volatile IdentityManager identityManager; + + public final static String TAG = "ForumSharingStatusActivity"; + private static final Logger LOG = Logger.getLogger(TAG); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_forum_sharing_status); + + Intent i = getIntent(); + byte[] b = i.getByteArrayExtra(GROUP_ID); + if (b == null) throw new IllegalStateException("No GroupId"); + groupId = new GroupId(b); + + sharedByList = (BriarRecyclerView) findViewById(R.id.sharedByView); + sharedByAdapter = new ForumSharingStatusAdapter(this); + sharedByList.setLayoutManager(new LinearLayoutManager(this)); + sharedByList.setAdapter(sharedByAdapter); + sharedByList.setEmptyText(getString(R.string.nobody)); + + sharedWithList = (BriarRecyclerView) findViewById(R.id.sharedWithView); + sharedWithAdapter = new ForumSharingStatusAdapter(this); + sharedWithList.setLayoutManager(new LinearLayoutManager(this)); + sharedWithList.setAdapter(sharedWithAdapter); + sharedWithList.setEmptyText(getString(R.string.nobody)); + } + + @Override + public void onResume() { + super.onResume(); + + loadSharedBy(); + loadSharedWith(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + // Handle presses on the action bar items + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + private void loadSharedBy() { + dbController.runOnDbThread(new Runnable() { + @Override + public void run() { + List<ContactListItem> contactItems = new ArrayList<>(); + try { + Collection<Contact> contacts = + forumSharingManager.getSharedBy(groupId); + for (Contact c : contacts) { + LocalAuthor localAuthor = identityManager + .getLocalAuthor(c.getLocalAuthorId()); + ContactListItem item = + new ContactListItem(c, localAuthor, false, null, + null); + contactItems.add(item); + } + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + displaySharedBy(contactItems); + } + }); + } + + private void displaySharedBy(final List<ContactListItem> contacts) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (contacts.isEmpty()) { + sharedByList.showData(); + } else { + sharedByAdapter.addAll(contacts); + } + } + }); + } + + private void loadSharedWith() { + dbController.runOnDbThread(new Runnable() { + @Override + public void run() { + List<ContactListItem> contactItems = new ArrayList<>(); + try { + Collection<Contact> contacts = + forumSharingManager.getSharedWith(groupId); + for (Contact c : contacts) { + LocalAuthor localAuthor = identityManager + .getLocalAuthor(c.getLocalAuthorId()); + ContactListItem item = + new ContactListItem(c, localAuthor, false, null, + null); + contactItems.add(item); + } + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + displaySharedWith(contactItems); + } + }); + } + + private void displaySharedWith(final List<ContactListItem> contacts) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (contacts.isEmpty()) { + sharedWithList.showData(); + } else { + sharedWithAdapter.addAll(contacts); + } + } + }); + } + +} diff --git a/briar-android/src/org/briarproject/android/forum/ForumSharingStatusAdapter.java b/briar-android/src/org/briarproject/android/forum/ForumSharingStatusAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..3d52480defda1ae9f1ec473e2a1aa69c623feb48 --- /dev/null +++ b/briar-android/src/org/briarproject/android/forum/ForumSharingStatusAdapter.java @@ -0,0 +1,36 @@ +package org.briarproject.android.forum; + +import android.content.Context; +import android.support.v4.content.ContextCompat; +import android.text.format.DateUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.R; +import org.briarproject.android.contact.BaseContactListAdapter; +import org.briarproject.android.contact.ContactListItem; + +public class ForumSharingStatusAdapter + extends BaseContactListAdapter<BaseContactListAdapter.BaseContactHolder> { + + public ForumSharingStatusAdapter(Context context) { + super(context, null); + } + + @Override + public BaseContactHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + View v = LayoutInflater.from(viewGroup.getContext()).inflate( + R.layout.list_item_contact_small, viewGroup, false); + + return new BaseContactHolder(v); + } + + @Override + public int compareContactListItems(ContactListItem c1, ContactListItem c2) { + return compareByName(c1, c2); + } + +} diff --git a/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java b/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java index dfc3c4c4f1d8f809abb2d835afb63868447a589e..93eeb669c177492cbb203c61c3c0448e7fbf0907 100644 --- a/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java +++ b/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java @@ -120,10 +120,11 @@ public class BriarRecyclerView extends FrameLayout { emptyView.setVisibility(VISIBLE); recyclerView.setVisibility(INVISIBLE); } else { - emptyView.setVisibility(INVISIBLE); + // use GONE here so empty view doesn't use space on small lists + emptyView.setVisibility(GONE); recyclerView.setVisibility(VISIBLE); } - progressBar.setVisibility(INVISIBLE); + progressBar.setVisibility(GONE); } } diff --git a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java index d20f427f6dc95dea0b23bc3b6bbf6a3e35fb928f..e38f13149e3b5be1da682efcd94b0c6eee6e0e00 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java +++ b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java @@ -41,7 +41,7 @@ public interface ForumSharingManager { Collection<Contact> getSharedBy(GroupId g) throws DbException; /** Returns the IDs of all contacts with whom the given forum is shared. */ - Collection<ContactId> getSharedWith(GroupId g) throws DbException; + Collection<Contact> getSharedWith(GroupId g) throws DbException; /** Returns true if the forum not already shared and no invitation is open */ boolean canBeShared(GroupId g, Contact c) throws DbException; diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java index 01572fbcb6ec221dc7fb933488f0d84e341669d8..08e80a8b9b5c2e425c48b882cc1de7c0bd28b790 100644 --- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java @@ -442,15 +442,15 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } @Override - public Collection<ContactId> getSharedWith(GroupId g) throws DbException { + public Collection<Contact> getSharedWith(GroupId g) throws DbException { try { - List<ContactId> shared = new ArrayList<ContactId>(); + List<Contact> shared = new ArrayList<Contact>(); Transaction txn = db.startTransaction(true); try { for (Contact c : db.getContacts(txn)) { GroupId contactGroup = getContactGroup(c).getId(); if (listContains(txn, contactGroup, g, SHARED_BY_US)) - shared.add(c.getId()); + shared.add(c); } txn.setComplete(); } finally {