Merge branch '646-shared-with-subtitle-forums' into 'master'

Add sharing info to ForumActivity action bar subtitle

This indirectly does also most of the work for adding the same information to private groups. However, completing this is blocked by !448.

![device-2016-12-07-152915](/uploads/5bb42f2e78a87931b0307e7597ba72c5/device-2016-12-07-152915.png)

Second part of #646

See merge request !451
This commit is contained in:
Torsten Grote
2016-12-09 16:06:21 +00:00
6 changed files with 179 additions and 13 deletions

View File

@@ -13,14 +13,17 @@ import android.support.v7.widget.LinearLayoutManager;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; 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.ForumSharingStatusActivity;
import org.briarproject.briar.android.sharing.ShareForumActivity; import org.briarproject.briar.android.sharing.ShareForumActivity;
import org.briarproject.briar.android.threaded.ThreadItemAdapter; import org.briarproject.briar.android.threaded.ThreadItemAdapter;
@@ -41,7 +44,8 @@ import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_POST_BOD
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class ForumActivity extends 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; private static final int REQUEST_FORUM_SHARED = 3;
@@ -66,6 +70,21 @@ public class ForumActivity extends
String groupName = i.getStringExtra(GROUP_NAME); String groupName = i.getStringExtra(GROUP_NAME);
if (groupName != null) setTitle(groupName); if (groupName != null) setTitle(groupName);
else loadNamedGroup(); 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 @Override
@@ -183,4 +202,11 @@ public class ForumActivity extends
}); });
} }
@Override
public void onForumLeft(ContactId c) {
sharingController.remove(c);
setToolbarSubTitle(sharingController.getTotalCount(),
sharingController.getOnlineCount());
}
} }

View File

@@ -1,5 +1,8 @@
package org.briarproject.briar.android.forum; 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.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.android.threaded.ThreadListController; import org.briarproject.briar.android.threaded.ThreadListController;
import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.Forum;
@@ -9,4 +12,9 @@ import org.briarproject.briar.api.forum.ForumPostHeader;
interface ForumController interface ForumController
extends ThreadListController<Forum, ForumItem, ForumPostHeader> { extends ThreadListController<Forum, ForumItem, ForumPostHeader> {
interface ForumListener extends ThreadListListener<ForumPostHeader> {
@UiThread
void onForumLeft(ContactId c);
}
} }

View File

