From feed2581c94459fe62f5333a8db48c38edf525c2 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 13 Oct 2016 12:56:31 -0300 Subject: [PATCH] Factor out a reuseable MessageFragment --- briar-android/res/layout/activity_share.xml | 6 - briar-android/res/layout/fragment_message.xml | 10 ++ .../res/layout/fragment_share_message.xml | 28 ---- .../android/sharing/BaseMessageFragment.java | 94 ++++++++++++ .../android/sharing/ShareActivity.java | 137 +++++++++++++----- .../android/sharing/ShareBlogActivity.java | 28 ++-- .../sharing/ShareBlogMessageFragment.java | 69 ++------- .../android/sharing/ShareForumActivity.java | 31 ++-- .../sharing/ShareForumMessageFragment.java | 67 ++------- .../android/sharing/ShareMessageFragment.java | 135 ----------------- 10 files changed, 271 insertions(+), 334 deletions(-) delete mode 100644 briar-android/res/layout/activity_share.xml create mode 100644 briar-android/res/layout/fragment_message.xml delete mode 100644 briar-android/res/layout/fragment_share_message.xml create mode 100644 briar-android/src/org/briarproject/android/sharing/BaseMessageFragment.java delete mode 100644 briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java diff --git a/briar-android/res/layout/activity_share.xml b/briar-android/res/layout/activity_share.xml deleted file mode 100644 index 80f19387f..000000000 --- a/briar-android/res/layout/activity_share.xml +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/briar-android/res/layout/fragment_message.xml b/briar-android/res/layout/fragment_message.xml new file mode 100644 index 000000000..168ff34a4 --- /dev/null +++ b/briar-android/res/layout/fragment_message.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/briar-android/res/layout/fragment_share_message.xml b/briar-android/res/layout/fragment_share_message.xml deleted file mode 100644 index 45b33c0ba..000000000 --- a/briar-android/res/layout/fragment_share_message.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - diff --git a/briar-android/src/org/briarproject/android/sharing/BaseMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/BaseMessageFragment.java new file mode 100644 index 000000000..bb26a29ad --- /dev/null +++ b/briar-android/src/org/briarproject/android/sharing/BaseMessageFragment.java @@ -0,0 +1,94 @@ +package org.briarproject.android.sharing; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.StringRes; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.R; +import org.briarproject.android.fragment.BaseFragment; +import org.briarproject.android.view.LargeTextInputView; +import org.briarproject.android.view.TextInputView.TextInputListener; +import org.briarproject.util.StringUtils; + +import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; +import static org.briarproject.util.StringUtils.truncateUtf8; + +abstract class BaseMessageFragment extends BaseFragment + implements TextInputListener { + + protected LargeTextInputView message; + private MessageFragmentListener listener; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + listener = (MessageFragmentListener) context; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + // allow for "up" button to act as back button + setHasOptionsMenu(true); + + // inflate view + View v = inflater.inflate(R.layout.fragment_message, container, + false); + message = (LargeTextInputView) v.findViewById(R.id.messageView); + message.setButtonText(getString(getButtonText())); + message.setHint(getHintText()); + message.setListener(this); + + return v; + } + + protected void setTitle(int res) { + listener.setTitle(res); + } + + protected abstract @StringRes int getButtonText(); + protected abstract @StringRes int getHintText(); + + @Override + public void onStart() { + super.onStart(); + message.showSoftKeyboard(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + listener.onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onSendClick(String msg) { + // disable button to prevent accidental double actions + message.setSendButtonEnabled(false); + message.hideSoftKeyboard(); + + msg = truncateUtf8(msg, MAX_INVITATION_MESSAGE_LENGTH); + listener.onButtonClick(msg); + } + + public interface MessageFragmentListener { + + void onBackPressed(); + + void setTitle(@StringRes int titleRes); + + void onButtonClick(String message); + + } + +} diff --git a/briar-android/src/org/briarproject/android/sharing/ShareActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareActivity.java index abef634fe..85c1cbc2d 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareActivity.java @@ -2,11 +2,14 @@ package org.briarproject.android.sharing; import android.content.Intent; import android.os.Bundle; -import android.view.View; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.BriarActivity; import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; +import org.briarproject.android.sharing.BaseMessageFragment.MessageFragmentListener; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DbException; @@ -15,34 +18,77 @@ import org.briarproject.api.sync.GroupId; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.logging.Logger; + +import static android.widget.Toast.LENGTH_SHORT; +import static java.util.logging.Level.WARNING; public abstract class ShareActivity extends BriarActivity implements - BaseFragmentListener, ContactSelectorListener { + BaseFragmentListener, ContactSelectorListener, MessageFragmentListener { + private final static Logger LOG = + Logger.getLogger(ShareActivity.class.getName()); final static String CONTACTS = "contacts"; - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + private volatile GroupId groupId; + private volatile Collection contacts; - setContentView(R.layout.activity_share); + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + + setContentView(R.layout.activity_fragment_container); Intent i = getIntent(); byte[] b = i.getByteArrayExtra(GROUP_ID); if (b == null) throw new IllegalStateException("No GroupId"); - GroupId groupId = new GroupId(b); + groupId = new GroupId(b); - if (savedInstanceState == null) { + if (bundle == null) { ContactSelectorFragment contactSelectorFragment = ContactSelectorFragment.newInstance(groupId); getSupportFragmentManager().beginTransaction() - .add(R.id.shareContainer, contactSelectorFragment) + .add(R.id.fragmentContainer, contactSelectorFragment) .commit(); + } else { + ArrayList intContacts = + bundle.getIntegerArrayList(CONTACTS); + if (intContacts != null) { + contacts = getContactsFromIntegers(intContacts); + } } } - abstract ShareMessageFragment getMessageFragment(GroupId groupId, - Collection contacts); + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (contacts != null) { + outState.putIntegerArrayList(CONTACTS, + getContactsFromIds(contacts)); + } + } + + @UiThread + @Override + public void contactsSelected(GroupId groupId, + Collection contacts) { + this.groupId = groupId; + this.contacts = contacts; + + BaseMessageFragment messageFragment = getMessageFragment(); + + getSupportFragmentManager().beginTransaction() + .setCustomAnimations(android.R.anim.fade_in, + android.R.anim.fade_out, + android.R.anim.slide_in_left, + android.R.anim.slide_out_right) + .replace(R.id.fragmentContainer, messageFragment, + ContactSelectorFragment.TAG) + .addToBackStack(null) + .commit(); + } + + abstract BaseMessageFragment getMessageFragment(); /** * This must only be called from a DbThread @@ -50,26 +96,8 @@ public abstract class ShareActivity extends BriarActivity implements public abstract boolean isDisabled(GroupId groupId, Contact c) throws DbException; - @Override - public void contactsSelected(GroupId groupId, - Collection contacts) { - ShareMessageFragment messageFragment = - getMessageFragment(groupId, contacts); - - getSupportFragmentManager().beginTransaction() - .setCustomAnimations(android.R.anim.fade_in, - android.R.anim.fade_out, - android.R.anim.slide_in_left, - android.R.anim.slide_out_right) - .replace(R.id.shareContainer, messageFragment, - ContactSelectorFragment.TAG) - .addToBackStack(null) - .commit(); - } - static ArrayList getContactsFromIds( Collection contacts) { - // transform ContactIds to Integers so they can be added to a bundle ArrayList intContacts = new ArrayList<>(contacts.size()); for (ContactId contactId : contacts) { @@ -78,15 +106,8 @@ public abstract class ShareActivity extends BriarActivity implements return intContacts; } - void sharingSuccessful(View v) { - setResult(RESULT_OK); - hideSoftKeyboard(v); - supportFinishAfterTransition(); - } - static Collection getContactsFromIntegers( ArrayList intContacts) { - // turn contact integers from a bundle back to ContactIds List contacts = new ArrayList<>(intContacts.size()); for (Integer c : intContacts) { @@ -95,6 +116,50 @@ public abstract class ShareActivity extends BriarActivity implements return contacts; } + @UiThread + @Override + public void onButtonClick(String message) { + share(message); + setResult(RESULT_OK); + supportFinishAfterTransition(); + } + + private void share(final String msg) { + runOnDbThread(new Runnable() { + @Override + public void run() { + try { + for (ContactId c : contacts) { + share(groupId, c, msg); + } + } catch (DbException e) { + // TODO proper error handling + sharingError(); + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + } + }); + } + + /** + * This method must be run from the DbThread. + */ + protected abstract void share(GroupId g, ContactId c, String msg) + throws DbException; + + private void sharingError() { + runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + int res = getSharingError(); + Toast.makeText(ShareActivity.this, res, LENGTH_SHORT).show(); + } + }); + } + + protected abstract @StringRes int getSharingError(); + @Override public void onFragmentCreated(String tag) { diff --git a/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java index b102453e5..d4ad59a6a 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java @@ -1,5 +1,6 @@ package org.briarproject.android.sharing; +import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.contact.Contact; @@ -7,18 +8,17 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DbException; import org.briarproject.api.sync.GroupId; -import java.util.Collection; - import javax.inject.Inject; public class ShareBlogActivity extends ShareActivity { + // Fields that are accessed from background threads must be volatile @Inject - volatile BlogSharingManager blogSharingManager; + protected volatile BlogSharingManager blogSharingManager; - ShareMessageFragment getMessageFragment(GroupId groupId, - Collection contacts) { - return ShareBlogMessageFragment.newInstance(groupId, contacts); + @Override + BaseMessageFragment getMessageFragment() { + return ShareBlogMessageFragment.newInstance(); } @Override @@ -26,10 +26,20 @@ public class ShareBlogActivity extends ShareActivity { component.inject(this); } - /** - * This must only be called from a DbThread - */ + @Override public boolean isDisabled(GroupId groupId, Contact c) throws DbException { return !blogSharingManager.canBeShared(groupId, c); } + + @Override + protected void share(GroupId g, ContactId c, String msg) + throws DbException { + blogSharingManager.sendInvitation(g, c, msg); + } + + @Override + protected int getSharingError() { + return R.string.blogs_sharing_error; + } + } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java index d9f944ab0..6d4dfb7b2 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java @@ -4,38 +4,16 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.ActivityComponent; -import org.briarproject.api.blogs.BlogSharingManager; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.db.DbException; -import org.briarproject.api.sync.GroupId; -import java.util.Collection; -import java.util.logging.Logger; - -import javax.inject.Inject; - -import static android.widget.Toast.LENGTH_SHORT; -import static java.util.logging.Level.WARNING; - -public class ShareBlogMessageFragment extends ShareMessageFragment { +public class ShareBlogMessageFragment extends BaseMessageFragment { public final static String TAG = ShareBlogMessageFragment.class.getName(); - private static final Logger LOG = Logger.getLogger(TAG); - // Fields that are accessed from background threads must be volatile - @Inject - protected volatile BlogSharingManager blogSharingManager; - - public static ShareBlogMessageFragment newInstance(GroupId groupId, - Collection contacts) { - - ShareBlogMessageFragment fragment = new ShareBlogMessageFragment(); - fragment.setArguments(getArguments(groupId, contacts)); - return fragment; + public static ShareBlogMessageFragment newInstance() { + return new ShareBlogMessageFragment(); } @Override @@ -43,10 +21,17 @@ public class ShareBlogMessageFragment extends ShareMessageFragment { Bundle savedInstanceState) { setTitle(R.string.blogs_sharing_share); + return super.onCreateView(inflater, container, savedInstanceState); + } - View v = super.onCreateView(inflater, container, savedInstanceState); - ui.message.setButtonText(getString(R.string.blogs_sharing_button)); - return v; + @Override + protected int getButtonText() { + return R.string.blogs_sharing_button; + } + + @Override + protected int getHintText() { + return R.string.forum_share_message; } @Override @@ -59,32 +44,4 @@ public class ShareBlogMessageFragment extends ShareMessageFragment { return TAG; } - @Override - protected void share(final String msg) { - listener.runOnDbThread(new Runnable() { - @Override - public void run() { - try { - for (ContactId c : getContacts()) { - blogSharingManager.sendInvitation(getGroupId(), c, msg); - } - } catch (DbException e) { - sharingError(); - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - }); - } - - @Override - protected void sharingError() { - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - int res = R.string.blogs_sharing_error; - Toast.makeText(getContext(), res, LENGTH_SHORT).show(); - } - }); - } } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java index 1f7653537..89093a2b0 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java @@ -1,5 +1,6 @@ package org.briarproject.android.sharing; +import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -7,17 +8,17 @@ import org.briarproject.api.db.DbException; import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.sync.GroupId; -import java.util.Collection; - import javax.inject.Inject; public class ShareForumActivity extends ShareActivity { - @Inject - volatile ForumSharingManager forumSharingManager; - ShareMessageFragment getMessageFragment(GroupId groupId, - Collection contacts) { - return ShareForumMessageFragment.newInstance(groupId, contacts); + // Fields that are accessed from background threads must be volatile + @Inject + protected volatile ForumSharingManager forumSharingManager; + + @Override + BaseMessageFragment getMessageFragment() { + return ShareForumMessageFragment.newInstance(); } @Override @@ -25,10 +26,20 @@ public class ShareForumActivity extends ShareActivity { component.inject(this); } - /** - * This must only be called from a DbThread - */ + @Override public boolean isDisabled(GroupId groupId, Contact c) throws DbException { return !forumSharingManager.canBeShared(groupId, c); } + + @Override + protected void share(GroupId g, ContactId c, String msg) + throws DbException { + forumSharingManager.sendInvitation(g, c, msg); + } + + @Override + protected int getSharingError() { + return R.string.forum_share_error; + } + } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java index 8414096f0..7824567a3 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java @@ -4,38 +4,16 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.ActivityComponent; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.db.DbException; -import org.briarproject.api.forum.ForumSharingManager; -import org.briarproject.api.sync.GroupId; -import java.util.Collection; -import java.util.logging.Logger; - -import javax.inject.Inject; - -import static android.widget.Toast.LENGTH_SHORT; -import static java.util.logging.Level.WARNING; - -public class ShareForumMessageFragment extends ShareMessageFragment { +public class ShareForumMessageFragment extends BaseMessageFragment { public final static String TAG = ShareForumMessageFragment.class.getName(); - private static final Logger LOG = Logger.getLogger(TAG); - // Fields that are accessed from background threads must be volatile - @Inject - protected volatile ForumSharingManager forumSharingManager; - - public static ShareForumMessageFragment newInstance(GroupId groupId, - Collection contacts) { - - ShareForumMessageFragment fragment = new ShareForumMessageFragment(); - fragment.setArguments(getArguments(groupId, contacts)); - return fragment; + public static ShareForumMessageFragment newInstance() { + return new ShareForumMessageFragment(); } @Override @@ -46,6 +24,16 @@ public class ShareForumMessageFragment extends ShareMessageFragment { return super.onCreateView(inflater, container, savedInstanceState); } + @Override + protected int getButtonText() { + return R.string.forum_share_button; + } + + @Override + protected int getHintText() { + return R.string.forum_share_message; + } + @Override public void injectFragment(ActivityComponent component) { component.inject(this); @@ -56,33 +44,4 @@ public class ShareForumMessageFragment extends ShareMessageFragment { return TAG; } - @Override - protected void share(final String msg) { - listener.runOnDbThread(new Runnable() { - @Override - public void run() { - try { - for (ContactId c : getContacts()) { - forumSharingManager. - sendInvitation(getGroupId(), c, msg); - } - } catch (DbException e) { - sharingError(); - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - }); - } - - @Override - protected void sharingError() { - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - int res = R.string.forum_share_error; - Toast.makeText(getContext(), res, LENGTH_SHORT).show(); - } - }); - } } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java deleted file mode 100644 index ea79398cf..000000000 --- a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.briarproject.android.sharing; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - -import org.briarproject.R; -import org.briarproject.android.fragment.BaseFragment; -import org.briarproject.android.view.LargeTextInputView; -import org.briarproject.android.view.TextInputView.TextInputListener; -import org.briarproject.api.blogs.BlogSharingManager; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.forum.ForumSharingManager; -import org.briarproject.api.sync.GroupId; -import org.briarproject.util.StringUtils; - -import java.util.ArrayList; -import java.util.Collection; - -import javax.inject.Inject; - -import static org.briarproject.android.sharing.ShareActivity.CONTACTS; -import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds; -import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; -import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; - -abstract class ShareMessageFragment extends BaseFragment - implements TextInputListener { - - protected ViewHolder ui; - private ShareActivity shareActivity; - - // Fields that are accessed from background threads must be volatile - @Inject - protected volatile ForumSharingManager forumSharingManager; - @Inject - protected volatile BlogSharingManager blogSharingManager; - private volatile GroupId groupId; - private volatile Collection contacts; - - protected static Bundle getArguments(GroupId groupId, - Collection contacts) { - - Bundle args = new Bundle(); - args.putByteArray(GROUP_ID, groupId.getBytes()); - args.putIntegerArrayList(CONTACTS, getContactsFromIds(contacts)); - return args; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - shareActivity = (ShareActivity) context; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - // allow for "up" button to act as back button - setHasOptionsMenu(true); - - // get groupID and contactIDs from fragment arguments - groupId = new GroupId(getArguments().getByteArray(GROUP_ID)); - ArrayList intContacts = - getArguments().getIntegerArrayList(CONTACTS); - if (intContacts == null) throw new IllegalArgumentException(); - contacts = ShareActivity.getContactsFromIntegers(intContacts); - - // inflate view - View v = inflater.inflate(R.layout.fragment_share_message, container, - false); - ui = new ViewHolder(v); - ui.message.setListener(this); - - return v; - } - - @Override - public void onStart() { - super.onStart(); - ui.message.showSoftKeyboard(); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - shareActivity.onBackPressed(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - protected void setTitle(int res) { - shareActivity.setTitle(res); - } - - @Override - public void onSendClick(String msg) { - // disable button to prevent accidental double invitations - ui.message.setSendButtonEnabled(false); - - msg = StringUtils.truncateUtf8(msg, MAX_INVITATION_MESSAGE_LENGTH); - share(msg); - - // don't wait for the invitation to be made before finishing activity - shareActivity.sharingSuccessful(ui.message); - } - - abstract void share(final String msg); - - abstract void sharingError(); - - protected Collection getContacts() { - return contacts; - } - - protected GroupId getGroupId() { - return groupId; - } - - protected static class ViewHolder { - protected final LargeTextInputView message; - - private ViewHolder(View v) { - message = (LargeTextInputView) v - .findViewById(R.id.invitationMessageView); - } - } -}