diff --git a/briar-android/res/menu/group_actions.xml b/briar-android/res/menu/group_actions.xml index 8ebe58a1b345f9c4b68b9be15f2c98dc467aba40..bf575e3255e7356bd6819277aaeef95709ec4f4a 100644 --- a/briar-android/res/menu/group_actions.xml +++ b/briar-android/res/menu/group_actions.xml @@ -25,15 +25,12 @@ <item android:id="@+id/action_group_leave" - android:enabled="false" android:icon="@drawable/action_delete_white" android:title="@string/groups_leave" - android:visible="false" app:showAsAction="never"/> <item android:id="@+id/action_group_dissolve" - android:enabled="false" android:icon="@drawable/action_delete_white" android:title="@string/groups_dissolve" app:showAsAction="never"/> diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index f69c03741706fa32928ad10b36a7985406973f94..8802b1543b6e569526e7e199998a53421b5be71a 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -163,6 +163,8 @@ <string name="groups_member_list">Member List</string> <string name="groups_invite_members">Invite Members</string> <string name="groups_leave">Leave Group</string> + <string name="groups_leave_dialog_title">Confirm Leaving Group</string> + <string name="groups_leave_dialog_message">Are you sure that you want to leave this group?</string> <string name="groups_dissolve">Dissolve Group</string> <string name="groups_member_joined">joined the group.</string> @@ -180,6 +182,9 @@ <string name="groups_invitations_response_declined_sent">You declined the group invitation from %s.</string> <string name="groups_invitations_response_accepted_received">%s accepted your group invitation.</string> <string name="groups_invitations_response_declined_received">%s declined your group invitation.</string> + <string name="groups_dissolve_dialog_title">Confirm Dissolving Group</string> + <string name="groups_dissolve_dialog_message">Are you sure that you want to dissolve this group?\n\nAll other members will not be able to continue their conversation and might not receive the latest messages.</string> + <string name="groups_dissolve_button">Dissolve</string> <!-- Forums --> <string name="no_forums">You don\'t have any forums yet.\n\nWhy don\'t you create a new one yourself by tapping the + icon at the top?\n\nYou can also ask your contacts to share forums with you.</string> diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index 36d552473a2684fbd3974a159c11d43d0a5c5ede..22c713889bd2e88c9ff0a5bac7dc0beb2a58f3b5 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -149,11 +149,11 @@ public class ForumActivity extends OnClickListener okListener = new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - deleteNamedGroup(); + deleteForum(); } }; - AlertDialog.Builder builder = new AlertDialog.Builder( - ForumActivity.this, R.style.BriarDialogTheme); + AlertDialog.Builder builder = new AlertDialog.Builder(this, + R.style.BriarDialogTheme); builder.setTitle(getString(R.string.dialog_title_leave_forum)); builder.setMessage(getString(R.string.dialog_message_leave_forum)); builder.setNegativeButton(R.string.dialog_button_leave, okListener); @@ -161,7 +161,7 @@ public class ForumActivity extends builder.show(); } - private void deleteNamedGroup() { + private void deleteForum() { forumController.deleteNamedGroup( new UiResultExceptionHandler<Void, DbException>(this) { @Override diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java index d17ed8d66374e1080c2761bce0a9f382a98c91ca..14000ec25acbdd296bc9272b1e408bf770f7b910 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java @@ -1,10 +1,13 @@ package org.briarproject.android.privategroup.conversation; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.os.Bundle; import android.support.annotation.LayoutRes; import android.support.annotation.StringRes; import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; import android.support.v7.widget.LinearLayoutManager; import android.view.Menu; import android.view.MenuInflater; @@ -12,8 +15,10 @@ import android.view.MenuItem; import org.briarproject.R; import org.briarproject.android.ActivityComponent; +import org.briarproject.android.controller.handler.UiResultExceptionHandler; import org.briarproject.android.threaded.ThreadListActivity; import org.briarproject.android.threaded.ThreadListController; +import org.briarproject.api.db.DbException; import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.PrivateGroup; @@ -22,11 +27,16 @@ import javax.inject.Inject; import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH; public class GroupActivity extends - ThreadListActivity<PrivateGroup, GroupMessageItem, GroupMessageHeader> { + ThreadListActivity<PrivateGroup, GroupMessageItem, GroupMessageHeader> + implements OnClickListener { @Inject GroupController controller; + private boolean isCreator; + private MenuItem leaveMenuItem; + private MenuItem dissolveMenuItem; + @Override public void injectActivity(ActivityComponent component) { component.inject(this); @@ -58,6 +68,20 @@ public class GroupActivity extends actionBar.setSubtitle(getString(R.string.groups_created_by, group.getAuthor().getName())); } + controller.isCreator(group, + new UiResultExceptionHandler<Boolean, DbException>(this) { + @Override + public void onResultUi(Boolean isCreator) { + GroupActivity.this.isCreator = isCreator; + showMenuItems(); + } + + @Override + public void onExceptionUi(DbException exception) { + // TODO proper error handling + finish(); + } + }); } @Override @@ -78,6 +102,10 @@ public class GroupActivity extends MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.group_actions, menu); + leaveMenuItem = menu.findItem(R.id.action_group_leave); + dissolveMenuItem = menu.findItem(R.id.action_group_dissolve); + showMenuItems(); + return super.onCreateOptionsMenu(menu); } @@ -87,6 +115,12 @@ public class GroupActivity extends case R.id.action_group_compose_message: showTextInput(null); return true; + case R.id.action_group_leave: + showLeaveGroupDialog(); + return true; + case R.id.action_group_dissolve: + showDissolveGroupDialog(); + return true; default: return super.onOptionsItemSelected(item); } @@ -109,4 +143,53 @@ public class GroupActivity extends return R.string.groups_message_received; } + private void showMenuItems() { + if (leaveMenuItem == null || dissolveMenuItem == null) return; + if (isCreator) { + leaveMenuItem.setVisible(false); + dissolveMenuItem.setVisible(true); + } else { + leaveMenuItem.setVisible(true); + dissolveMenuItem.setVisible(false); + } + } + + private void showLeaveGroupDialog() { + AlertDialog.Builder builder = + new AlertDialog.Builder(this, R.style.BriarDialogTheme); + builder.setTitle(getString(R.string.groups_leave_dialog_title)); + builder.setMessage(getString(R.string.groups_leave_dialog_message)); + builder.setNegativeButton(R.string.dialog_button_leave, this); + builder.setPositiveButton(R.string.cancel, null); + builder.show(); + } + + private void showDissolveGroupDialog() { + AlertDialog.Builder builder = + new AlertDialog.Builder(this, R.style.BriarDialogTheme); + builder.setTitle(getString(R.string.groups_dissolve_dialog_title)); + builder.setMessage(getString(R.string.groups_dissolve_dialog_message)); + builder.setNegativeButton(R.string.groups_dissolve_button, this); + builder.setPositiveButton(R.string.cancel, null); + builder.show(); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + controller.deleteNamedGroup( + new UiResultExceptionHandler<Void, DbException>(this) { + @Override + public void onResultUi(Void v) { + // The activity is going to be destroyed by the + // GroupRemovedEvent being fired + } + + @Override + public void onExceptionUi(DbException exception) { + // TODO proper error handling + finish(); + } + }); + } + } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupController.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupController.java index 0292f22787bba631e676d6eed41945ca4bbf865e..1a2fa951e87481a613e1a02ebc2ced45a0bb3f86 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupController.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupController.java @@ -1,6 +1,8 @@ package org.briarproject.android.privategroup.conversation; +import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.android.threaded.ThreadListController; +import org.briarproject.api.db.DbException; import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.PrivateGroup; @@ -8,4 +10,7 @@ public interface GroupController extends ThreadListController<PrivateGroup, GroupMessageItem, GroupMessageHeader> { + void isCreator(PrivateGroup group, + ResultExceptionHandler<Boolean, DbException> handler); + } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java index abbf10d423508e41b7459f74f389e48f9ea67b2d..df366c675c61193732c8fb901cd5be98c21cd3f9 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java @@ -30,6 +30,7 @@ import java.util.logging.Logger; import javax.inject.Inject; import static java.lang.Math.max; + import static java.util.logging.Level.WARNING; public class GroupControllerImpl extends @@ -174,4 +175,24 @@ public class GroupControllerImpl extends return new GroupMessageItem(header, body); } + @Override + public void isCreator(final PrivateGroup group, + final ResultExceptionHandler<Boolean, DbException> handler) { + runOnDbThread(new Runnable() { + @Override + public void run() { + try { + LocalAuthor author = identityManager.getLocalAuthor(); + boolean isCreator = + author.getId().equals(group.getAuthor().getId()); + handler.onResult(isCreator); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + handler.onException(e); + } + } + }); + } + } diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java index 6ea72c892357f669bc1fcd8d322ddca3b4b787cc..018188a481a398ccdcb443e525ea667a49061b37 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java @@ -41,16 +41,14 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T private static final Logger LOG = Logger.getLogger(ThreadListControllerImpl.class.getName()); - protected final IdentityManager identityManager; - protected final Executor cryptoExecutor; - protected final AndroidNotificationManager notificationManager; - protected final Clock clock; private final EventBus eventBus; - private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>(); - private volatile GroupId groupId; + protected final IdentityManager identityManager; + protected final AndroidNotificationManager notificationManager; + protected final Executor cryptoExecutor; + protected final Clock clock; protected volatile ThreadListListener<H> listener; protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,