@@ -1,5 +1,7 @@
package org.briarproject.briar.android.forum; 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.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; 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.sync.MessageId;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; 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.android.threaded.ThreadListControllerImpl;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.forum.Forum; 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.ForumManager;
import org.briarproject.briar.api.forum.ForumPost; import org.briarproject.briar.api.forum.ForumPost;
import org.briarproject.briar.api.forum.ForumPostHeader; 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.forum.event.ForumPostReceivedEvent;
import org.briarproject.briar.api.sharing.event.ShareableLeftEvent;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -34,23 +41,26 @@ import static java.util.logging.Level.WARNING;
@NotNullByDefault @NotNullByDefault
class ForumControllerImpl extends class ForumControllerImpl extends
ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost, ThreadListListener<ForumPostHeader>> ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost, ForumListener>
implements ForumController { implements ForumController {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ForumControllerImpl.class.getName()); Logger.getLogger(ForumControllerImpl.class.getName());
private final ForumManager forumManager; private final ForumManager forumManager;
private final ForumSharingManager forumSharingManager;
@Inject @Inject
ForumControllerImpl(@DatabaseExecutor Executor dbExecutor, ForumControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, IdentityManager identityManager, LifecycleManager lifecycleManager, IdentityManager identityManager,
@CryptoExecutor Executor cryptoExecutor, @CryptoExecutor Executor cryptoExecutor,
ForumManager forumManager, EventBus eventBus, ForumManager forumManager, ForumSharingManager forumSharingManager,
Clock clock, AndroidNotificationManager notificationManager) { EventBus eventBus, Clock clock,
AndroidNotificationManager notificationManager) {
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
eventBus, clock, notificationManager); eventBus, clock, notificationManager);
this.forumManager = forumManager; this.forumManager = forumManager;
this.forumSharingManager = forumSharingManager;
} }
@Override @Override
@@ -67,13 +77,22 @@ class ForumControllerImpl extends
ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e; ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e;
if (pe.getGroupId().equals(getGroupId())) { if (pe.getGroupId().equals(getGroupId())) {
LOG.info("Forum post received, adding..."); LOG.info("Forum post received, adding...");
final ForumPostHeader fph = pe.getForumPostHeader(); onForumPostHeaderReceived(pe.getForumPostHeader());
listener.runOnUiThreadUnlessDestroyed(new Runnable() { }
@Override } else if (e instanceof ForumInvitationResponseReceivedEvent) {
public void run() { ForumInvitationResponseReceivedEvent f =
listener.onHeaderReceived(fph); (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); 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 @Override
public void createAndStoreMessage(final String body, public void createAndStoreMessage(final String body,
@Nullable final ForumItem parentItem, @Nullable final ForumItem parentItem,
@@ -153,4 +194,31 @@ class ForumControllerImpl extends
return new ForumItem(header, body); 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);
}
});
}
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.briar.android.privategroup.conversation; 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.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
@@ -134,6 +135,12 @@ class GroupControllerImpl extends
privateGroupManager.setReadFlag(getGroupId(), id, true); privateGroupManager.setReadFlag(getGroupId(), id, true);
} }
@Override
public void loadSharingContacts(
ResultExceptionHandler<Collection<ContactId>, DbException> handler) {
// TODO
}
@Override @Override
public void createAndStoreMessage(final String body, public void createAndStoreMessage(final String body,
@Nullable final GroupMessageItem parentItem, @Nullable final GroupMessageItem parentItem,

View File

@@ -8,10 +8,12 @@ import android.support.annotation.StringRes;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; 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.bramble.util.StringUtils;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BriarActivity; 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.controller.handler.UiResultExceptionHandler;
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener; import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener; import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
@@ -33,6 +37,7 @@ import java.util.Collection;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject;
import static android.support.design.widget.Snackbar.make; import static android.support.design.widget.Snackbar.make;
import static android.view.View.GONE; import static android.view.View.GONE;
@@ -42,7 +47,7 @@ import static android.view.View.VISIBLE;
@ParametersNotNullByDefault @ParametersNotNullByDefault
public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader> public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader>
extends BriarActivity extends BriarActivity
implements ThreadListListener<H>, TextInputListener, implements ThreadListListener<H>, TextInputListener, SharingListener,
ThreadItemListener<I> { ThreadItemListener<I> {
protected static final String KEY_INPUT_VISIBILITY = "inputVisibility"; 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; private MessageId replyId;
protected abstract ThreadListController<G, I, H> getController(); protected abstract ThreadListController<G, I, H> getController();
@Inject
protected SharingController sharingController;
@CallSuper @CallSuper
@Override @Override
@@ -88,6 +95,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
} }
loadItems(); loadItems();
sharingController.setSharingListener(this);
loadSharingContacts();
} }
@LayoutRes @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 @CallSuper
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
sharingController.onStart();
list.startPeriodicUpdate(); list.startPeriodicUpdate();
} }
@@ -155,6 +184,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
sharingController.onStop();
list.stopPeriodicUpdate(); list.stopPeriodicUpdate();
} }
@@ -210,6 +240,26 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
showTextInput(item); 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) { protected void displaySnackbarShort(@StringRes int stringId) {
Snackbar snackbar = make(list, stringId, Snackbar.LENGTH_SHORT); Snackbar snackbar = make(list, stringId, Snackbar.LENGTH_SHORT);
snackbar.getView().setBackgroundResource(R.color.briar_primary); snackbar.getView().setBackgroundResource(R.color.briar_primary);

View File

@@ -2,6 +2,7 @@ package org.briarproject.briar.android.threaded;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; 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 loadNamedGroup(ResultExceptionHandler<G, DbException> handler);
void loadSharingContacts(
ResultExceptionHandler<Collection<ContactId>, DbException> handler);
void loadItem(H header, ResultExceptionHandler<I, DbException> handler); void loadItem(H header, ResultExceptionHandler<I, DbException> handler);
void loadItems(ResultExceptionHandler<Collection<I>, DbException> handler); void loadItems(ResultExceptionHandler<Collection<I>, DbException> handler);
@@ -43,6 +47,9 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
@UiThread @UiThread
void onGroupRemoved(); void onGroupRemoved();
@UiThread
void onInvitationAccepted(ContactId c);
} }
} }