mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +01:00
[android] Require users of TextInputView to set its controller
This commit is contained in:
@@ -20,6 +20,7 @@ import org.briarproject.briar.android.controller.handler.UiResultExceptionHandle
|
|||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
import org.briarproject.briar.android.view.TextInputView;
|
import org.briarproject.briar.android.view.TextInputView;
|
||||||
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
|
import org.briarproject.briar.android.view.TextSendController;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -81,6 +82,9 @@ public class ReblogFragment extends BaseFragment implements SendListener {
|
|||||||
View v = inflater.inflate(R.layout.fragment_reblog, container, false);
|
View v = inflater.inflate(R.layout.fragment_reblog, container, false);
|
||||||
ui = new ViewHolder(v);
|
ui = new ViewHolder(v);
|
||||||
ui.post.setTransitionName(postId);
|
ui.post.setTransitionName(postId);
|
||||||
|
TextSendController sendController =
|
||||||
|
new TextSendController(ui.input, this, true);
|
||||||
|
ui.input.setSendController(sendController);
|
||||||
ui.input.setEnabled(false);
|
ui.input.setEnabled(false);
|
||||||
ui.input.setMaxTextLength(MAX_BLOG_POST_TEXT_LENGTH);
|
ui.input.setMaxTextLength(MAX_BLOG_POST_TEXT_LENGTH);
|
||||||
showProgressBar();
|
showProgressBar();
|
||||||
@@ -117,7 +121,6 @@ public class ReblogFragment extends BaseFragment implements SendListener {
|
|||||||
ui.post.bindItem(item);
|
ui.post.bindItem(item);
|
||||||
ui.post.hideReblogButton();
|
ui.post.hideReblogButton();
|
||||||
|
|
||||||
ui.input.setListener(this);
|
|
||||||
ui.input.setEnabled(true);
|
ui.input.setEnabled(true);
|
||||||
ui.scrollView.post(() -> ui.scrollView.fullScroll(FOCUS_DOWN));
|
ui.scrollView.post(() -> ui.scrollView.fullScroll(FOCUS_DOWN));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
|||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.view.TextInputView;
|
import org.briarproject.briar.android.view.TextInputView;
|
||||||
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
|
import org.briarproject.briar.android.view.TextSendController;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.blog.BlogManager;
|
import org.briarproject.briar.api.blog.BlogManager;
|
||||||
import org.briarproject.briar.api.blog.BlogPost;
|
import org.briarproject.briar.api.blog.BlogPost;
|
||||||
@@ -75,8 +76,10 @@ public class WriteBlogPostActivity extends BriarActivity
|
|||||||
setContentView(R.layout.activity_write_blog_post);
|
setContentView(R.layout.activity_write_blog_post);
|
||||||
|
|
||||||
input = findViewById(R.id.textInput);
|
input = findViewById(R.id.textInput);
|
||||||
|
TextSendController sendController =
|
||||||
|
new TextSendController(input, this, false);
|
||||||
|
input.setSendController(sendController);
|
||||||
input.setMaxTextLength(MAX_BLOG_POST_TEXT_LENGTH);
|
input.setMaxTextLength(MAX_BLOG_POST_TEXT_LENGTH);
|
||||||
input.setListener(this);
|
|
||||||
|
|
||||||
progressBar = findViewById(R.id.progressBar);
|
progressBar = findViewById(R.id.progressBar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,9 +63,11 @@ import org.briarproject.briar.android.forum.ForumActivity;
|
|||||||
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
||||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||||
|
import org.briarproject.briar.android.view.TextAttachmentController;
|
||||||
import org.briarproject.briar.android.view.TextInputView;
|
import org.briarproject.briar.android.view.TextInputView;
|
||||||
import org.briarproject.briar.android.view.TextInputView.AttachImageListener;
|
import org.briarproject.briar.android.view.TextInputView.AttachImageListener;
|
||||||
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
|
import org.briarproject.briar.android.view.TextSendController;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.blog.BlogSharingManager;
|
import org.briarproject.briar.api.blog.BlogSharingManager;
|
||||||
import org.briarproject.briar.api.client.ProtocolStateException;
|
import org.briarproject.briar.api.client.ProtocolStateException;
|
||||||
@@ -166,6 +168,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
private LinearLayoutManager layoutManager;
|
private LinearLayoutManager layoutManager;
|
||||||
private TextInputView textInputView;
|
private TextInputView textInputView;
|
||||||
|
private TextSendController sendController;
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
@@ -255,12 +258,15 @@ public class ConversationActivity extends BriarActivity
|
|||||||
list.setEmptyText(getString(R.string.no_private_messages));
|
list.setEmptyText(getString(R.string.no_private_messages));
|
||||||
|
|
||||||
textInputView = findViewById(R.id.text_input_container);
|
textInputView = findViewById(R.id.text_input_container);
|
||||||
|
if (FEATURE_FLAG_IMAGE_ATTACHMENTS) {
|
||||||
|
sendController = new TextAttachmentController(textInputView, this,
|
||||||
|
this, getWindowManager());
|
||||||
|
} else {
|
||||||
|
sendController = new TextSendController(textInputView, this, false);
|
||||||
|
}
|
||||||
|
textInputView.setSendController(sendController);
|
||||||
textInputView.setMaxTextLength(MAX_PRIVATE_MESSAGE_TEXT_LENGTH);
|
textInputView.setMaxTextLength(MAX_PRIVATE_MESSAGE_TEXT_LENGTH);
|
||||||
textInputView.setEnabled(false);
|
textInputView.setEnabled(false);
|
||||||
textInputView.setListener(this);
|
|
||||||
if (FEATURE_FLAG_IMAGE_ATTACHMENTS) {
|
|
||||||
textInputView.setAttachImageListener(this, getWindowManager());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -278,7 +284,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||||
snackbar.show();
|
snackbar.show();
|
||||||
} else if (request == REQUEST_ATTACH_IMAGE && result == RESULT_OK) {
|
} else if (request == REQUEST_ATTACH_IMAGE && result == RESULT_OK) {
|
||||||
textInputView.onImageReceived(data);
|
// remove cast when removing FEATURE_FLAG_IMAGE_ATTACHMENTS
|
||||||
|
((TextAttachmentController) sendController).onImageReceived(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
|||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
import org.briarproject.briar.android.view.TextInputView;
|
import org.briarproject.briar.android.view.TextInputView;
|
||||||
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
|
import org.briarproject.briar.android.view.TextSendController;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionManager;
|
import org.briarproject.briar.api.introduction.IntroductionManager;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -102,6 +103,9 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
View v = inflater.inflate(R.layout.introduction_message, container,
|
View v = inflater.inflate(R.layout.introduction_message, container,
|
||||||
false);
|
false);
|
||||||
ui = new ViewHolder(v);
|
ui = new ViewHolder(v);
|
||||||
|
TextSendController sendController =
|
||||||
|
new TextSendController(ui.message, this, true);
|
||||||
|
ui.message.setSendController(sendController);
|
||||||
ui.message.setMaxTextLength(MAX_INTRODUCTION_TEXT_LENGTH);
|
ui.message.setMaxTextLength(MAX_INTRODUCTION_TEXT_LENGTH);
|
||||||
ui.message.setEnabled(false);
|
ui.message.setEnabled(false);
|
||||||
|
|
||||||
@@ -162,9 +166,6 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
ui.progressBar.setVisibility(GONE);
|
ui.progressBar.setVisibility(GONE);
|
||||||
|
|
||||||
if (possible) {
|
if (possible) {
|
||||||
// set button action
|
|
||||||
ui.message.setListener(IntroductionMessageFragment.this);
|
|
||||||
|
|
||||||
// show views
|
// show views
|
||||||
ui.notPossible.setVisibility(GONE);
|
ui.notPossible.setVisibility(GONE);
|
||||||
ui.message.setVisibility(VISIBLE);
|
ui.message.setVisibility(VISIBLE);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
import org.briarproject.briar.android.view.LargeTextInputView;
|
import org.briarproject.briar.android.view.LargeTextInputView;
|
||||||
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
|
import org.briarproject.briar.android.view.TextSendController;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -44,10 +45,12 @@ public abstract class BaseMessageFragment extends BaseFragment
|
|||||||
View v = inflater.inflate(R.layout.fragment_message, container,
|
View v = inflater.inflate(R.layout.fragment_message, container,
|
||||||
false);
|
false);
|
||||||
message = v.findViewById(R.id.messageView);
|
message = v.findViewById(R.id.messageView);
|
||||||
|
TextSendController sendController =
|
||||||
|
new TextSendController(message, this, true);
|
||||||
|
message.setSendController(sendController);
|
||||||
message.setMaxTextLength(listener.getMaximumTextLength());
|
message.setMaxTextLength(listener.getMaximumTextLength());
|
||||||
message.setButtonText(getString(getButtonText()));
|
message.setButtonText(getString(getButtonText()));
|
||||||
message.setHint(getHintText());
|
message.setHint(getHintText());
|
||||||
message.setListener(this);
|
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.briarproject.briar.android.threaded.ThreadListController.ThreadListLi
|
|||||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||||
import org.briarproject.briar.android.view.TextInputView;
|
import org.briarproject.briar.android.view.TextInputView;
|
||||||
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
|
import org.briarproject.briar.android.view.TextSendController;
|
||||||
import org.briarproject.briar.android.view.UnreadMessageButton;
|
import org.briarproject.briar.android.view.UnreadMessageButton;
|
||||||
import org.briarproject.briar.api.client.NamedGroup;
|
import org.briarproject.briar.api.client.NamedGroup;
|
||||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
|
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
|
||||||
@@ -88,8 +89,10 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
getController().setGroupId(groupId);
|
getController().setGroupId(groupId);
|
||||||
|
|
||||||
textInput = findViewById(R.id.text_input_container);
|
textInput = findViewById(R.id.text_input_container);
|
||||||
|
TextSendController sendController =
|
||||||
|
new TextSendController(textInput, this, false);
|
||||||
|
textInput.setSendController(sendController);
|
||||||
textInput.setMaxTextLength(getMaxTextLength());
|
textInput.setMaxTextLength(getMaxTextLength());
|
||||||
textInput.setListener(this);
|
|
||||||
list = findViewById(R.id.list);
|
list = findViewById(R.id.list);
|
||||||
layoutManager = new LinearLayoutManager(this);
|
layoutManager = new LinearLayoutManager(this);
|
||||||
// FIXME pre-fetching messes with read state, find better solution #1289
|
// FIXME pre-fetching messes with read state, find better solution #1289
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class LargeTextInputView extends TextInputView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setButtonText(String text) {
|
public void setButtonText(String text) {
|
||||||
((Button) sendButton).setText(text);
|
((Button) findViewById(R.id.btn_send)).setText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.graphics.Bitmap;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
@@ -13,7 +14,6 @@ import android.support.v4.view.AbsSavedState;
|
|||||||
import android.support.v7.graphics.Palette;
|
import android.support.v7.graphics.Palette;
|
||||||
import android.support.v7.widget.AppCompatImageButton;
|
import android.support.v7.widget.AppCompatImageButton;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewGroup.LayoutParams;
|
import android.view.ViewGroup.LayoutParams;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
@@ -28,6 +28,7 @@ import com.bumptech.glide.request.target.Target;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.conversation.glide.GlideApp;
|
import org.briarproject.briar.android.conversation.glide.GlideApp;
|
||||||
import org.briarproject.briar.android.view.TextInputView.AttachImageListener;
|
import org.briarproject.briar.android.view.TextInputView.AttachImageListener;
|
||||||
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -53,21 +54,21 @@ import static java.util.Collections.singletonList;
|
|||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
class TextAttachmentController extends TextSendController {
|
public class TextAttachmentController extends TextSendController {
|
||||||
|
|
||||||
private final AppCompatImageButton imageButton;
|
private final AppCompatImageButton imageButton;
|
||||||
private final ViewGroup imageLayout;
|
private final ViewGroup imageLayout;
|
||||||
private final ImageView imageView;
|
private final ImageView imageView;
|
||||||
|
|
||||||
@Nullable
|
private final AttachImageListener imageListener;
|
||||||
private AttachImageListener imageListener;
|
|
||||||
|
|
||||||
private CharSequence textHint;
|
private CharSequence textHint;
|
||||||
private List<Uri> imageUris = emptyList();
|
private List<Uri> imageUris = emptyList();
|
||||||
|
|
||||||
TextAttachmentController(View v, View sendButton,
|
public TextAttachmentController(TextInputView v, SendListener listener,
|
||||||
TextInputController textInput) {
|
AttachImageListener imageListener, WindowManager windowManager) {
|
||||||
super(sendButton, textInput, true);
|
super(v, listener, true);
|
||||||
|
this.imageListener = imageListener;
|
||||||
|
|
||||||
imageLayout = v.findViewById(R.id.imageLayout);
|
imageLayout = v.findViewById(R.id.imageLayout);
|
||||||
imageView = v.findViewById(R.id.imageView);
|
imageView = v.findViewById(R.id.imageView);
|
||||||
@@ -82,11 +83,7 @@ class TextAttachmentController extends TextSendController {
|
|||||||
textInput.clearText();
|
textInput.clearText();
|
||||||
reset();
|
reset();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttachImageListener(AttachImageListener imageListener,
|
|
||||||
WindowManager windowManager) {
|
|
||||||
this.imageListener = imageListener;
|
|
||||||
// set preview size based on screen height
|
// set preview size based on screen height
|
||||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||||
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
|
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
|
||||||
@@ -98,20 +95,16 @@ class TextAttachmentController extends TextSendController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTextValidityChanged(boolean isEmpty) {
|
public void onTextIsEmptyChanged(boolean isEmpty) {
|
||||||
if (imageUris.isEmpty()) showImageButton(isEmpty);
|
if (imageUris.isEmpty()) showImageButton(isEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void onSendButtonClicked() {
|
void onSendButtonClicked() {
|
||||||
if (listener != null) {
|
if (canSend()) {
|
||||||
if (textInput.isTooLong()) {
|
|
||||||
textInput.showError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
listener.onSendClick(textInput.getText(), imageUris);
|
listener.onSendClick(textInput.getText(), imageUris);
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onImageButtonClicked() {
|
private void onImageButtonClicked() {
|
||||||
@@ -124,7 +117,7 @@ class TextAttachmentController extends TextSendController {
|
|||||||
requireNonNull(imageListener).onAttachImage(intent);
|
requireNonNull(imageListener).onAttachImage(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onImageReceived(@Nullable Intent resultData) {
|
public void onImageReceived(@Nullable Intent resultData) {
|
||||||
if (resultData == null) return;
|
if (resultData == null) return;
|
||||||
if (resultData.getData() != null) {
|
if (resultData.getData() != null) {
|
||||||
imageUris = singletonList(resultData.getData());
|
imageUris = singletonList(resultData.getData());
|
||||||
@@ -205,7 +198,7 @@ class TextAttachmentController extends TextSendController {
|
|||||||
} else {
|
} else {
|
||||||
sendButton.setVisibility(VISIBLE);
|
sendButton.setVisibility(VISIBLE);
|
||||||
// enable/disable buttons right away to allow fast sending
|
// enable/disable buttons right away to allow fast sending
|
||||||
sendButton.setEnabled(true);
|
sendButton.setEnabled(enabled);
|
||||||
imageButton.setEnabled(false);
|
imageButton.setEnabled(false);
|
||||||
if (SDK_INT <= 15) {
|
if (SDK_INT <= 15) {
|
||||||
imageButton.setVisibility(INVISIBLE);
|
imageButton.setVisibility(INVISIBLE);
|
||||||
@@ -231,6 +224,7 @@ class TextAttachmentController extends TextSendController {
|
|||||||
showImageButton(true);
|
showImageButton(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Parcelable onSaveInstanceState(@Nullable Parcelable superState) {
|
public Parcelable onSaveInstanceState(@Nullable Parcelable superState) {
|
||||||
SavedState state =
|
SavedState state =
|
||||||
new SavedState(superState == null ? EMPTY_STATE : superState);
|
new SavedState(superState == null ? EMPTY_STATE : superState);
|
||||||
@@ -238,8 +232,9 @@ class TextAttachmentController extends TextSendController {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Parcelable onRestoreInstanceState(Parcelable inState) {
|
public Parcelable onRestoreInstanceState(@NonNull Parcelable inState) {
|
||||||
SavedState state = (SavedState) inState;
|
SavedState state = (SavedState) inState;
|
||||||
imageUris = state.imageUris;
|
imageUris = state.imageUris;
|
||||||
onNewUris();
|
onNewUris();
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.os.IBinder;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.design.widget.Snackbar;
|
|
||||||
import android.support.v7.widget.AppCompatImageButton;
|
import android.support.v7.widget.AppCompatImageButton;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
@@ -21,9 +20,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
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 android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong;
|
||||||
import static org.briarproject.briar.android.view.TextInputView.TextValidityListener;
|
import static org.briarproject.briar.android.view.TextInputView.TextValidityListener;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -35,7 +34,8 @@ class TextInputController implements TextWatcher {
|
|||||||
private final EmojiPopup emojiPopup;
|
private final EmojiPopup emojiPopup;
|
||||||
private final EmojiEditText editText;
|
private final EmojiEditText editText;
|
||||||
|
|
||||||
private @Nullable TextValidityListener listener;
|
@Nullable
|
||||||
|
private TextValidityListener listener;
|
||||||
private int maxLength = Integer.MAX_VALUE;
|
private int maxLength = Integer.MAX_VALUE;
|
||||||
private final boolean emptyTextAllowed;
|
private final boolean emptyTextAllowed;
|
||||||
private boolean isEmpty = true;
|
private boolean isEmpty = true;
|
||||||
@@ -66,15 +66,16 @@ class TextInputController implements TextWatcher {
|
|||||||
@Override
|
@Override
|
||||||
public void onTextChanged(CharSequence s, int start, int before,
|
public void onTextChanged(CharSequence s, int start, int before,
|
||||||
int count) {
|
int count) {
|
||||||
if (emptyTextAllowed || listener == null) return;
|
// Need to start at position 0 to change empty
|
||||||
if (s.toString().trim().length() == 0) {
|
if (start != 0 || emptyTextAllowed || listener == null) return;
|
||||||
|
if (s.length() == 0) {
|
||||||
if (!isEmpty) {
|
if (!isEmpty) {
|
||||||
isEmpty = true;
|
isEmpty = true;
|
||||||
listener.onTextValidityChanged(true);
|
listener.onTextIsEmptyChanged(true);
|
||||||
}
|
}
|
||||||
} else if (isEmpty) {
|
} else if (isEmpty) {
|
||||||
isEmpty = false;
|
isEmpty = false;
|
||||||
listener.onTextValidityChanged(false);
|
listener.onTextIsEmptyChanged(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,9 +87,13 @@ class TextInputController implements TextWatcher {
|
|||||||
this.maxLength = maxLength;
|
this.maxLength = maxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isEmpty() {
|
||||||
|
return getText() == null;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isTooLong() {
|
boolean isTooLong() {
|
||||||
return editText.getText() != null &&
|
return editText.getText() != null &&
|
||||||
editText.getText().toString().trim().length() > maxLength;
|
utf8IsTooLong(editText.getText().toString().trim(), maxLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,9 +103,9 @@ class TextInputController implements TextWatcher {
|
|||||||
@Nullable
|
@Nullable
|
||||||
String getText() {
|
String getText() {
|
||||||
Editable editable = editText.getText();
|
Editable editable = editText.getText();
|
||||||
if (editable == null || editable.toString().trim().length() == 0)
|
String str = editable == null ? null : editable.toString().trim();
|
||||||
return null;
|
if (str == null || str.length() == 0) return null;
|
||||||
return editable.toString().trim();
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearText() {
|
void clearText() {
|
||||||
@@ -123,10 +128,6 @@ class TextInputController implements TextWatcher {
|
|||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showError() {
|
|
||||||
Snackbar.make(editText, R.string.text_too_long, LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean requestFocus(int direction, Rect previouslyFocusedRect) {
|
boolean requestFocus(int direction, Rect previouslyFocusedRect) {
|
||||||
return editText.requestFocus(direction, previouslyFocusedRect);
|
return editText.requestFocus(direction, previouslyFocusedRect);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import android.support.annotation.UiThread;
|
|||||||
import android.support.v7.widget.AppCompatImageButton;
|
import android.support.v7.widget.AppCompatImageButton;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
|
|
||||||
import com.vanniktech.emoji.EmojiEditText;
|
import com.vanniktech.emoji.EmojiEditText;
|
||||||
import com.vanniktech.emoji.RecentEmoji;
|
import com.vanniktech.emoji.RecentEmoji;
|
||||||
@@ -43,12 +41,9 @@ public class TextInputView extends KeyboardAwareLinearLayout {
|
|||||||
RecentEmoji recentEmoji;
|
RecentEmoji recentEmoji;
|
||||||
|
|
||||||
TextInputController textInputController;
|
TextInputController textInputController;
|
||||||
|
@Nullable
|
||||||
TextSendController textSendController;
|
TextSendController textSendController;
|
||||||
EmojiEditText editText;
|
EmojiEditText editText;
|
||||||
View sendButton;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
TextAttachmentController attachmentController;
|
|
||||||
|
|
||||||
public TextInputView(Context context) {
|
public TextInputView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
@@ -87,8 +82,6 @@ public class TextInputView extends KeyboardAwareLinearLayout {
|
|||||||
String hint = attributes.getString(R.styleable.TextInputView_hint);
|
String hint = attributes.getString(R.styleable.TextInputView_hint);
|
||||||
boolean allowEmptyText = attributes
|
boolean allowEmptyText = attributes
|
||||||
.getBoolean(R.styleable.TextInputView_allowEmptyText, false);
|
.getBoolean(R.styleable.TextInputView_allowEmptyText, false);
|
||||||
boolean supportsAttachments = attributes
|
|
||||||
.getBoolean(R.styleable.TextInputView_supportsAttachments, false);
|
|
||||||
attributes.recycle();
|
attributes.recycle();
|
||||||
|
|
||||||
// set up input controller
|
// set up input controller
|
||||||
@@ -97,16 +90,34 @@ public class TextInputView extends KeyboardAwareLinearLayout {
|
|||||||
textInputController = new TextInputController(this, emojiToggle,
|
textInputController = new TextInputController(this, emojiToggle,
|
||||||
editText, recentEmoji, allowEmptyText);
|
editText, recentEmoji, allowEmptyText);
|
||||||
if (hint != null) textInputController.setHint(hint);
|
if (hint != null) textInputController.setHint(hint);
|
||||||
|
}
|
||||||
|
|
||||||
// set up sending controller
|
@Nullable
|
||||||
sendButton = findViewById(R.id.btn_send);
|
@Override
|
||||||
if (supportsAttachments) {
|
protected Parcelable onSaveInstanceState() {
|
||||||
textSendController = new TextAttachmentController(this, sendButton,
|
Parcelable superState = super.onSaveInstanceState();
|
||||||
textInputController);
|
if (textSendController != null) {
|
||||||
} else {
|
superState = textSendController.onSaveInstanceState(superState);
|
||||||
textSendController = new TextSendController(sendButton,
|
|
||||||
textInputController, allowEmptyText);
|
|
||||||
}
|
}
|
||||||
|
return superState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Parcelable state) {
|
||||||
|
if (textSendController != null) {
|
||||||
|
Parcelable outState =
|
||||||
|
textSendController.onRestoreInstanceState(state);
|
||||||
|
super.onRestoreInstanceState(outState);
|
||||||
|
} else {
|
||||||
|
super.onRestoreInstanceState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this in onCreate() before any other methods of this class.
|
||||||
|
*/
|
||||||
|
public <T extends TextSendController> void setSendController(T controller) {
|
||||||
|
textSendController = controller;
|
||||||
textInputController.setTextValidityListener(textSendController);
|
textInputController.setTextValidityListener(textSendController);
|
||||||
|
|
||||||
// support sending with Ctrl+Enter
|
// support sending with Ctrl+Enter
|
||||||
@@ -119,47 +130,15 @@ public class TextInputView extends KeyboardAwareLinearLayout {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public TextInputController getTextInputController() {
|
||||||
@Override
|
return textInputController;
|
||||||
protected Parcelable onSaveInstanceState() {
|
|
||||||
Parcelable superState = super.onSaveInstanceState();
|
|
||||||
if (attachmentController != null) {
|
|
||||||
superState = attachmentController.onSaveInstanceState(superState);
|
|
||||||
}
|
|
||||||
return superState;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onRestoreInstanceState(Parcelable state) {
|
|
||||||
if (attachmentController != null) {
|
|
||||||
Parcelable outState =
|
|
||||||
attachmentController.onRestoreInstanceState(state);
|
|
||||||
super.onRestoreInstanceState(outState);
|
|
||||||
} else {
|
|
||||||
super.onRestoreInstanceState(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setListener(SendListener listener) {
|
|
||||||
textSendController.setSendListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttachImageListener(AttachImageListener imageListener,
|
|
||||||
WindowManager windowManager) {
|
|
||||||
attachmentController = (TextAttachmentController) textSendController;
|
|
||||||
attachmentController.setAttachImageListener(imageListener, windowManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onImageReceived(@Nullable Intent resultData) {
|
|
||||||
if (attachmentController == null) throw new IllegalStateException();
|
|
||||||
attachmentController.onImageReceived(resultData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
super.setEnabled(enabled);
|
super.setEnabled(enabled);
|
||||||
textInputController.setEnabled(enabled);
|
textInputController.setEnabled(enabled);
|
||||||
textSendController.setEnabled(enabled);
|
requireNonNull(textSendController).setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -195,7 +174,7 @@ public class TextInputView extends KeyboardAwareLinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface TextValidityListener {
|
interface TextValidityListener {
|
||||||
void onTextValidityChanged(boolean isEmpty);
|
void onTextIsEmptyChanged(boolean isEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface AttachImageListener {
|
public interface AttachImageListener {
|
||||||
|
|||||||
@@ -1,62 +1,77 @@
|
|||||||
package org.briarproject.briar.android.view;
|
package org.briarproject.briar.android.view;
|
||||||
|
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.CallSuper;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
import org.briarproject.briar.android.view.TextInputView.SendListener;
|
||||||
import org.briarproject.briar.android.view.TextInputView.TextValidityListener;
|
import org.briarproject.briar.android.view.TextInputView.TextValidityListener;
|
||||||
|
|
||||||
|
import static android.support.design.widget.Snackbar.LENGTH_SHORT;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class TextSendController implements TextValidityListener {
|
public class TextSendController implements TextValidityListener {
|
||||||
|
|
||||||
protected final TextInputController textInput;
|
protected final TextInputController textInput;
|
||||||
protected final View sendButton;
|
protected final View sendButton;
|
||||||
@Nullable
|
protected final SendListener listener;
|
||||||
protected SendListener listener;
|
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
|
|
||||||
private final boolean allowEmptyText;
|
private final boolean allowEmptyText;
|
||||||
private boolean wasEmpty = true;
|
private boolean wasEmpty = true;
|
||||||
|
|
||||||
TextSendController(View sendButton, TextInputController textInput,
|
public TextSendController(TextInputView v, SendListener listener,
|
||||||
boolean allowEmptyText) {
|
boolean allowEmptyText) {
|
||||||
this.sendButton = sendButton;
|
this.sendButton = v.findViewById(R.id.btn_send);
|
||||||
this.sendButton.setOnClickListener(v -> onSendButtonClicked());
|
this.sendButton.setOnClickListener(view -> onSendButtonClicked());
|
||||||
this.sendButton.setEnabled(allowEmptyText);
|
this.sendButton.setEnabled(allowEmptyText);
|
||||||
this.textInput = textInput;
|
this.listener = listener;
|
||||||
|
this.textInput = v.getTextInputController();
|
||||||
this.allowEmptyText = allowEmptyText;
|
this.allowEmptyText = allowEmptyText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTextValidityChanged(boolean isEmpty) {
|
public void onTextIsEmptyChanged(boolean isEmpty) {
|
||||||
sendButton.setEnabled(enabled && !isEmpty);
|
sendButton.setEnabled(enabled && !isEmpty);
|
||||||
wasEmpty = isEmpty;
|
wasEmpty = isEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Parcelable onSaveInstanceState(@Nullable Parcelable superState) {
|
||||||
|
return superState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Parcelable onRestoreInstanceState(Parcelable state) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
sendButton.setOnClickListener(
|
sendButton.setEnabled(enabled && (!wasEmpty || allowEmptyText));
|
||||||
enabled ? v -> onSendButtonClicked() : null);
|
|
||||||
sendButton.setEnabled(!wasEmpty || allowEmptyText);
|
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSendListener(SendListener listener) {
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onSendButtonClicked() {
|
void onSendButtonClicked() {
|
||||||
if (listener != null) {
|
if (canSend()) {
|
||||||
if (textInput.isTooLong()) {
|
|
||||||
textInput.showError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
listener.onSendClick(textInput.getText(), emptyList());
|
listener.onSendClick(textInput.getText(), emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean canSend() {
|
||||||
|
if (textInput.isTooLong()) {
|
||||||
|
Snackbar.make(sendButton, R.string.text_too_long, LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return enabled && (allowEmptyText || !textInput.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@
|
|||||||
android:id="@+id/text_input_container"
|
android:id="@+id/text_input_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:hint="@string/message_hint"
|
app:hint="@string/message_hint"/>
|
||||||
app:supportsAttachments="true"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
<declare-styleable name="TextInputView">
|
<declare-styleable name="TextInputView">
|
||||||
<attr name="hint" format="string"/>
|
<attr name="hint" format="string"/>
|
||||||
<attr name="allowEmptyText" format="boolean"/>
|
<attr name="allowEmptyText" format="boolean"/>
|
||||||
<attr name="supportsAttachments" format="boolean"/>
|
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="LargeTextInputView">
|
<declare-styleable name="LargeTextInputView">
|
||||||
|
|||||||
Reference in New Issue
Block a user