diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java index bb3dda396..94f75cb8c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java @@ -19,7 +19,7 @@ import org.briarproject.briar.android.controller.handler.UiExceptionHandler; import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.view.TextInputView; -import org.briarproject.briar.android.view.TextInputView.TextInputListener; +import org.briarproject.briar.android.view.TextInputView.SendListener; import java.util.List; @@ -32,10 +32,11 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.blog.BasePostFragment.POST_ID; +import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_POST_TEXT_LENGTH; @MethodsNotNullByDefault @ParametersNotNullByDefault -public class ReblogFragment extends BaseFragment implements TextInputListener { +public class ReblogFragment extends BaseFragment implements SendListener { public static final String TAG = ReblogFragment.class.getName(); @@ -80,7 +81,8 @@ public class ReblogFragment extends BaseFragment implements TextInputListener { View v = inflater.inflate(R.layout.fragment_reblog, container, false); ui = new ViewHolder(v); ui.post.setTransitionName(postId); - ui.input.setSendButtonEnabled(false); + ui.input.setEnabled(false); + ui.input.setMaxTextLength(MAX_BLOG_POST_TEXT_LENGTH); showProgressBar(); return v; @@ -116,7 +118,7 @@ public class ReblogFragment extends BaseFragment implements TextInputListener { ui.post.hideReblogButton(); ui.input.setListener(this); - ui.input.setSendButtonEnabled(true); + ui.input.setEnabled(true); ui.scrollView.post(() -> ui.scrollView.fullScroll(FOCUS_DOWN)); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java index e54764d78..e26e2e05e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java @@ -4,8 +4,6 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; -import android.text.Editable; -import android.text.TextWatcher; import android.view.KeyEvent; import android.view.MenuItem; import android.widget.ProgressBar; @@ -23,7 +21,7 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.view.TextInputView; -import org.briarproject.briar.android.view.TextInputView.TextInputListener; +import org.briarproject.briar.android.view.TextInputView.SendListener; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogPost; @@ -40,13 +38,12 @@ import static android.view.View.VISIBLE; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; -import static org.briarproject.bramble.util.StringUtils.truncateUtf8; import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_POST_TEXT_LENGTH; @MethodsNotNullByDefault @ParametersNotNullByDefault public class WriteBlogPostActivity extends BriarActivity - implements OnEditorActionListener, TextInputListener { + implements OnEditorActionListener, SendListener { private static final Logger LOG = Logger.getLogger(WriteBlogPostActivity.class.getName()); @@ -78,23 +75,7 @@ public class WriteBlogPostActivity extends BriarActivity setContentView(R.layout.activity_write_blog_post); input = findViewById(R.id.textInput); - input.setSendButtonEnabled(false); - input.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - - @Override - public void afterTextChanged(Editable s) { - enableOrDisablePublishButton(); - } - }); + input.setMaxTextLength(MAX_BLOG_POST_TEXT_LENGTH); input.setListener(this); progressBar = findViewById(R.id.progressBar); @@ -134,20 +115,15 @@ public class WriteBlogPostActivity extends BriarActivity return true; } - private void enableOrDisablePublishButton() { - input.setSendButtonEnabled(!input.isEmpty()); - } - @Override public void onSendClick(@Nullable String text, List imageUris) { - if (isNullOrEmpty(text)) return; + if (isNullOrEmpty(text)) throw new AssertionError(); // hide publish button, show progress bar input.hideSoftKeyboard(); input.setVisibility(GONE); progressBar.setVisibility(VISIBLE); - text = truncateUtf8(text, MAX_BLOG_POST_TEXT_LENGTH); storePost(text); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index aa183ef74..890e8f16a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -65,7 +65,7 @@ import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.TextInputView; import org.briarproject.briar.android.view.TextInputView.AttachImageListener; -import org.briarproject.briar.android.view.TextInputView.TextInputListener; +import org.briarproject.briar.android.view.TextInputView.SendListener; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.blog.BlogSharingManager; import org.briarproject.briar.api.client.ProtocolStateException; @@ -118,7 +118,6 @@ import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; -import static org.briarproject.bramble.util.StringUtils.truncateUtf8; import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_IMAGE_ATTACHMENTS; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_ATTACH_IMAGE; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_INTRODUCTION; @@ -136,7 +135,7 @@ import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.S @MethodsNotNullByDefault @ParametersNotNullByDefault public class ConversationActivity extends BriarActivity - implements EventListener, ConversationListener, TextInputListener, + implements EventListener, ConversationListener, SendListener, TextCache, AttachmentCache, AttachImageListener { public static final String CONTACT_ID = "briar.CONTACT_ID"; @@ -256,6 +255,8 @@ public class ConversationActivity extends BriarActivity list.setEmptyText(getString(R.string.no_private_messages)); textInputView = findViewById(R.id.text_input_container); + textInputView.setMaxTextLength(MAX_PRIVATE_MESSAGE_TEXT_LENGTH); + textInputView.setEnabled(false); textInputView.setListener(this); if (FEATURE_FLAG_IMAGE_ATTACHMENTS) { textInputView.setAttachImageListener(this); @@ -416,7 +417,7 @@ public class ConversationActivity extends BriarActivity runOnUiThreadUnlessDestroyed(() -> { if (revision == adapter.getRevision()) { adapter.incrementRevision(); - textInputView.setSendButtonEnabled(true); + textInputView.setEnabled(true); List items = createItems(headers); adapter.addAll(items); list.showData(); @@ -592,16 +593,15 @@ public class ConversationActivity extends BriarActivity public void onSendClick(@Nullable String text, List imageUris) { if (!imageUris.isEmpty()) { Toast.makeText(this, "Not yet implemented.", LENGTH_LONG).show(); - textInputView.setText(""); + textInputView.clearText(); return; } - if (isNullOrEmpty(text)) return; - text = truncateUtf8(text, MAX_PRIVATE_MESSAGE_TEXT_LENGTH); + if (isNullOrEmpty(text)) throw new AssertionError(); long timestamp = System.currentTimeMillis(); timestamp = Math.max(timestamp, getMinTimestampForNewMessage()); if (messagingGroupId == null) loadGroupId(text, timestamp); else createMessage(text, timestamp); - textInputView.setText(""); + textInputView.clearText(); } private long getMinTimestampForNewMessage() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java index 96be4eae5..651a05413 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java @@ -23,7 +23,7 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.view.TextInputView; -import org.briarproject.briar.android.view.TextInputView.TextInputListener; +import org.briarproject.briar.android.view.TextInputView.SendListener; import org.briarproject.briar.api.introduction.IntroductionManager; import java.util.List; @@ -40,14 +40,13 @@ import static android.view.View.VISIBLE; import static android.widget.Toast.LENGTH_SHORT; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.util.LogUtils.logException; -import static org.briarproject.bramble.util.StringUtils.truncateUtf8; import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; @MethodsNotNullByDefault @ParametersNotNullByDefault public class IntroductionMessageFragment extends BaseFragment - implements TextInputListener { + implements SendListener { public static final String TAG = IntroductionMessageFragment.class.getName(); @@ -103,7 +102,8 @@ public class IntroductionMessageFragment extends BaseFragment View v = inflater.inflate(R.layout.introduction_message, container, false); ui = new ViewHolder(v); - ui.message.setSendButtonEnabled(false); + ui.message.setMaxTextLength(MAX_INTRODUCTION_TEXT_LENGTH); + ui.message.setEnabled(false); return v; } @@ -168,7 +168,7 @@ public class IntroductionMessageFragment extends BaseFragment // show views ui.notPossible.setVisibility(GONE); ui.message.setVisibility(VISIBLE); - ui.message.setSendButtonEnabled(true); + ui.message.setEnabled(true); ui.message.showSoftKeyboard(); } else { ui.notPossible.setVisibility(VISIBLE); @@ -192,11 +192,8 @@ public class IntroductionMessageFragment extends BaseFragment @Override public void onSendClick(@Nullable String text, List imageUris) { // disable button to prevent accidental double invitations - ui.message.setSendButtonEnabled(false); + ui.message.setEnabled(false); - if (text != null) { - text = truncateUtf8(text, MAX_INTRODUCTION_TEXT_LENGTH); - } makeIntroduction(contact1, contact2, text); // don't wait for the introduction to be made before finishing activity diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java index 65b2587e9..cc60fa1e6 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java @@ -196,7 +196,7 @@ public class GroupActivity extends private void setGroupEnabled(boolean enabled) { isDissolved = !enabled; - textInput.setSendButtonEnabled(enabled); + textInput.setEnabled(enabled); list.getRecyclerView().setAlpha(enabled ? 1f : 0.5f); if (!enabled) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupController.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupController.java index 56a7614c0..6d4692c71 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupController.java @@ -1,5 +1,7 @@ package org.briarproject.briar.android.privategroup.creation; +import android.support.annotation.Nullable; + import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -18,6 +20,7 @@ public interface CreateGroupController ResultExceptionHandler result); void sendInvitation(GroupId g, Collection contacts, - String text, ResultExceptionHandler result); + @Nullable String text, + ResultExceptionHandler result); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java index efdd03bb3..75ddbb53d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java @@ -1,5 +1,7 @@ package org.briarproject.briar.android.privategroup.creation; +import android.support.annotation.Nullable; + import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactManager; @@ -123,7 +125,8 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl @Override public void sendInvitation(GroupId g, Collection contactIds, - String text, ResultExceptionHandler handler) { + @Nullable String text, + ResultExceptionHandler handler) { runOnDbThread(() -> { try { LocalAuthor localAuthor = identityManager.getLocalAuthor(); @@ -144,7 +147,7 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl } private void signInvitations(GroupId g, LocalAuthor localAuthor, - Collection contacts, String text, + Collection contacts, @Nullable String text, ResultExceptionHandler handler) { cryptoExecutor.execute(() -> { long timestamp = clock.currentTimeMillis(); @@ -160,15 +163,14 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl } private void sendInvitations(GroupId g, - Collection contexts, String text, + Collection contexts, @Nullable String text, ResultExceptionHandler handler) { runOnDbThread(() -> { try { - String txt = text.isEmpty() ? null : text; for (InvitationContext context : contexts) { try { groupInvitationManager.sendInvitation(g, - context.contactId, txt, context.timestamp, + context.contactId, text, context.timestamp, context.signature); } catch (NoSuchContactException e) { // Continue diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/GroupInviteActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/GroupInviteActivity.java index 64dd54404..4ae58201d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/GroupInviteActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/GroupInviteActivity.java @@ -55,7 +55,7 @@ public class GroupInviteActivity extends ContactSelectorActivity } @Override - public boolean onButtonClick(String text) { + public void onButtonClick(@Nullable String text) { if (groupId == null) throw new IllegalStateException("GroupId was not initialized"); controller.sendInvitation(groupId, contacts, text, @@ -72,7 +72,6 @@ public class GroupInviteActivity extends ContactSelectorActivity handleDbException(exception); } }); - return true; } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java index 1934acd48..7f732a760 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java @@ -6,7 +6,6 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.annotation.UiThread; -import android.support.design.widget.Snackbar; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -18,17 +17,14 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.view.LargeTextInputView; -import org.briarproject.briar.android.view.TextInputView.TextInputListener; +import org.briarproject.briar.android.view.TextInputView.SendListener; import java.util.List; -import static android.support.design.widget.Snackbar.LENGTH_SHORT; -import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong; - @MethodsNotNullByDefault @ParametersNotNullByDefault public abstract class BaseMessageFragment extends BaseFragment - implements TextInputListener { + implements SendListener { protected LargeTextInputView message; private MessageFragmentListener listener; @@ -48,6 +44,7 @@ public abstract class BaseMessageFragment extends BaseFragment View v = inflater.inflate(R.layout.fragment_message, container, false); message = v.findViewById(R.id.messageView); + message.setMaxTextLength(listener.getMaximumTextLength()); message.setButtonText(getString(getButtonText())); message.setHint(getHintText()); message.setListener(this); @@ -84,20 +81,11 @@ public abstract class BaseMessageFragment extends BaseFragment @Override public void onSendClick(@Nullable String text, List imageUris) { - if (text == null) return; - if (utf8IsTooLong(text, listener.getMaximumTextLength())) { - Snackbar.make(message, R.string.text_too_long, LENGTH_SHORT).show(); - return; - } - // disable button to prevent accidental double actions - message.setSendButtonEnabled(false); + message.setEnabled(false); message.hideSoftKeyboard(); - if(!listener.onButtonClick(text)) { - message.setSendButtonEnabled(true); - message.showSoftKeyboard(); - } + listener.onButtonClick(text); } @UiThread @@ -108,8 +96,7 @@ public abstract class BaseMessageFragment extends BaseFragment void setTitle(@StringRes int titleRes); - /** Returns true when the button click has been consumed. */ - boolean onButtonClick(String text); + void onButtonClick(@Nullable String text); int getMaximumTextLength(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareActivity.java index 4c7e6268a..4d39005a2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareActivity.java @@ -41,13 +41,12 @@ public abstract class ShareActivity extends ContactSelectorActivity @UiThread @Override - public boolean onButtonClick(String text) { + public void onButtonClick(@Nullable String text) { share(contacts, text); setResult(RESULT_OK); supportFinishAfterTransition(); - return true; } - abstract void share(Collection contacts, String text); + abstract void share(Collection contacts, @Nullable String text); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogActivity.java index 3a89eb994..56bd95f72 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogActivity.java @@ -51,7 +51,7 @@ public class ShareBlogActivity extends ShareActivity { } @Override - void share(Collection contacts, String text) { + void share(Collection contacts, @Nullable String text) { controller.share(groupId, contacts, text, new UiExceptionHandler(this) { @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogController.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogController.java index 2500d8b59..16afbcded 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogController.java @@ -9,10 +9,12 @@ import org.briarproject.briar.android.controller.handler.ExceptionHandler; import java.util.Collection; +import javax.annotation.Nullable; + public interface ShareBlogController extends ContactSelectorController { - void share(GroupId g, Collection contacts, String text, + void share(GroupId g, Collection contacts, @Nullable String text, ExceptionHandler handler); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java index e00a09a43..26af4b3ca 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java @@ -20,12 +20,12 @@ import java.util.Collection; import java.util.concurrent.Executor; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.util.LogUtils.logException; -import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @Immutable @NotNullByDefault @@ -56,17 +56,16 @@ class ShareBlogControllerImpl extends ContactSelectorControllerImpl } @Override - public void share(GroupId g, Collection contacts, String text, - ExceptionHandler handler) { + public void share(GroupId g, Collection contacts, @Nullable + String text, ExceptionHandler handler) { runOnDbThread(() -> { try { - String txt = isNullOrEmpty(text) ? null : text; for (ContactId c : contacts) { try { long time = Math.max(clock.currentTimeMillis(), conversationManager.getGroupCount(c) .getLatestMsgTime() + 1); - blogSharingManager.sendInvitation(g, c, txt, time); + blogSharingManager.sendInvitation(g, c, text, time); } catch (NoSuchContactException | NoSuchGroupException e) { logException(LOG, WARNING, e); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumActivity.java index d4c5974e1..5969ea92d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumActivity.java @@ -51,7 +51,7 @@ public class ShareForumActivity extends ShareActivity { } @Override - void share(Collection contacts, String text) { + void share(Collection contacts, @Nullable String text) { controller.share(groupId, contacts, text, new UiExceptionHandler(this) { @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumController.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumController.java index 744605714..d63de47fa 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumController.java @@ -9,10 +9,12 @@ import org.briarproject.briar.android.controller.handler.ExceptionHandler; import java.util.Collection; +import javax.annotation.Nullable; + public interface ShareForumController extends ContactSelectorController { - void share(GroupId g, Collection contacts, String text, + void share(GroupId g, Collection contacts, @Nullable String text, ExceptionHandler handler); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java index a2a4f308d..9bbc6d3e7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java @@ -13,19 +13,19 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.android.contactselection.ContactSelectorControllerImpl; import org.briarproject.briar.android.controller.handler.ExceptionHandler; -import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.conversation.ConversationManager; +import org.briarproject.briar.api.forum.ForumSharingManager; import java.util.Collection; import java.util.concurrent.Executor; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.util.LogUtils.logException; -import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @Immutable @NotNullByDefault @@ -57,16 +57,15 @@ class ShareForumControllerImpl extends ContactSelectorControllerImpl @Override public void share(GroupId g, Collection contacts, - String text, ExceptionHandler handler) { + @Nullable String text, ExceptionHandler handler) { runOnDbThread(() -> { try { - String txt = isNullOrEmpty(text) ? null : text; for (ContactId c : contacts) { try { long time = Math.max(clock.currentTimeMillis(), conversationManager.getGroupCount(c) .getLatestMsgTime() + 1); - forumSharingManager.sendInvitation(g, c, txt, time); + forumSharingManager.sendInvitation(g, c, text, time); } catch (NoSuchContactException | NoSuchGroupException e) { logException(LOG, WARNING, e); } 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 d9534edb6..9429b0ed8 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 @@ -28,7 +28,7 @@ import org.briarproject.briar.android.threaded.ThreadListController.ThreadListDa import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener; import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.TextInputView; -import org.briarproject.briar.android.view.TextInputView.TextInputListener; +import org.briarproject.briar.android.view.TextInputView.SendListener; import org.briarproject.briar.android.view.UnreadMessageButton; import org.briarproject.briar.api.client.NamedGroup; import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout; @@ -44,14 +44,14 @@ import static android.support.design.widget.Snackbar.make; import static android.support.v7.widget.RecyclerView.NO_POSITION; import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE; import static java.util.logging.Level.INFO; -import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong; +import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; import static org.briarproject.briar.android.threaded.ThreadItemAdapter.UnreadCount; @MethodsNotNullByDefault @ParametersNotNullByDefault public abstract class ThreadListActivity> extends BriarActivity - implements ThreadListListener, TextInputListener, SharingListener, + implements ThreadListListener, SendListener, SharingListener, ThreadItemListener, ThreadListDataSource { protected static final String KEY_REPLY_ID = "replyId"; @@ -88,6 +88,7 @@ public abstract class ThreadListActivity imageUris) { - if (text == null || text.trim().length() == 0) - return; - if (utf8IsTooLong(text, getMaxTextLength())) { - displaySnackbar(R.string.text_too_long); - return; - } + if (isNullOrEmpty(text)) throw new AssertionError(); + I replyItem = adapter.getHighlightedItem(); UiResultExceptionHandler handler = new UiResultExceptionHandler(this) { @@ -372,7 +369,7 @@ public abstract class ThreadListActivity imageUris = emptyList(); - public TextInputAttachmentController(View v, EmojiEditText editText, - View sendButton, AttachImageListener listener) { + TextAttachmentController(View v, View sendButton, + TextInputController textInput) { + super(sendButton, textInput, true); imageLayout = v.findViewById(R.id.imageLayout); imageView = v.findViewById(R.id.imageView); @@ -72,20 +70,37 @@ class TextInputAttachmentController implements TextWatcher { v.findViewById(R.id.imageCancelButton); imageButton = v.findViewById(R.id.imageButton); - this.listener = listener; - this.sendButton = sendButton; - this.editText = editText; - this.textHint = editText.getHint().toString(); + textHint = textInput.getHint(); - editText.addTextChangedListener(this); imageButton.setOnClickListener(view -> onImageButtonClicked()); imageCancelButton.setOnClickListener(view -> { - editText.setText(null); + textInput.clearText(); reset(); }); + } + + public void setAttachImageListener(AttachImageListener imageListener) { + this.imageListener = imageListener; showImageButton(true); } + @Override + public void onTextValidityChanged(boolean isEmpty) { + if (imageUris.isEmpty()) showImageButton(isEmpty); + } + + @Override + void onSendButtonClicked() { + if (listener != null) { + if (textInput.isTooLong()) { + textInput.showError(); + return; + } + listener.onSendClick(textInput.getText(), imageUris); + } + reset(); + } + private void onImageButtonClicked() { Intent intent = new Intent(SDK_INT >= 19 ? ACTION_OPEN_DOCUMENT : ACTION_GET_CONTENT); @@ -93,7 +108,7 @@ class TextInputAttachmentController implements TextWatcher { intent.setType("image/*"); if (SDK_INT >= 18) // TODO set true to allow attaching multiple images intent.putExtra(EXTRA_ALLOW_MULTIPLE, false); - listener.onAttachImage(intent); + requireNonNull(imageListener).onAttachImage(intent); } void onImageReceived(@Nullable Intent resultData) { @@ -114,7 +129,7 @@ class TextInputAttachmentController implements TextWatcher { private void onNewUris() { if (imageUris.isEmpty()) return; showImageButton(false); - editText.setHint(R.string.image_caption_hint); + textInput.setHint(R.string.image_caption_hint); imageLayout.setVisibility(VISIBLE); GlideApp.with(imageView) .asBitmap() @@ -135,7 +150,7 @@ class TextInputAttachmentController implements TextWatcher { Object model, Target target, DataSource dataSource, boolean isFirstResource) { Palette.from(resource).generate( - TextInputAttachmentController.this::onPaletteGenerated); + TextAttachmentController.this::onPaletteGenerated); return false; } }) @@ -158,11 +173,12 @@ class TextInputAttachmentController implements TextWatcher { private void showImageButton(boolean showImageButton) { if (showImageButton) { imageButton.setVisibility(VISIBLE); + sendButton.setEnabled(false); if (SDK_INT <= 15) { sendButton.setVisibility(INVISIBLE); + imageButton.setEnabled(true); } else { sendButton.clearAnimation(); - sendButton.setEnabled(false); sendButton.animate().alpha(0f).withEndAction(() -> { sendButton.setVisibility(INVISIBLE); imageButton.setEnabled(true); @@ -172,51 +188,25 @@ class TextInputAttachmentController implements TextWatcher { } } else { sendButton.setVisibility(VISIBLE); + // enable/disable buttons right away to allow fast sending + sendButton.setEnabled(true); + imageButton.setEnabled(false); if (SDK_INT <= 15) { imageButton.setVisibility(INVISIBLE); } else { sendButton.clearAnimation(); sendButton.animate().alpha(1f).start(); imageButton.clearAnimation(); - imageButton.setEnabled(false); - imageButton.animate().alpha(0f).withEndAction(() -> { - imageButton.setVisibility(INVISIBLE); - sendButton.setEnabled(true); - }).start(); + imageButton.animate().alpha(0f).withEndAction(() -> + imageButton.setVisibility(INVISIBLE) + ).start(); } } } - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - // noop - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - if (start != 0 || !imageUris.isEmpty()) return; - if (s.length() > 0) showImageButton(false); - else showImageButton(true); - } - - @Override - public void afterTextChanged(Editable s) { - // noop - } - - public List getUris() { - return imageUris; - } - - public void saveHint(String hint) { - textHint = hint; - } - - void reset() { + private void reset() { // restore hint - editText.setHint(textHint); + textInput.setHint(textHint); // hide image layout imageLayout.setVisibility(GONE); // reset image URIs diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextInputController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextInputController.java new file mode 100644 index 000000000..991f37af1 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextInputController.java @@ -0,0 +1,165 @@ +package org.briarproject.briar.android.view; + +import android.content.Context; +import android.graphics.Rect; +import android.os.IBinder; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.support.design.widget.Snackbar; +import android.support.v7.widget.AppCompatImageButton; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +import com.vanniktech.emoji.EmojiEditText; +import com.vanniktech.emoji.EmojiPopup; +import com.vanniktech.emoji.RecentEmoji; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.R; + +import static android.content.Context.INPUT_METHOD_SERVICE; +import static android.support.design.widget.Snackbar.LENGTH_SHORT; +import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; +import static java.util.Objects.requireNonNull; +import static org.briarproject.briar.android.view.TextInputView.TextValidityListener; + +@UiThread +@NotNullByDefault +class TextInputController implements TextWatcher { + + private final Context ctx; + private final AppCompatImageButton emojiToggle; + private final EmojiPopup emojiPopup; + private final EmojiEditText editText; + + private @Nullable TextValidityListener listener; + private int maxLength = Integer.MAX_VALUE; + private final boolean emptyTextAllowed; + private boolean isEmpty = true; + + TextInputController(View rootView, AppCompatImageButton emojiToggle, + EmojiEditText editText, RecentEmoji recentEmoji, + boolean emptyTextAllowed) { + ctx = rootView.getContext(); + this.emojiToggle = emojiToggle; + this.editText = editText; + this.editText.addTextChangedListener(this); + this.editText.setOnClickListener(v -> showSoftKeyboard()); + emojiPopup = EmojiPopup.Builder + .fromRootView(rootView) + .setRecentEmoji(recentEmoji) + .setOnEmojiPopupShownListener(this::showKeyboardIcon) + .setOnEmojiPopupDismissListener(this::showEmojiIcon) + .build(this.editText); + this.emojiToggle.setOnClickListener(v -> emojiPopup.toggle()); + this.emptyTextAllowed = emptyTextAllowed; + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + if (emptyTextAllowed || listener == null) return; + if (s.toString().trim().length() == 0) { + if (!isEmpty) { + isEmpty = true; + listener.onTextValidityChanged(true); + } + } else if (isEmpty) { + isEmpty = false; + listener.onTextValidityChanged(false); + } + } + + @Override + public void afterTextChanged(Editable s) { + } + + void setMaxLength(int maxLength) { + this.maxLength = maxLength; + } + + boolean isTooLong() { + return editText.getText() != null && + editText.getText().toString().trim().length() > maxLength; + } + + /** + * Returns the current text or {@code null}, + * if it is empty or only consists of white-spaces. + */ + @Nullable + String getText() { + Editable editable = editText.getText(); + if (editable == null || editable.toString().trim().length() == 0) + return null; + return editable.toString().trim(); + } + + void clearText() { + editText.setText(null); + } + + CharSequence getHint() { + return editText.getHint(); + } + + void setHint(@StringRes int res) { + setHint(ctx.getString(res)); + } + + void setHint(CharSequence hint) { + editText.setHint(hint); + } + + void setTextValidityListener(@Nullable TextValidityListener listener) { + this.listener = listener; + } + + void showError() { + Snackbar.make(editText, R.string.text_too_long, LENGTH_SHORT).show(); + } + + boolean requestFocus(int direction, Rect previouslyFocusedRect) { + return editText.requestFocus(direction, previouslyFocusedRect); + } + + void onDetachedFromWindow() { + if (emojiPopup.isShowing()) emojiPopup.dismiss(); + } + + void showSoftKeyboard() { + Object o = ctx.getSystemService(INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) requireNonNull(o); + imm.showSoftInput(editText, SHOW_IMPLICIT); + } + + void hideSoftKeyboard() { + if (emojiPopup.isShowing()) emojiPopup.dismiss(); + IBinder token = editText.getWindowToken(); + Object o = ctx.getSystemService(INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) requireNonNull(o); + imm.hideSoftInputFromWindow(token, 0); + } + + private void showEmojiIcon() { + emojiToggle.setImageResource(R.drawable.ic_emoji_toggle); + } + + private void showKeyboardIcon() { + emojiToggle.setImageResource(R.drawable.ic_keyboard); + } + + public void setEnabled(boolean enabled) { + editText.setEnabled(enabled); + emojiToggle.setEnabled(enabled); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextInputView.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextInputView.java index b98aac366..870e756f5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextInputView.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextInputView.java @@ -6,22 +6,17 @@ import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Rect; import android.net.Uri; -import android.os.IBinder; import android.os.Parcelable; import android.support.annotation.CallSuper; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.annotation.UiThread; import android.support.v7.widget.AppCompatImageButton; -import android.text.Editable; -import android.text.TextWatcher; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; -import android.view.inputmethod.InputMethodManager; import com.vanniktech.emoji.EmojiEditText; -import com.vanniktech.emoji.EmojiPopup; import com.vanniktech.emoji.RecentEmoji; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; @@ -34,11 +29,8 @@ import java.util.List; import javax.inject.Inject; -import static android.content.Context.INPUT_METHOD_SERVICE; import static android.content.Context.LAYOUT_INFLATER_SERVICE; import static android.view.KeyEvent.KEYCODE_ENTER; -import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; -import static java.util.Collections.emptyList; import static java.util.Objects.requireNonNull; @UiThread @@ -49,16 +41,14 @@ public class TextInputView extends KeyboardAwareLinearLayout { @Inject RecentEmoji recentEmoji; - @Nullable - TextInputListener listener; - @Nullable - TextInputAttachmentController attachmentController; - - AppCompatImageButton emojiToggle; + TextInputController textInputController; + TextSendController textSendController; EmojiEditText editText; - EmojiPopup emojiPopup; View sendButton; + @Nullable + TextAttachmentController attachmentController; + public TextInputView(Context context) { this(context, null); } @@ -90,34 +80,42 @@ public class TextInputView extends KeyboardAwareLinearLayout { @CallSuper protected void setUpViews(Context context, @Nullable AttributeSet attrs) { - emojiToggle = findViewById(R.id.emoji_toggle); - editText = findViewById(R.id.input_text); - emojiPopup = EmojiPopup.Builder - .fromRootView(this) - .setRecentEmoji(recentEmoji) - .setOnEmojiPopupShownListener(this::showKeyboardIcon) - .setOnEmojiPopupDismissListener(this::showEmojiIcon) - .build(editText); - sendButton = findViewById(R.id.btn_send); - // get attributes TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.TextInputView); String hint = attributes.getString(R.styleable.TextInputView_hint); + boolean allowEmptyText = attributes + .getBoolean(R.styleable.TextInputView_allowEmptyText, false); + boolean supportsAttachments = attributes + .getBoolean(R.styleable.TextInputView_supportsAttachments, false); attributes.recycle(); - if (hint != null) setHint(hint); + // set up input controller + AppCompatImageButton emojiToggle = findViewById(R.id.emoji_toggle); + editText = findViewById(R.id.input_text); + textInputController = new TextInputController(this, emojiToggle, + editText, recentEmoji, allowEmptyText); + if (hint != null) textInputController.setHint(hint); - emojiToggle.setOnClickListener(v -> emojiPopup.toggle()); - editText.setOnClickListener(v -> showSoftKeyboard()); + // set up sending controller + sendButton = findViewById(R.id.btn_send); + if (supportsAttachments) { + textSendController = new TextAttachmentController(this, sendButton, + textInputController); + } else { + textSendController = new TextSendController(sendButton, + textInputController, allowEmptyText); + } + textInputController.setTextValidityListener(textSendController); + + // support sending with Ctrl+Enter editText.setOnKeyListener((v, keyCode, event) -> { if (keyCode == KEYCODE_ENTER && event.isCtrlPressed()) { - onSendButtonClicked(); + textSendController.onSendButtonClicked(); return true; } return false; }); - sendButton.setOnClickListener(v -> onSendButtonClicked()); } @Nullable @@ -141,41 +139,13 @@ public class TextInputView extends KeyboardAwareLinearLayout { } } - public void setListener(TextInputListener listener) { - this.listener = listener; + public void setListener(SendListener listener) { + textSendController.setSendListener(listener); } - /** - * Call this during onCreate() to enable image attachment support. - * Do not call it twice! - */ public void setAttachImageListener(AttachImageListener imageListener) { - if (attachmentController != null) throw new IllegalStateException(); - attachmentController = new TextInputAttachmentController(getRootView(), - editText, sendButton, imageListener - ); - } - - private void showEmojiIcon() { - emojiToggle.setImageResource(R.drawable.ic_emoji_toggle); - } - - private void showKeyboardIcon() { - emojiToggle.setImageResource(R.drawable.ic_keyboard); - } - - private void onSendButtonClicked() { - if (listener != null) { - Editable editable = editText.getText(); - String text = editable == null || editable.length() == 0 ? - null : editable.toString(); - List imageUris = attachmentController == null ? emptyList() : - attachmentController.getUris(); - listener.onSendClick(text, imageUris); - } - if (attachmentController != null) { - attachmentController.reset(); - } + attachmentController = (TextAttachmentController) textSendController; + attachmentController.setAttachImageListener(imageListener); } public void onImageReceived(@Nullable Intent resultData) { @@ -183,61 +153,54 @@ public class TextInputView extends KeyboardAwareLinearLayout { attachmentController.onImageReceived(resultData); } + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + textInputController.setEnabled(enabled); + textSendController.setEnabled(enabled); + } + @Override public boolean requestFocus(int direction, Rect previouslyFocusedRect) { - return editText.requestFocus(direction, previouslyFocusedRect); + return textInputController + .requestFocus(direction, previouslyFocusedRect); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (emojiPopup.isShowing()) emojiPopup.dismiss(); + textInputController.onDetachedFromWindow(); } - public void setText(String text) { - editText.setText(text); - } - - public boolean isEmpty() { - return editText.getText() == null || editText.getText().length() == 0; + public void clearText() { + textInputController.clearText(); } public void setHint(@StringRes int res) { - setHint(getContext().getString(res)); + textInputController.setHint(getContext().getString(res)); } - public void setHint(String hint) { - if (attachmentController != null) attachmentController.saveHint(hint); - editText.setHint(hint); - } - - public void setSendButtonEnabled(boolean enabled) { - sendButton.setEnabled(enabled); - } - - public void addTextChangedListener(TextWatcher watcher) { - editText.addTextChangedListener(watcher); + public void setMaxTextLength(int maxLength) { + textInputController.setMaxLength(maxLength); } public void showSoftKeyboard() { - Object o = getContext().getSystemService(INPUT_METHOD_SERVICE); - InputMethodManager imm = (InputMethodManager) requireNonNull(o); - imm.showSoftInput(editText, SHOW_IMPLICIT); + textInputController.showSoftKeyboard(); } public void hideSoftKeyboard() { - if (emojiPopup.isShowing()) emojiPopup.dismiss(); - IBinder token = editText.getWindowToken(); - Object o = getContext().getSystemService(INPUT_METHOD_SERVICE); - InputMethodManager imm = (InputMethodManager) requireNonNull(o); - imm.hideSoftInputFromWindow(token, 0); + textInputController.hideSoftKeyboard(); + } + + interface TextValidityListener { + void onTextValidityChanged(boolean isEmpty); } public interface AttachImageListener { void onAttachImage(Intent intent); } - public interface TextInputListener { + public interface SendListener { void onSendClick(@Nullable String text, List imageUris); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java new file mode 100644 index 000000000..3d0cb30c1 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java @@ -0,0 +1,62 @@ +package org.briarproject.briar.android.view; + +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; +import android.view.View; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.android.view.TextInputView.SendListener; +import org.briarproject.briar.android.view.TextInputView.TextValidityListener; + +import static java.util.Collections.emptyList; + +@UiThread +@NotNullByDefault +class TextSendController implements TextValidityListener { + + protected final TextInputController textInput; + protected final View sendButton; + @Nullable + protected SendListener listener; + protected boolean enabled = true; + + private final boolean allowEmptyText; + private boolean wasEmpty = true; + + TextSendController(View sendButton, TextInputController textInput, + boolean allowEmptyText) { + this.sendButton = sendButton; + this.sendButton.setOnClickListener(v -> onSendButtonClicked()); + this.sendButton.setEnabled(allowEmptyText); + this.textInput = textInput; + this.allowEmptyText = allowEmptyText; + } + + @Override + public void onTextValidityChanged(boolean isEmpty) { + sendButton.setEnabled(enabled && !isEmpty); + wasEmpty = isEmpty; + } + + public void setEnabled(boolean enabled) { + sendButton.setOnClickListener( + enabled ? v -> onSendButtonClicked() : null); + sendButton.setEnabled(!wasEmpty || allowEmptyText); + this.enabled = enabled; + } + + void setSendListener(SendListener listener) { + this.listener = listener; + } + + void onSendButtonClicked() { + if (listener != null) { + if (textInput.isTooLong()) { + textInput.showError(); + return; + } + listener.onSendClick(textInput.getText(), emptyList()); + } + } + +} diff --git a/briar-android/src/main/res/layout/activity_conversation.xml b/briar-android/src/main/res/layout/activity_conversation.xml index 02b0e6ab2..4ae3cedab 100644 --- a/briar-android/src/main/res/layout/activity_conversation.xml +++ b/briar-android/src/main/res/layout/activity_conversation.xml @@ -32,9 +32,9 @@ android:layout_height="match_parent" android:layout_marginLeft="@dimen/margin_medium" android:layout_marginStart="@dimen/margin_medium" + android:ellipsize="end" android:gravity="center" android:maxLines="1" - android:ellipsize="end" android:textColor="@color/action_bar_text" tools:text="Contact Name of someone who chose a long name"/> @@ -54,6 +54,7 @@ android:id="@+id/text_input_container" android:layout_width="match_parent" android:layout_height="wrap_content" - app:hint="@string/message_hint"/> + app:hint="@string/message_hint" + app:supportsAttachments="true"/> \ No newline at end of file diff --git a/briar-android/src/main/res/layout/fragment_message.xml b/briar-android/src/main/res/layout/fragment_message.xml index 7f74c6577..b9061e7ef 100644 --- a/briar-android/src/main/res/layout/fragment_message.xml +++ b/briar-android/src/main/res/layout/fragment_message.xml @@ -5,6 +5,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + app:allowEmptyText="true" app:buttonText="@string/forum_share_button" app:fillHeight="true" app:hint="@string/forum_share_message"/> \ No newline at end of file diff --git a/briar-android/src/main/res/layout/fragment_reblog.xml b/briar-android/src/main/res/layout/fragment_reblog.xml index 401a2bacd..2cfa7e5f5 100644 --- a/briar-android/src/main/res/layout/fragment_reblog.xml +++ b/briar-android/src/main/res/layout/fragment_reblog.xml @@ -39,6 +39,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="bottom" + app:allowEmptyText="true" app:buttonText="@string/blogs_reblog_button" app:hint="@string/blogs_reblog_comment_hint" app:maxLines="5"/> diff --git a/briar-android/src/main/res/layout/introduction_message.xml b/briar-android/src/main/res/layout/introduction_message.xml index 69848a81c..b8020fa28 100644 --- a/briar-android/src/main/res/layout/introduction_message.xml +++ b/briar-android/src/main/res/layout/introduction_message.xml @@ -118,6 +118,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_large" android:visibility="gone" + app:allowEmptyText="true" app:buttonText="@string/introduction_button" app:hint="@string/introduction_message_hint" app:layout_constraintBottom_toBottomOf="parent" diff --git a/briar-android/src/main/res/layout/text_input_view.xml b/briar-android/src/main/res/layout/text_input_view.xml index 1ceb3a43b..b5416ff92 100644 --- a/briar-android/src/main/res/layout/text_input_view.xml +++ b/briar-android/src/main/res/layout/text_input_view.xml @@ -78,20 +78,6 @@ android:layout_height="@dimen/text_input_height" android:layout_gravity="bottom"> - - + + diff --git a/briar-android/src/main/res/values/attrs.xml b/briar-android/src/main/res/values/attrs.xml index d2e212bb7..a97af7189 100644 --- a/briar-android/src/main/res/values/attrs.xml +++ b/briar-android/src/main/res/values/attrs.xml @@ -21,6 +21,8 @@ + +