diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 42c7979248d15ffbece6ea6d82cb05f79f8953b4..3d9e47c001926a5cc595b65756ba084ad67e849b 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -155,7 +155,7 @@ <item quantity="other">%d messages</item> </plurals> <string name="groups_group_is_empty">This group is empty</string> - <string name="groups_group_is_dissolved">This group is dissolved</string> + <string name="groups_group_is_dissolved">This group has been dissolved</string> <string name="groups_remove">Remove</string> <string name="groups_create_group_title">Create Private Group</string> <string name="groups_no_messages">This group is empty.\n\nYou can use the pen icon at the top to compose the first message.</string> @@ -168,11 +168,16 @@ <string name="groups_message_received">Message received</string> <string name="groups_member_list">Member List</string> <string name="groups_invite_members">Invite Members</string> + <string name="groups_member_joined">joined the group.</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> + <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> + <string name="groups_dissolved_dialog_title">Group Has Been Dissolved</string> + <string name="groups_dissolved_dialog_message">The creator of this group has dissolved it.\n\nYou can no longer write messages to the group and might not receive all posts that have been written.</string> <!-- Private Group Invitations --> <string name="groups_invitations_title">Group Invitations</string> @@ -188,9 +193,6 @@ <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/ForumControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java index a3b7fde89355ad3c5879a5960535013de290f8e5..55c8f817b86e5b4e0d62a32dd6003c0b13561c08 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java +++ b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java @@ -4,6 +4,7 @@ import android.support.annotation.Nullable; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.controller.handler.ResultExceptionHandler; +import org.briarproject.android.threaded.ThreadListController.ThreadListListener; import org.briarproject.android.threaded.ThreadListControllerImpl; import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.crypto.CryptoExecutor; @@ -32,7 +33,7 @@ import static java.lang.Math.max; import static java.util.logging.Level.WARNING; public class ForumControllerImpl - extends ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost> + extends ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost, ThreadListListener<ForumPostHeader>> implements ForumController { private static final Logger LOG = 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 dcdabb5febe1617d099451c0b9ba9342ac893f5d..e59f6cdacab3fef325737597d2c1a59d105aa5b9 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java @@ -18,8 +18,9 @@ import android.view.MenuItem; import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.controller.handler.UiResultExceptionHandler; -import org.briarproject.android.privategroup.memberlist.GroupMemberListActivity; +import org.briarproject.android.privategroup.conversation.GroupController.GroupListener; import org.briarproject.android.privategroup.creation.GroupInviteActivity; +import org.briarproject.android.privategroup.memberlist.GroupMemberListActivity; import org.briarproject.android.threaded.ThreadListActivity; import org.briarproject.android.threaded.ThreadListController; import org.briarproject.api.db.DbException; @@ -29,11 +30,12 @@ import org.briarproject.api.privategroup.PrivateGroup; import javax.inject.Inject; import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation; +import static android.view.View.GONE; import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH; public class GroupActivity extends ThreadListActivity<PrivateGroup, GroupMessageItem, GroupMessageHeader> - implements OnClickListener { + implements GroupListener, OnClickListener { private final static int REQUEST_INVITE = 2; @@ -200,6 +202,12 @@ public class GroupActivity extends if (writeMenuItem != null) writeMenuItem.setVisible(enabled); textInput.setSendButtonEnabled(enabled); list.getRecyclerView().setAlpha(enabled ? 1f : 0.5f); + + if (!enabled) { + textInput.setVisibility(GONE); + if (textInput.isKeyboardOpen()) textInput.hideSoftKeyboard(); + if (textInput.isEmojiDrawerOpen()) textInput.hideEmojiDrawer(); + } } private void showMenuItems() { @@ -254,4 +262,15 @@ public class GroupActivity extends }); } + @Override + public void onGroupDissolved() { + setGroupEnabled(false); + AlertDialog.Builder builder = + new AlertDialog.Builder(this, R.style.BriarDialogTheme); + builder.setTitle(getString(R.string.groups_dissolved_dialog_title)); + builder.setMessage(getString(R.string.groups_dissolved_dialog_message)); + builder.setNeutralButton(R.string.ok, null); + builder.show(); + } + } 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 ffdc971fce6bcc7b221b748533d5f4f1a9a6fea5..18915ab15df9bfb700b69f518d3099c9edae274f 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupController.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupController.java @@ -1,5 +1,7 @@ package org.briarproject.android.privategroup.conversation; +import android.support.annotation.UiThread; + import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.android.threaded.ThreadListController; import org.briarproject.api.db.DbException; @@ -16,4 +18,9 @@ public interface GroupController void isDissolved( ResultExceptionHandler<Boolean, DbException> handler); + interface GroupListener extends ThreadListListener<GroupMessageHeader> { + @UiThread + void onGroupDissolved(); + } + } 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 8146f200aaaa99b8eb2a94229940c23523fe4557..89de8033149d97050882402892d25185e36cd6d8 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java @@ -4,12 +4,14 @@ import android.support.annotation.Nullable; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.controller.handler.ResultExceptionHandler; +import org.briarproject.android.privategroup.conversation.GroupController.GroupListener; import org.briarproject.android.threaded.ThreadListControllerImpl; import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DbException; import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; +import org.briarproject.api.event.GroupDissolvedEvent; import org.briarproject.api.event.GroupMessageAddedEvent; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.LocalAuthor; @@ -34,7 +36,7 @@ import static java.lang.Math.max; import static java.util.logging.Level.WARNING; public class GroupControllerImpl extends - ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessage> + ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessage, GroupListener> implements GroupController { private static final Logger LOG = @@ -78,6 +80,16 @@ public class GroupControllerImpl extends } }); } + } else if (e instanceof GroupDissolvedEvent) { + GroupDissolvedEvent g = (GroupDissolvedEvent) e; + if (getGroupId().equals(g.getGroupId())) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onGroupDissolved(); + } + }); + } } } diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java index ac75f29cd57ef089b8cfc0a26306619093dccfd5..31c6458a654bc0fbbd409e2e1810b85a36836aab 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java @@ -70,4 +70,8 @@ class GroupItem { return dissolved; } + void setDissolved() { + dissolved = true; + } + } diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java index f102f82e49dd0641709f6b52a85f59e39a6aecb5..71c9f830589181c43a61dde66178aed029bf19fd 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java @@ -38,11 +38,18 @@ public interface GroupListController extends DbController { @UiThread void onGroupMessageAdded(GroupMessageHeader header); + @UiThread + void onGroupInvitationReceived(); + @UiThread void onGroupAdded(GroupId groupId); @UiThread void onGroupRemoved(GroupId groupId); + + @UiThread + void onGroupDissolved(GroupId groupId); + } } diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java index 4524e484b399b3cbcdcb91a2edd0f38d508615b6..60881e1c897c92583274e5ca505deb477d3b624c 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java @@ -13,6 +13,8 @@ import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.GroupAddedEvent; +import org.briarproject.api.event.GroupDissolvedEvent; +import org.briarproject.api.event.GroupInvitationReceivedEvent; import org.briarproject.api.event.GroupMessageAddedEvent; import org.briarproject.api.event.GroupRemovedEvent; import org.briarproject.api.lifecycle.LifecycleManager; @@ -89,6 +91,10 @@ public class GroupListControllerImpl extends DbControllerImpl GroupMessageAddedEvent g = (GroupMessageAddedEvent) e; LOG.info("Private group message added"); onGroupMessageAdded(g.getHeader()); + } else if (e instanceof GroupInvitationReceivedEvent) { + GroupInvitationReceivedEvent g = (GroupInvitationReceivedEvent) e; + LOG.info("Private group invitation received"); + onGroupInvitationReceived(); } else if (e instanceof GroupAddedEvent) { GroupAddedEvent g = (GroupAddedEvent) e; ClientId id = g.getGroup().getClientId(); @@ -103,6 +109,10 @@ public class GroupListControllerImpl extends DbControllerImpl LOG.info("Private group removed"); onGroupRemoved(g.getGroup().getId()); } + } else if (e instanceof GroupDissolvedEvent) { + GroupDissolvedEvent g = (GroupDissolvedEvent) e; + LOG.info("Private group dissolved"); + onGroupDissolved(g.getGroupId()); } } @@ -115,6 +125,15 @@ public class GroupListControllerImpl extends DbControllerImpl }); } + private void onGroupInvitationReceived() { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onGroupInvitationReceived(); + } + }); + } + private void onGroupAdded(final GroupId g) { listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override @@ -133,6 +152,15 @@ public class GroupListControllerImpl extends DbControllerImpl }); } + private void onGroupDissolved(final GroupId g) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onGroupDissolved(g); + } + }); + } + @Override public void loadGroups( final ResultExceptionHandler<Collection<GroupItem>, DbException> handler) { diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java index ec9f94b9f446b6b156de50696ab569efaaefbb4f..6dbcf3149946709185019dec247f576dcf26a941 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java @@ -151,6 +151,11 @@ public class GroupListFragment extends BaseFragment implements } } + @Override + public void onGroupInvitationReceived() { + loadAvailableGroups(); + } + @UiThread @Override public void onGroupAdded(GroupId groupId) { @@ -164,6 +169,17 @@ public class GroupListFragment extends BaseFragment implements adapter.removeItem(groupId); } + @Override + public void onGroupDissolved(GroupId groupId) { + adapter.incrementRevision(); + int position = adapter.findItemPosition(groupId); + GroupItem item = adapter.getItemAt(position); + if (item != null) { + item.setDissolved(); + adapter.updateItemAt(position, item); + } + } + @Override public String getUniqueTag() { return TAG; diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java index 441758258ec704ec07e7fb21f4964ddf7fee7779..3d52c972fa8b02b8b924570c1ac2e1a07310be64 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java @@ -6,6 +6,7 @@ import android.support.annotation.CallSuper; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.controller.DbControllerImpl; import org.briarproject.android.controller.handler.ResultExceptionHandler; +import org.briarproject.android.threaded.ThreadListController.ThreadListListener; import org.briarproject.api.clients.ThreadedMessage; import org.briarproject.api.clients.NamedGroup; import org.briarproject.api.clients.PostHeader; @@ -34,7 +35,7 @@ import java.util.logging.Logger; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; -public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends ThreadItem, H extends PostHeader, M extends ThreadedMessage> +public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends ThreadItem, H extends PostHeader, M extends ThreadedMessage, L extends ThreadListListener<H>> extends DbControllerImpl implements ThreadListController<G, I, H>, EventListener { @@ -49,7 +50,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T protected final AndroidNotificationManager notificationManager; protected final Executor cryptoExecutor; protected final Clock clock; - protected volatile ThreadListListener<H> listener; + protected volatile L listener; protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, IdentityManager identityManager, @@ -72,7 +73,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T @SuppressWarnings("unchecked") @Override public void onActivityCreate(Activity activity) { - listener = (ThreadListListener<H>) activity; + listener = (L) activity; } @CallSuper diff --git a/briar-api/src/org/briarproject/api/event/GroupDissolvedEvent.java b/briar-api/src/org/briarproject/api/event/GroupDissolvedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..5b8a3224d36643f7139b0425e05fb938cc27cf7c --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/GroupDissolvedEvent.java @@ -0,0 +1,26 @@ +package org.briarproject.api.event; + +import org.briarproject.api.nullsafety.NotNullByDefault; +import org.briarproject.api.sync.GroupId; + +import javax.annotation.concurrent.Immutable; + +/** + * An event that is broadcast when a private group was dissolved + * by a remote creator. + */ +@Immutable +@NotNullByDefault +public class GroupDissolvedEvent extends Event { + + private final GroupId groupId; + + public GroupDissolvedEvent(GroupId groupId) { + this.groupId = groupId; + } + + public GroupId getGroupId() { + return groupId; + } + +} diff --git a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java index 4b2ab02666881033dd666eb1d6b491d39f204277..2865aa9382fc7d15ddbb1b95897896d93daa4f1f 100644 --- a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java +++ b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java @@ -10,6 +10,8 @@ import org.briarproject.api.data.MetadataParser; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; import org.briarproject.api.db.Transaction; +import org.briarproject.api.event.Event; +import org.briarproject.api.event.GroupDissolvedEvent; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author.Status; import org.briarproject.api.identity.AuthorId; @@ -176,6 +178,8 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements } catch (FormatException e) { throw new DbException(e); } + Event e = new GroupDissolvedEvent(g); + txn.attach(e); } @Override