1108652823
* Add EmojiCompat * EmojiCompat doesn' replace all emojis anymore * This app should be now capable of loading a EmojiCompat-font located in a file somewhere inside the device's storage * Should now replace all emojis * Add EmojiCompat support to EditTextTyped * Provide EmojiCompat fonts * The app won't crash anymore when no emoji font is available. Emoji font should now be located at [Private external app directory]/files/EmojiCompat.ttf * Removed BundledEmojiCompat dependency Since this EmojiCompat-implementation does not rely on BundledEmojiCompat, there's no reason to have it enabled. * Update EditTextTyped.kt Since connection isn't assigned to (I tried doing so), it can be declared final/val again. * Update README.md * Add some non-working emoji preferences * Add a short font list for testing * Finished implementation * Add Twemoji to font list * Update documentation, more comments * Delete AssetEmojiCompat which is obsolete now * Update the font list * Update the font list * Fix font list & add Exception handling for malformed JSON files (hopefully) * More fixes. It should work now... * Removed AssetEmojiCompat (again) * Add most of the changes * Improved the EmojiCompat dialog's style * The font list is now based on a static layout without external files * Re-add the real font URL for Twemoji * Emoji-font captions are now translatable * Removed one unused String (loading) * Removed emoji fonts from this repo * Applied changes from the PR change requests * The correct emoji font will be selected after cancelling a change * Add details on the EmojiCompat fonts available (not shown yet) * Add licensing information on Twemoji and Blobmoji * Reworked some strings * Moved FileEmojiCompat to its own library * Update FileEmojiCompat to the latest version (1.0.3) * EmojiCompat bug should be fixed * Better handling of failed downloads * Removed one TODO Signed-off-by: Constantin A <10349490+C1710@users.noreply.github.com> * Update emoji attribution strings Signed-off-by: Constantin A <10349490+C1710@users.noreply.github.com> * Fixed some misspelled strings Signed-off-by: Constantin A <10349490+C1710@users.noreply.github.com>
278 lines
10 KiB
Java
278 lines
10 KiB
Java
package com.keylesspalace.tusky;
|
|
|
|
import android.app.AlarmManager;
|
|
import android.app.PendingIntent;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.os.Build;
|
|
import android.preference.DialogPreference;
|
|
import android.preference.PreferenceManager;
|
|
import android.support.v7.app.AlertDialog;
|
|
import android.util.AttributeSet;
|
|
import android.util.Log;
|
|
import android.view.View;
|
|
import android.widget.ImageButton;
|
|
import android.widget.ImageView;
|
|
import android.widget.ProgressBar;
|
|
import android.widget.RadioButton;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import com.keylesspalace.tusky.util.EmojiCompatFont;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
/**
|
|
* This Preference lets the user select their preferred emoji font
|
|
*/
|
|
public class EmojiPreference extends DialogPreference {
|
|
private static final String TAG = "EmojiPreference";
|
|
private final Context context;
|
|
private EmojiCompatFont selected, original;
|
|
static final String FONT_PREFERENCE = "selected_emoji_font";
|
|
private static final EmojiCompatFont[] FONTS = EmojiCompatFont.FONTS;
|
|
// Please note that this array should be sorted in the same way as their fonts.
|
|
private static final int[] viewIds = {
|
|
R.id.item_nomoji,
|
|
R.id.item_blobmoji,
|
|
R.id.item_twemoji};
|
|
|
|
private ArrayList<RadioButton> radioButtons = new ArrayList<>();
|
|
|
|
|
|
public EmojiPreference(Context context, AttributeSet attrs) {
|
|
super(context, attrs);
|
|
this.context = context;
|
|
|
|
setDialogLayoutResource(R.layout.dialog_emojicompat);
|
|
|
|
setPositiveButtonText(android.R.string.ok);
|
|
setNegativeButtonText(android.R.string.cancel);
|
|
setDialogIcon(null);
|
|
|
|
// Find out which font is currently active
|
|
this.selected = EmojiCompatFont.byId(PreferenceManager
|
|
.getDefaultSharedPreferences(context)
|
|
.getInt(FONT_PREFERENCE, 0));
|
|
// We'll use this later to determine if anything has changed
|
|
this.original = this.selected;
|
|
|
|
setSummary(selected.getDisplay(context));
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
protected void onBindDialogView(View view) {
|
|
super.onBindDialogView(view);
|
|
for(int i = 0; i < viewIds.length; i++) {
|
|
setupItem(view.findViewById(viewIds[i]), FONTS[i]);
|
|
}
|
|
}
|
|
|
|
private void setupItem(View container, EmojiCompatFont font) {
|
|
Context context = container.getContext();
|
|
|
|
TextView title = container.findViewById(R.id.emojicompat_name);
|
|
TextView caption = container.findViewById(R.id.emojicompat_caption);
|
|
ImageView thumb = container.findViewById(R.id.emojicompat_thumb);
|
|
ImageButton download = container.findViewById(R.id.emojicompat_download);
|
|
|
|
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
|
|
|
|
RadioButton radio = container.findViewById(R.id.emojicompat_radio);
|
|
|
|
// Initialize all the views
|
|
title.setText(font.getDisplay(context));
|
|
caption.setText(font.getCaption(context));
|
|
thumb.setImageDrawable(font.getThumb(context));
|
|
|
|
// There needs to be a list of all the radio buttons in order to uncheck them when one is selected
|
|
radioButtons.add(radio);
|
|
|
|
updateItem(font, container);
|
|
|
|
// Set actions
|
|
download.setOnClickListener((downloadButton) ->
|
|
startDownload(font, container));
|
|
|
|
cancel.setOnClickListener((cancelButton) ->
|
|
cancelDownload(font, container));
|
|
|
|
radio.setOnClickListener((radioButton) ->
|
|
select(font, (RadioButton) radioButton));
|
|
|
|
container.setOnClickListener((containterView) ->
|
|
select(font,
|
|
containterView.findViewById(R.id.emojicompat_radio
|
|
)));
|
|
}
|
|
|
|
private void startDownload(EmojiCompatFont font, View container) {
|
|
ImageButton download = container.findViewById(R.id.emojicompat_download);
|
|
TextView caption = container.findViewById(R.id.emojicompat_caption);
|
|
|
|
ProgressBar progressBar = container.findViewById(R.id.emojicompat_progress);
|
|
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
|
|
|
|
// Switch to downloading style
|
|
download.setVisibility(View.GONE);
|
|
caption.setVisibility(View.GONE);
|
|
progressBar.setVisibility(View.VISIBLE);
|
|
cancel.setVisibility(View.VISIBLE);
|
|
|
|
|
|
font.downloadFont(context, new EmojiCompatFont.Downloader.EmojiDownloadListener() {
|
|
@Override
|
|
public void onDownloaded(EmojiCompatFont font) {
|
|
finishDownload(font, container);
|
|
}
|
|
|
|
@Override
|
|
public void onProgress(float progress) {
|
|
// The progress is returned as a float between 0 and 1
|
|
progress *= progressBar.getMax();
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
progressBar.setProgress((int) progress, true);
|
|
}
|
|
else {
|
|
progressBar.setProgress((int) progress);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onFailed() {
|
|
Toast.makeText(getContext(), R.string.download_failed, Toast.LENGTH_SHORT).show();
|
|
updateItem(font, container);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void cancelDownload(EmojiCompatFont font, View container) {
|
|
font.cancelDownload();
|
|
updateItem(font, container);
|
|
}
|
|
|
|
private void finishDownload(EmojiCompatFont font, View container) {
|
|
select(font, container.findViewById(R.id.emojicompat_radio));
|
|
updateItem(font, container);
|
|
}
|
|
|
|
/**
|
|
* Select a font both visually and logically
|
|
* @param font The font to be selected
|
|
* @param radio The radio button associated with it's visual item
|
|
*/
|
|
private void select(EmojiCompatFont font, RadioButton radio) {
|
|
selected = font;
|
|
// Uncheck all the other buttons
|
|
for(RadioButton other : radioButtons) {
|
|
if(other != radio) {
|
|
other.setChecked(false);
|
|
}
|
|
}
|
|
radio.setChecked(true);
|
|
}
|
|
|
|
/**
|
|
* Called when a "consistent" state is reached, i.e. it's not downloading the font
|
|
* @param font The font to be displayed
|
|
* @param container The ConstraintLayout containing the item
|
|
*/
|
|
private void updateItem(EmojiCompatFont font, View container) {
|
|
// Assignments
|
|
ImageButton download = container.findViewById(R.id.emojicompat_download);
|
|
TextView caption = container.findViewById(R.id.emojicompat_caption);
|
|
|
|
ProgressBar progress = container.findViewById(R.id.emojicompat_progress);
|
|
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
|
|
|
|
RadioButton radio = container.findViewById(R.id.emojicompat_radio);
|
|
|
|
// There's no download going on
|
|
progress.setVisibility(View.GONE);
|
|
cancel.setVisibility(View.GONE);
|
|
caption.setVisibility(View.VISIBLE);
|
|
|
|
if(font.isDownloaded(context)) {
|
|
// Make it selectable
|
|
download.setVisibility(View.GONE);
|
|
radio.setVisibility(View.VISIBLE);
|
|
container.setClickable(true);
|
|
}
|
|
else {
|
|
// Make it downloadable
|
|
download.setVisibility(View.VISIBLE);
|
|
radio.setVisibility(View.GONE);
|
|
container.setClickable(false);
|
|
}
|
|
|
|
// Select it if necessary
|
|
if(font == selected) {
|
|
radio.setChecked(true);
|
|
}
|
|
else {
|
|
radio.setChecked(false);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* In order to be able to use this font later on, it needs to be saved first.
|
|
*/
|
|
private void saveSelectedFont() {
|
|
int index = selected.getId();
|
|
Log.i(TAG, "saveSelectedFont: Font ID: " + index);
|
|
// It's saved using the key FONT_PREFERENCE
|
|
PreferenceManager
|
|
.getDefaultSharedPreferences(context)
|
|
.edit()
|
|
.putInt(FONT_PREFERENCE, index)
|
|
.apply();
|
|
setSummary(selected.getDisplay(getContext()));
|
|
}
|
|
|
|
/**
|
|
* That's it. The user doesn't want to switch between these amazing radio buttons anymore!
|
|
* That means, the selected font can be saved (if the user hit OK)
|
|
* @param positiveResult if OK has been selected.
|
|
*/
|
|
@Override
|
|
public void onDialogClosed(boolean positiveResult) {
|
|
if(positiveResult) {
|
|
saveSelectedFont();
|
|
if(selected != original) {
|
|
new AlertDialog.Builder(context)
|
|
.setTitle(R.string.restart_required)
|
|
.setMessage(R.string.restart_emoji)
|
|
.setNegativeButton(R.string.later, null)
|
|
.setPositiveButton(R.string.restart, ((dialog, which) -> {
|
|
// Restart the app
|
|
// TODO: I'm not sure if this is a good solution but it seems to work
|
|
// From https://stackoverflow.com/a/17166729/5070653
|
|
Intent launchIntent = new Intent(context, MainActivity.class);
|
|
PendingIntent mPendingIntent = PendingIntent.getActivity(
|
|
context,
|
|
// This is the codepoint of the party face emoji :D
|
|
0x1f973,
|
|
launchIntent,
|
|
PendingIntent.FLAG_CANCEL_CURRENT);
|
|
AlarmManager mgr =
|
|
(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
|
if (mgr != null) {
|
|
mgr.set(
|
|
AlarmManager.RTC,
|
|
System.currentTimeMillis() + 100,
|
|
mPendingIntent);
|
|
}
|
|
System.exit(0);
|
|
})).show();
|
|
}
|
|
}
|
|
else {
|
|
// This line is needed in order to reset the radio buttons later
|
|
selected = original;
|
|
}
|
|
}
|
|
|
|
}
|