mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Use vanniktech emoji library.
This commit is contained in:
@@ -28,6 +28,7 @@ import org.briarproject.briar.BriarCoreEagerSingletons;
|
||||
import org.briarproject.briar.BriarCoreModule;
|
||||
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||
import org.briarproject.briar.android.reporting.BriarReportSender;
|
||||
import org.briarproject.briar.android.view.TextInputView;
|
||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||
import org.briarproject.briar.api.android.LockManager;
|
||||
@@ -49,8 +50,6 @@ import org.briarproject.briar.api.privategroup.PrivateGroupManager;
|
||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory;
|
||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
||||
import org.briarproject.briar.api.test.TestDataCreator;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider;
|
||||
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -161,12 +160,10 @@ public interface AndroidComponent
|
||||
|
||||
void inject(BriarReportSender briarReportSender);
|
||||
|
||||
void inject(EmojiProvider emojiProvider);
|
||||
|
||||
void inject(RecentEmojiPageModel recentEmojiPageModel);
|
||||
|
||||
void inject(NotificationCleanupService notificationCleanupService);
|
||||
|
||||
void inject(TextInputView textInputView);
|
||||
|
||||
// Eager singleton load
|
||||
void inject(AppModule.EagerSingletons init);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.StrictMode;
|
||||
|
||||
import com.vanniktech.emoji.RecentEmoji;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
@@ -65,6 +67,8 @@ public class AppModule {
|
||||
NetworkUsageLogger networkUsageLogger;
|
||||
@Inject
|
||||
DozeWatchdog dozeWatchdog;
|
||||
@Inject
|
||||
RecentEmoji recentEmoji;
|
||||
}
|
||||
|
||||
private final Application application;
|
||||
@@ -211,4 +215,11 @@ public class AppModule {
|
||||
return lockManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
RecentEmoji provideRecentEmoji(LifecycleManager lifecycleManager,
|
||||
RecentEmojiImpl recentEmoji) {
|
||||
lifecycleManager.registerClient(recentEmoji);
|
||||
return recentEmoji;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ import android.os.StrictMode.ThreadPolicy;
|
||||
import android.os.StrictMode.VmPolicy;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.vanniktech.emoji.EmojiManager;
|
||||
import com.vanniktech.emoji.google.GoogleEmojiProvider;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.acra.ReportingInteractionMode;
|
||||
import org.acra.annotation.ReportsCrashes;
|
||||
@@ -89,6 +92,7 @@ public class BriarApplicationImpl extends Application
|
||||
Localizer.getInstance().setLocale(base));
|
||||
setTheme(base, prefs);
|
||||
ACRA.init(this);
|
||||
EmojiManager.install(new GoogleEmojiProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package org.briarproject.briar.android;
|
||||
|
||||
import com.vanniktech.emoji.EmojiRange;
|
||||
import com.vanniktech.emoji.EmojiUtils;
|
||||
import com.vanniktech.emoji.RecentEmoji;
|
||||
import com.vanniktech.emoji.emoji.Emoji;
|
||||
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.api.settings.Settings;
|
||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||
import org.briarproject.bramble.api.sync.Client;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
class RecentEmojiImpl implements RecentEmoji, Client {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(RecentEmojiImpl.class.getName());
|
||||
|
||||
private static final String EMOJI_LRU_PREFERENCE = "pref_emoji_recent2";
|
||||
private static final int EMOJI_LRU_SIZE = 50;
|
||||
|
||||
// UI thread
|
||||
private final LinkedHashSet<Emoji> recentlyUsed = new LinkedHashSet<>();
|
||||
|
||||
private final Executor dbExecutor;
|
||||
private final AndroidExecutor androidExecutor;
|
||||
private final SettingsManager settingsManager;
|
||||
|
||||
@Inject
|
||||
RecentEmojiImpl(@DatabaseExecutor Executor dbExecutor,
|
||||
AndroidExecutor androidExecutor, SettingsManager settingsManager) {
|
||||
this.dbExecutor = dbExecutor;
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.settingsManager = settingsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Emoji> getRecentEmojis() {
|
||||
return new ArrayList<>(recentlyUsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEmoji(Emoji emoji) {
|
||||
recentlyUsed.remove(emoji);
|
||||
recentlyUsed.add(emoji);
|
||||
|
||||
if (recentlyUsed.size() > EMOJI_LRU_SIZE) {
|
||||
Iterator<Emoji> iterator = recentlyUsed.iterator();
|
||||
iterator.next();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persist() {
|
||||
if (!recentlyUsed.isEmpty()) save(serialize(recentlyUsed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLocalState(Transaction txn) throws DbException {
|
||||
Settings settings =
|
||||
settingsManager.getSettings(txn, SETTINGS_NAMESPACE);
|
||||
String serialized = settings.get(EMOJI_LRU_PREFERENCE);
|
||||
if (serialized != null) {
|
||||
androidExecutor.runOnUiThread(() ->
|
||||
recentlyUsed.addAll(deserialize(serialized)));
|
||||
}
|
||||
}
|
||||
|
||||
private String serialize(Collection<Emoji> emojis) {
|
||||
Collection<String> strings = new ArrayList<>(emojis.size());
|
||||
for (Emoji emoji : emojis) strings.add(emoji.getUnicode());
|
||||
return StringUtils.join(strings, "\t");
|
||||
}
|
||||
|
||||
private Collection<Emoji> deserialize(String serialized) {
|
||||
Collection<EmojiRange> ranges = EmojiUtils.emojis(serialized);
|
||||
Collection<Emoji> result = new ArrayList<>(ranges.size());
|
||||
for (EmojiRange range : ranges) result.add(range.emoji);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void save(String serialized) {
|
||||
dbExecutor.execute(() -> {
|
||||
Settings settings = new Settings();
|
||||
settings.put(EMOJI_LRU_PREFERENCE, serialized);
|
||||
try {
|
||||
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,6 @@ public class GroupActivity extends
|
||||
if (!enabled) {
|
||||
textInput.setVisibility(GONE);
|
||||
if (textInput.isKeyboardOpen()) textInput.hideSoftKeyboard();
|
||||
if (textInput.isEmojiDrawerOpen()) textInput.hideEmojiDrawer();
|
||||
} else {
|
||||
textInput.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -15,6 +17,8 @@ import javax.annotation.Nullable;
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
|
||||
@UiThread
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class LargeTextInputView extends TextInputView {
|
||||
|
||||
public LargeTextInputView(Context context) {
|
||||
@@ -46,30 +50,28 @@ public class LargeTextInputView extends TextInputView {
|
||||
R.styleable.LargeTextInputView);
|
||||
String buttonText =
|
||||
attributes.getString(R.styleable.LargeTextInputView_buttonText);
|
||||
int maxLines =
|
||||
attributes
|
||||
.getInteger(R.styleable.LargeTextInputView_maxLines, 0);
|
||||
int maxLines = attributes
|
||||
.getInteger(R.styleable.LargeTextInputView_maxLines, 0);
|
||||
boolean fillHeight = attributes
|
||||
.getBoolean(R.styleable.LargeTextInputView_fillHeight,
|
||||
false);
|
||||
.getBoolean(R.styleable.LargeTextInputView_fillHeight, false);
|
||||
attributes.recycle();
|
||||
|
||||
if (buttonText != null) setButtonText(buttonText);
|
||||
if (maxLines > 0) ui.editText.setMaxLines(maxLines);
|
||||
if (maxLines > 0) editText.setMaxLines(maxLines);
|
||||
if (fillHeight) {
|
||||
ViewGroup layout = findViewById(R.id.input_layout);
|
||||
LayoutParams params = (LayoutParams) layout.getLayoutParams();
|
||||
params.height = 0;
|
||||
params.weight = 1;
|
||||
layout.setLayoutParams(params);
|
||||
ViewGroup.LayoutParams editParams = ui.editText.getLayoutParams();
|
||||
ViewGroup.LayoutParams editParams = editText.getLayoutParams();
|
||||
editParams.height = MATCH_PARENT;
|
||||
ui.editText.setLayoutParams(editParams);
|
||||
editText.setLayoutParams(editParams);
|
||||
}
|
||||
}
|
||||
|
||||
public void setButtonText(String text) {
|
||||
((Button) ui.sendButton).setText(text);
|
||||
((Button) sendButton).setText(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,35 +8,47 @@ import android.os.IBinder;
|
||||
import android.support.annotation.CallSuper;
|
||||
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.KeyEvent;
|
||||
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;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.BriarApplication;
|
||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer.EmojiEventListener;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiEditText;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
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_BACK;
|
||||
import static android.view.KeyEvent.KEYCODE_ENTER;
|
||||
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
||||
|
||||
@UiThread
|
||||
public class TextInputView extends KeyboardAwareLinearLayout
|
||||
implements EmojiEventListener {
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class TextInputView extends KeyboardAwareLinearLayout {
|
||||
|
||||
protected final ViewHolder ui;
|
||||
protected TextInputListener listener;
|
||||
@Inject
|
||||
RecentEmoji recentEmoji;
|
||||
|
||||
@Nullable
|
||||
TextInputListener listener;
|
||||
|
||||
AppCompatImageButton emojiToggle;
|
||||
EmojiEditText editText;
|
||||
EmojiPopup emojiPopup;
|
||||
View sendButton;
|
||||
|
||||
public TextInputView(Context context) {
|
||||
this(context, null);
|
||||
@@ -49,11 +61,12 @@ public class TextInputView extends KeyboardAwareLinearLayout
|
||||
public TextInputView(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
BriarApplication app =
|
||||
(BriarApplication) context.getApplicationContext();
|
||||
app.getApplicationComponent().inject(this);
|
||||
setOrientation(VERTICAL);
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
|
||||
inflateLayout(context);
|
||||
ui = new ViewHolder();
|
||||
setUpViews(context, attrs);
|
||||
}
|
||||
|
||||
@@ -65,89 +78,79 @@ 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);
|
||||
attributes.recycle();
|
||||
|
||||
if (hint != null) {
|
||||
ui.editText.setHint(hint);
|
||||
}
|
||||
if (hint != null) editText.setHint(hint);
|
||||
|
||||
ui.emojiToggle.attach(ui.emojiDrawer);
|
||||
ui.emojiToggle.setOnClickListener(v -> onEmojiToggleClicked());
|
||||
ui.editText.setOnClickListener(v -> showSoftKeyboard());
|
||||
ui.editText.setOnKeyListener((v, keyCode, event) -> {
|
||||
if (keyCode == KEYCODE_BACK && isEmojiDrawerOpen()) {
|
||||
hideEmojiDrawer();
|
||||
return true;
|
||||
}
|
||||
emojiToggle.setOnClickListener(v -> emojiPopup.toggle());
|
||||
editText.setOnClickListener(v -> showSoftKeyboard());
|
||||
editText.setOnKeyListener((v, keyCode, event) -> {
|
||||
if (keyCode == KEYCODE_ENTER && event.isCtrlPressed()) {
|
||||
trySendMessage();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
ui.sendButton.setOnClickListener(v -> trySendMessage());
|
||||
ui.emojiDrawer.setEmojiEventListener(this);
|
||||
sendButton.setOnClickListener(v -> trySendMessage());
|
||||
}
|
||||
|
||||
private void showEmojiIcon() {
|
||||
emojiToggle.setImageResource(R.drawable.ic_emoji_toggle);
|
||||
}
|
||||
|
||||
private void showKeyboardIcon() {
|
||||
emojiToggle.setImageResource(R.drawable.ic_keyboard);
|
||||
}
|
||||
|
||||
private void trySendMessage() {
|
||||
if (listener != null) {
|
||||
listener.onSendClick(ui.editText.getText().toString());
|
||||
listener.onSendClick(editText.getText().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (visibility == GONE && isKeyboardOpen()) {
|
||||
onKeyboardClose();
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyEvent(KeyEvent keyEvent) {
|
||||
ui.editText.dispatchKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEmojiSelected(String emoji) {
|
||||
ui.editText.insertEmoji(emoji);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
|
||||
return ui.editText.requestFocus(direction, previouslyFocusedRect);
|
||||
return editText.requestFocus(direction, previouslyFocusedRect);
|
||||
}
|
||||
|
||||
private void onEmojiToggleClicked() {
|
||||
if (isEmojiDrawerOpen()) {
|
||||
showSoftKeyboard();
|
||||
} else {
|
||||
showEmojiDrawer();
|
||||
}
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (emojiPopup.isShowing()) emojiPopup.dismiss();
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
ui.editText.setText(text);
|
||||
editText.setText(text);
|
||||
}
|
||||
|
||||
public Editable getText() {
|
||||
return ui.editText.getText();
|
||||
return editText.getText();
|
||||
}
|
||||
|
||||
public void setHint(@StringRes int res) {
|
||||
ui.editText.setHint(res);
|
||||
editText.setHint(res);
|
||||
}
|
||||
|
||||
public void setSendButtonEnabled(boolean enabled) {
|
||||
ui.sendButton.setEnabled(enabled);
|
||||
sendButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void addTextChangedListener(TextWatcher watcher) {
|
||||
ui.editText.addTextChangedListener(watcher);
|
||||
editText.addTextChangedListener(watcher);
|
||||
}
|
||||
|
||||
public void setListener(TextInputListener listener) {
|
||||
@@ -155,58 +158,16 @@ public class TextInputView extends KeyboardAwareLinearLayout
|
||||
}
|
||||
|
||||
public void showSoftKeyboard() {
|
||||
if (isKeyboardOpen()) return;
|
||||
|
||||
if (ui.emojiDrawer.isShowing()) {
|
||||
postOnKeyboardOpen(this::hideEmojiDrawer);
|
||||
}
|
||||
ui.editText.post(() -> {
|
||||
ui.editText.requestFocus();
|
||||
InputMethodManager imm = (InputMethodManager)
|
||||
getContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(ui.editText, SHOW_IMPLICIT);
|
||||
});
|
||||
Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||
((InputMethodManager) o).showSoftInput(editText, SHOW_IMPLICIT);
|
||||
}
|
||||
|
||||
public void hideSoftKeyboard() {
|
||||
IBinder token = ui.editText.getWindowToken();
|
||||
IBinder token = editText.getWindowToken();
|
||||
Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||
((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
|
||||
}
|
||||
|
||||
public void showEmojiDrawer() {
|
||||
if (isKeyboardOpen()) {
|
||||
postOnKeyboardClose(() -> ui.emojiDrawer.show(getKeyboardHeight()));
|
||||
hideSoftKeyboard();
|
||||
} else {
|
||||
ui.emojiDrawer.show(getKeyboardHeight());
|
||||
ui.editText.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
public void hideEmojiDrawer() {
|
||||
ui.emojiDrawer.hide();
|
||||
}
|
||||
|
||||
public boolean isEmojiDrawerOpen() {
|
||||
return ui.emojiDrawer.isShowing();
|
||||
}
|
||||
|
||||
protected class ViewHolder {
|
||||
|
||||
private final EmojiToggle emojiToggle;
|
||||
final EmojiEditText editText;
|
||||
final View sendButton;
|
||||
final EmojiDrawer emojiDrawer;
|
||||
|
||||
private ViewHolder() {
|
||||
emojiToggle = findViewById(R.id.emoji_toggle);
|
||||
editText = findViewById(R.id.input_text);
|
||||
emojiDrawer = findViewById(R.id.emoji_drawer);
|
||||
sendButton = findViewById(R.id.btn_send);
|
||||
}
|
||||
}
|
||||
|
||||
public interface TextInputListener {
|
||||
void onSendClick(String text);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user