diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java index ad961043d48e52dfdbd112b89289550af27cc457..bf079bbf0868732ba078a04170c69edf5edbadd3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java @@ -13,14 +13,17 @@ import android.support.v7.widget.LinearLayoutManager; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.View; import android.widget.Toast; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.briar.android.forum.ForumController.ForumListener; import org.briarproject.briar.android.sharing.ForumSharingStatusActivity; import org.briarproject.briar.android.sharing.ShareForumActivity; import org.briarproject.briar.android.threaded.ThreadItemAdapter; @@ -41,7 +44,8 @@ import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_POST_BOD @MethodsNotNullByDefault @ParametersNotNullByDefault public class ForumActivity extends - ThreadListActivity<Forum, ThreadItemAdapter<ForumItem>, ForumItem, ForumPostHeader> { + ThreadListActivity<Forum, ThreadItemAdapter<ForumItem>, ForumItem, ForumPostHeader> + implements ForumListener { private static final int REQUEST_FORUM_SHARED = 3; @@ -66,6 +70,21 @@ public class ForumActivity extends String groupName = i.getStringExtra(GROUP_NAME); if (groupName != null) setTitle(groupName); else loadNamedGroup(); + + // Open Sharing Status 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(ForumActivity.this, + ForumSharingStatusActivity.class); + i.putExtra(GROUP_ID, groupId.getBytes()); + startActivity(i); + } + }); + } } @Override @@ -183,4 +202,11 @@ public class ForumActivity extends }); } + @Override + public void onForumLeft(ContactId c) { + sharingController.remove(c); + setToolbarSubTitle(sharingController.getTotalCount(), + sharingController.getOnlineCount()); + } + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumController.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumController.java index 8b99ab1741f6341cd1e6750b11d86bb3c2d9e81b..3d800e241f4feb2924f275c1bb43fba2d887a3a9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumController.java @@ -1,5 +1,8 @@ package org.briarproject.briar.android.forum; +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.android.threaded.ThreadListController; import org.briarproject.briar.api.forum.Forum; @@ -9,4 +12,9 @@ import org.briarproject.briar.api.forum.ForumPostHeader; interface ForumController extends ThreadListController<Forum, ForumItem, ForumPostHeader> { + interface ForumListener extends ThreadListListener<ForumPostHeader> { + @UiThread + void onForumLeft(ContactId c); + } + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java index 3b9f91f6178b23a2e086727d2493b26beeddf189..b8df259551d688f8f07e27d457e7f2422d96e32c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java @@ -1,5 +1,7 @@ package org.briarproject.briar.android.forum; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; @@ -12,16 +14,21 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; -import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener; +import org.briarproject.briar.android.forum.ForumController.ForumListener; import org.briarproject.briar.android.threaded.ThreadListControllerImpl; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.forum.Forum; +import org.briarproject.briar.api.forum.ForumInvitationResponse; import org.briarproject.briar.api.forum.ForumManager; import org.briarproject.briar.api.forum.ForumPost; import org.briarproject.briar.api.forum.ForumPostHeader; +import org.briarproject.briar.api.forum.ForumSharingManager; +import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent; import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent; +import org.briarproject.briar.api.sharing.event.ShareableLeftEvent; +import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -34,23 +41,26 @@ import static java.util.logging.Level.WARNING; @NotNullByDefault class ForumControllerImpl extends - ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost, ThreadListListener<ForumPostHeader>> + ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost, ForumListener> implements ForumController { private static final Logger LOG = Logger.getLogger(ForumControllerImpl.class.getName()); private final ForumManager forumManager; + private final ForumSharingManager forumSharingManager; @Inject ForumControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, - ForumManager forumManager, EventBus eventBus, - Clock clock, AndroidNotificationManager notificationManager) { + ForumManager forumManager, ForumSharingManager forumSharingManager, + EventBus eventBus, Clock clock, + AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, eventBus, clock, notificationManager); this.forumManager = forumManager; + this.forumSharingManager = forumSharingManager; } @Override @@ -67,13 +77,22 @@ class ForumControllerImpl extends ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e; if (pe.getGroupId().equals(getGroupId())) { LOG.info("Forum post received, adding..."); - final ForumPostHeader fph = pe.getForumPostHeader(); - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - listener.onHeaderReceived(fph); - } - }); + onForumPostHeaderReceived(pe.getForumPostHeader()); + } + } else if (e instanceof ForumInvitationResponseReceivedEvent) { + ForumInvitationResponseReceivedEvent f = + (ForumInvitationResponseReceivedEvent) e; + ForumInvitationResponse r = + (ForumInvitationResponse) f.getResponse(); + if (r.getGroupId().equals(getGroupId()) && r.wasAccepted()) { + LOG.info("Forum invitation was accepted"); + onForumInvitationAccepted(r.getContactId()); + } + } else if (e instanceof ShareableLeftEvent) { + ShareableLeftEvent s = (ShareableLeftEvent) e; + if (s.getGroupId().equals(getGroupId())) { + LOG.info("Forum left by contact"); + onForumLeft(s.getContactId()); } } } @@ -98,6 +117,28 @@ class ForumControllerImpl extends forumManager.setReadFlag(getGroupId(), id, true); } + @Override + public void loadSharingContacts( + final ResultExceptionHandler<Collection<ContactId>, DbException> handler) { + runOnDbThread(new Runnable() { + @Override + public void run() { + try { + Collection<Contact> contacts = + forumSharingManager.getSharedWith(getGroupId()); + Collection<ContactId> contactIds = + new ArrayList<>(contacts.size()); + for (Contact c : contacts) contactIds.add(c.getId()); + handler.onResult(contactIds); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + handler.onException(e); + } + } + }); + } + @Override public void createAndStoreMessage(final String body, @Nullable final ForumItem parentItem, @@ -153,4 +194,31 @@ class ForumControllerImpl extends return new ForumItem(header, body); } + private void onForumPostHeaderReceived(final ForumPostHeader h) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onHeaderReceived(h); + } + }); + } + + private void onForumInvitationAccepted(final ContactId c) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onInvitationAccepted(c); + } + }); + } + + private void onForumLeft(final ContactId c) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onForumLeft(c); + } + }); + } + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java index 431c66a59bf602967783880eabef8d1bf7f4bb6e..a34e0365eae96720e8ce3932491053493ce8f9e5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.privategroup.conversation; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; @@ -134,6 +135,12 @@ class GroupControllerImpl extends privateGroupManager.setReadFlag(getGroupId(), id, true); } + @Override + public void loadSharingContacts( + ResultExceptionHandler<Collection<ContactId>, DbException> handler) { + // TODO + } + @Override public void createAndStoreMessage(final String body, @Nullable final GroupMessageItem parentItem, diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java index 2c2d20793f90b61d9a7edba5e0a3b3d492cebb9b..b1d937dda529df39fd9a102451e43ad05f78fbe9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java @@ -8,10 +8,12 @@ import android.support.annotation.StringRes; import android.support.annotation.UiThread; import android.support.design.widget.Snackbar; import android.support.v4.content.ContextCompat; +import android.support.v7.app.ActionBar; import android.support.v7.widget.LinearLayoutManager; import android.view.MenuItem; import android.view.View; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; @@ -20,6 +22,8 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.BriarActivity; +import org.briarproject.briar.android.controller.SharingController; +import org.briarproject.briar.android.controller.SharingController.SharingListener; import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener; import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener; @@ -33,6 +37,7 @@ import java.util.Collection; import java.util.logging.Logger; import javax.annotation.Nullable; +import javax.inject.Inject; import static android.support.design.widget.Snackbar.make; import static android.view.View.GONE; @@ -42,7 +47,7 @@ import static android.view.View.VISIBLE; @ParametersNotNullByDefault public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader> extends BriarActivity - implements ThreadListListener<H>, TextInputListener, + implements ThreadListListener<H>, TextInputListener, SharingListener, ThreadItemListener<I> { protected static final String KEY_INPUT_VISIBILITY = "inputVisibility"; @@ -58,6 +63,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI private MessageId replyId; protected abstract ThreadListController<G, I, H> getController(); + @Inject + protected SharingController sharingController; @CallSuper @Override @@ -88,6 +95,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI } loadItems(); + sharingController.setSharingListener(this); + loadSharingContacts(); } @LayoutRes @@ -144,10 +153,30 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI }); } + protected void loadSharingContacts() { + getController().loadSharingContacts( + new UiResultExceptionHandler<Collection<ContactId>, DbException>( + this) { + @Override + public void onResultUi(Collection<ContactId> contacts) { + sharingController.addAll(contacts); + int online = sharingController.getOnlineCount(); + setToolbarSubTitle(contacts.size(), online); + } + + @Override + public void onExceptionUi(DbException e) { + // TODO Proper error handling + finish(); + } + }); + } + @CallSuper @Override public void onStart() { super.onStart(); + sharingController.onStart(); list.startPeriodicUpdate(); } @@ -155,6 +184,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI @Override public void onStop() { super.onStop(); + sharingController.onStop(); list.stopPeriodicUpdate(); } @@ -210,6 +240,26 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI showTextInput(item); } + @Override + public void onSharingInfoUpdated(int total, int online) { + setToolbarSubTitle(total, online); + } + + @Override + public void onInvitationAccepted(ContactId c) { + sharingController.add(c); + setToolbarSubTitle(sharingController.getTotalCount(), + sharingController.getOnlineCount()); + } + + protected void setToolbarSubTitle(int total, int online) { + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setSubtitle( + getString(R.string.shared_with, total, online)); + } + } + protected void displaySnackbarShort(@StringRes int stringId) { Snackbar snackbar = make(list, stringId, Snackbar.LENGTH_SHORT); snackbar.getView().setBackgroundResource(R.color.briar_primary); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java index 942a61d6806d69b16e739dc6f82fae1bda111193..caebd1ec65d53dad3c590e0d1cf287703073e0d2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java @@ -2,6 +2,7 @@ package org.briarproject.briar.android.threaded; import android.support.annotation.UiThread; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; @@ -24,6 +25,9 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem void loadNamedGroup(ResultExceptionHandler<G, DbException> handler); + void loadSharingContacts( + ResultExceptionHandler<Collection<ContactId>, DbException> handler); + void loadItem(H header, ResultExceptionHandler<I, DbException> handler); void loadItems(ResultExceptionHandler<Collection<I>, DbException> handler); @@ -43,6 +47,9 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem @UiThread void onGroupRemoved(); + + @UiThread + void onInvitationAccepted(ContactId c); } }