mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-24 16:00:02 +00:00
committed by
Moxie Marlinspike
parent
20a1507f7a
commit
fa62b9bde2
@@ -16,68 +16,84 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.widget.LinearLayoutCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* LinearLayout that, when a view container, will report back when it thinks a soft keyboard
|
||||
* has been opened and what its height would be.
|
||||
*/
|
||||
public class KeyboardAwareLinearLayout extends LinearLayout {
|
||||
private static final String TAG = KeyboardAwareLinearLayout.class.getSimpleName();
|
||||
private static final Rect rect = new Rect();
|
||||
public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
private static final String TAG = KeyboardAwareLinearLayout.class.getSimpleName();
|
||||
|
||||
private final Rect oldRect = new Rect();
|
||||
private final Rect newRect = new Rect();
|
||||
private final Set<OnKeyboardHiddenListener> hiddenListeners = new HashSet<>();
|
||||
private final Set<OnKeyboardShownListener> shownListeners = new HashSet<>();
|
||||
private final int minKeyboardSize;
|
||||
|
||||
private boolean keyboardOpen;
|
||||
|
||||
public KeyboardAwareLinearLayout(Context context) {
|
||||
super(context);
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
minKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_keyboard_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* inspired by http://stackoverflow.com/a/7104303
|
||||
* @param widthMeasureSpec width measure
|
||||
* @param heightMeasureSpec height measure
|
||||
*/
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int res = getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
Log.w(TAG, String.format("onMeasure(%s, %s)", MeasureSpec.toString(widthMeasureSpec), MeasureSpec.toString(heightMeasureSpec)));
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
int res = getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||
int statusBarHeight = res > 0 ? getResources().getDimensionPixelSize(res) : 0;
|
||||
|
||||
final int availableHeight = this.getRootView().getHeight() - statusBarHeight - getViewInset();
|
||||
getWindowVisibleDisplayFrame(rect);
|
||||
getWindowVisibleDisplayFrame(newRect);
|
||||
|
||||
final int keyboardHeight = availableHeight - (rect.bottom - rect.top);
|
||||
final int oldKeyboardHeight = availableHeight - (oldRect.bottom - oldRect.top);
|
||||
final int keyboardHeight = availableHeight - (newRect.bottom - newRect.top);
|
||||
|
||||
if (keyboardHeight > getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height)) {
|
||||
onKeyboardShown(keyboardHeight);
|
||||
if (keyboardHeight - oldKeyboardHeight > minKeyboardSize && !keyboardOpen) {
|
||||
onKeyboardOpen(keyboardHeight);
|
||||
} else if (oldKeyboardHeight - keyboardHeight > minKeyboardSize && keyboardOpen) {
|
||||
onKeyboardClose();
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
oldRect.set(newRect);
|
||||
}
|
||||
|
||||
public int getViewInset() {
|
||||
public void padForCustomKeyboard(int height) {
|
||||
setPadding(0, 0, 0, height);
|
||||
}
|
||||
|
||||
public void unpadForCustomKeyboard() {
|
||||
setPadding(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
private int getViewInset() {
|
||||
if (Build.VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
|
||||
return 0;
|
||||
}
|
||||
@@ -100,8 +116,9 @@ public class KeyboardAwareLinearLayout extends LinearLayout {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void onKeyboardShown(int keyboardHeight) {
|
||||
Log.w(TAG, "keyboard shown, height " + keyboardHeight);
|
||||
protected void onKeyboardOpen(int keyboardHeight) {
|
||||
keyboardOpen = true;
|
||||
Log.w(TAG, "onKeyboardOpen(" + keyboardHeight + ")");
|
||||
|
||||
WindowManager wm = (WindowManager) getContext().getSystemService(Activity.WINDOW_SERVICE);
|
||||
if (wm == null || wm.getDefaultDisplay() == null) {
|
||||
@@ -118,10 +135,22 @@ public class KeyboardAwareLinearLayout extends LinearLayout {
|
||||
case Surface.ROTATION_180:
|
||||
setKeyboardPortraitHeight(keyboardHeight);
|
||||
}
|
||||
notifyShownListeners();
|
||||
unpadForCustomKeyboard();
|
||||
}
|
||||
|
||||
protected void onKeyboardClose() {
|
||||
keyboardOpen = false;
|
||||
Log.w(TAG, "onKeyboardClose()");
|
||||
notifyHiddenListeners();
|
||||
}
|
||||
|
||||
public boolean isKeyboardOpen() {
|
||||
return keyboardOpen;
|
||||
}
|
||||
|
||||
public int getKeyboardHeight() {
|
||||
WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
if (wm == null || wm.getDefaultDisplay() == null) {
|
||||
throw new AssertionError("WindowManager was null or there is no default display");
|
||||
}
|
||||
@@ -161,4 +190,52 @@ public class KeyboardAwareLinearLayout extends LinearLayout {
|
||||
.edit().putInt("keyboard_height_portrait", height).apply();
|
||||
}
|
||||
|
||||
public void postOnKeyboardClose(final Runnable runnable) {
|
||||
if (keyboardOpen) {
|
||||
addOnKeyboardHiddenListener(new OnKeyboardHiddenListener() {
|
||||
@Override public void onKeyboardHidden() {
|
||||
removeOnKeyboardHiddenListener(this);
|
||||
runnable.run();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void addOnKeyboardHiddenListener(OnKeyboardHiddenListener listener) {
|
||||
hiddenListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeOnKeyboardHiddenListener(OnKeyboardHiddenListener listener) {
|
||||
hiddenListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addOnKeyboardShownListener(OnKeyboardShownListener listener) {
|
||||
shownListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeOnKeyboardShownListener(OnKeyboardShownListener listener) {
|
||||
shownListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void notifyHiddenListeners() {
|
||||
for (OnKeyboardHiddenListener listener : hiddenListeners) {
|
||||
listener.onKeyboardHidden();
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyShownListeners() {
|
||||
for (OnKeyboardShownListener listener : shownListeners) {
|
||||
listener.onKeyboardShown();
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnKeyboardHiddenListener {
|
||||
void onKeyboardHidden();
|
||||
}
|
||||
|
||||
public interface OnKeyboardShownListener {
|
||||
void onKeyboardShown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.widget.LinearLayoutCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
@@ -14,12 +15,10 @@ import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ImageView.ScaleType;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.astuetz.PagerSlidingTabStrip;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
|
||||
import org.thoughtcrime.securesms.components.RepeatableImageKey;
|
||||
import org.thoughtcrime.securesms.components.RepeatableImageKey.KeyEventListener;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageView.EmojiSelectionListener;
|
||||
@@ -28,70 +27,50 @@ import org.thoughtcrime.securesms.util.ResUtil;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class EmojiDrawer extends KeyboardAwareLinearLayout {
|
||||
public class EmojiDrawer extends LinearLayoutCompat {
|
||||
private static final KeyEvent DELETE_KEY_EVENT = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
|
||||
|
||||
private EmojiEditText composeText;
|
||||
private KeyboardAwareLinearLayout container;
|
||||
private ViewPager pager;
|
||||
private List<EmojiPageModel> models;
|
||||
private PagerSlidingTabStrip strip;
|
||||
private RecentEmojiPageModel recentModel;
|
||||
private LinearLayout container;
|
||||
private ViewPager pager;
|
||||
private List<EmojiPageModel> models;
|
||||
private PagerSlidingTabStrip strip;
|
||||
private RecentEmojiPageModel recentModel;
|
||||
private EmojiEventListener listener;
|
||||
|
||||
public EmojiDrawer(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public EmojiDrawer(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public EmojiDrawer(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setComposeEditText(EmojiEditText composeText) {
|
||||
this.composeText = composeText;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
final View v = LayoutInflater.from(getContext()).inflate(R.layout.emoji_drawer, this, true);
|
||||
initializeResources(v);
|
||||
initializePageModels();
|
||||
initializeEmojiGrid();
|
||||
}
|
||||
|
||||
public void setEmojiEventListener(EmojiEventListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private void initializeResources(View v) {
|
||||
Log.w("EmojiDrawer", "initializeResources()");
|
||||
this.container = (KeyboardAwareLinearLayout) v.findViewById(R.id.container);
|
||||
this.pager = (ViewPager) v.findViewById(R.id.emoji_pager);
|
||||
this.strip = (PagerSlidingTabStrip) v.findViewById(R.id.tabs);
|
||||
this.container = (LinearLayout) v.findViewById(R.id.container);
|
||||
this.pager = (ViewPager) v.findViewById(R.id.emoji_pager);
|
||||
this.strip = (PagerSlidingTabStrip) v.findViewById(R.id.tabs);
|
||||
|
||||
RepeatableImageKey backspace = (RepeatableImageKey)v.findViewById(R.id.backspace);
|
||||
backspace.setOnKeyEventListener(new KeyEventListener() {
|
||||
@Override public void onKeyEvent() {
|
||||
if (composeText != null && composeText.getText().length() > 0) {
|
||||
composeText.dispatchKeyEvent(DELETE_KEY_EVENT);
|
||||
}
|
||||
if (listener != null) listener.onKeyEvent(DELETE_KEY_EVENT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
container.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
int keyboardHeight = container.getKeyboardHeight();
|
||||
Log.w("EmojiDrawer", "setting emoji drawer to height " + keyboardHeight);
|
||||
container.setLayoutParams(new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, keyboardHeight));
|
||||
container.requestLayout();
|
||||
container.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return container.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
@@ -102,7 +81,7 @@ public class EmojiDrawer extends KeyboardAwareLinearLayout {
|
||||
new EmojiSelectionListener() {
|
||||
@Override public void onEmojiSelected(String emoji) {
|
||||
recentModel.onCodePointSelected(emoji);
|
||||
composeText.insertEmoji(emoji);
|
||||
if (listener != null) listener.onEmojiSelected(emoji);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -170,4 +149,8 @@ public class EmojiDrawer extends KeyboardAwareLinearLayout {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
public interface EmojiEventListener extends EmojiSelectionListener {
|
||||
void onKeyEvent(KeyEvent keyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.thoughtcrime.securesms.components.emoji;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer.EmojiEventListener;
|
||||
|
||||
public class EmojiPopup extends PopupWindow {
|
||||
private View parent;
|
||||
|
||||
public EmojiPopup(View parent) {
|
||||
super(new EmojiDrawer(parent.getContext()),
|
||||
parent.getWidth(),
|
||||
parent.getResources().getDimensionPixelSize(R.dimen.min_emoji_drawer_height));
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setEmojiEventListener(EmojiEventListener listener) {
|
||||
((EmojiDrawer)getContentView()).setEmojiEventListener(listener);
|
||||
}
|
||||
|
||||
public void show(int height) {
|
||||
setHeight(height);
|
||||
showAtLocation(parent, Gravity.BOTTOM | Gravity.LEFT, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -14,7 +13,6 @@ public class EmojiToggle extends ImageButton {
|
||||
|
||||
private Drawable emojiToggle;
|
||||
private Drawable imeToggle;
|
||||
private OnClickListener listener;
|
||||
|
||||
public EmojiToggle(Context context) {
|
||||
super(context);
|
||||
@@ -31,46 +29,23 @@ public class EmojiToggle extends ImageButton {
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnClickListener(OnClickListener listener) {
|
||||
this.listener = listener;
|
||||
public void setToEmoji() {
|
||||
setImageDrawable(emojiToggle);
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
if (getDrawable() == emojiToggle) {
|
||||
setImageDrawable(imeToggle);
|
||||
} else {
|
||||
setImageDrawable(emojiToggle);
|
||||
}
|
||||
public void setToIme() {
|
||||
setImageDrawable(imeToggle);
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
initializeResources();
|
||||
initializeListeners();
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
int attributes[] = new int[] {R.attr.conversation_emoji_toggle,
|
||||
R.attr.conversation_keyboard_toggle};
|
||||
R.attr.conversation_keyboard_toggle};
|
||||
|
||||
TypedArray drawables = getContext().obtainStyledAttributes(attributes);
|
||||
this.emojiToggle = drawables.getDrawable(0);
|
||||
this.imeToggle = drawables.getDrawable(1);
|
||||
|
||||
drawables.recycle();
|
||||
|
||||
setImageDrawable(this.emojiToggle);
|
||||
}
|
||||
|
||||
private void initializeListeners() {
|
||||
super.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
toggle();
|
||||
|
||||
if (listener != null)
|
||||
listener.onClick(v);
|
||||
}
|
||||
});
|
||||
setToEmoji();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user