@ -0,0 +1,55 @@ |
|||
package gr.thmmy.mthmmy.editorview; |
|||
|
|||
import android.content.Context; |
|||
import android.content.res.TypedArray; |
|||
import android.util.AttributeSet; |
|||
import android.widget.GridLayout; |
|||
import gr.thmmy.mthmmy.R; |
|||
|
|||
public class AutoFitGridLayout extends GridLayout { |
|||
private int columnWidth; |
|||
private int defaultColumnCount; |
|||
|
|||
public AutoFitGridLayout(Context context) { |
|||
super(context); |
|||
init(context, null, 0); |
|||
} |
|||
|
|||
public AutoFitGridLayout(Context context, AttributeSet attrs) { |
|||
super(context, attrs); |
|||
init(context, attrs, 0); |
|||
} |
|||
|
|||
public AutoFitGridLayout(Context context, AttributeSet attrs, int defStyleAttr) { |
|||
super(context, attrs, defStyleAttr); |
|||
init(context, attrs, defStyleAttr); |
|||
} |
|||
|
|||
public void init(Context context, AttributeSet attrs, int defStyleAttr) { |
|||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoFitGridLayout, 0, defStyleAttr); |
|||
try { |
|||
columnWidth = a.getDimensionPixelSize(R.styleable.AutoFitGridLayout_columnWidth, 0); |
|||
|
|||
int[] set = {android.R.attr.columnCount}; |
|||
a = context.obtainStyledAttributes(attrs, set, 0, defStyleAttr); |
|||
defaultColumnCount = a.getInt(0, 6); |
|||
} finally { |
|||
a.recycle(); |
|||
} |
|||
setColumnCount(1); |
|||
} |
|||
|
|||
@Override |
|||
protected void onMeasure(int widthSpec, int heightSpec) { |
|||
super.onMeasure(widthSpec, heightSpec); |
|||
|
|||
int width = MeasureSpec.getSize(widthSpec); |
|||
if (columnWidth > 0 && width > 0) { |
|||
int totalSpace = width - getPaddingRight() - getPaddingLeft(); |
|||
int columnCount = Math.max(1, totalSpace / columnWidth); |
|||
setColumnCount(columnCount); |
|||
} else { |
|||
setColumnCount(defaultColumnCount); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,283 @@ |
|||
package gr.thmmy.mthmmy.editorview; |
|||
|
|||
import android.app.Activity; |
|||
import android.app.AlertDialog; |
|||
import android.content.Context; |
|||
import android.content.res.TypedArray; |
|||
import android.graphics.drawable.Drawable; |
|||
import android.support.annotation.Nullable; |
|||
import android.support.design.widget.TextInputEditText; |
|||
import android.support.design.widget.TextInputLayout; |
|||
import android.support.v7.widget.AppCompatImageButton; |
|||
import android.text.Editable; |
|||
import android.text.TextUtils; |
|||
import android.util.AttributeSet; |
|||
import android.util.SparseArray; |
|||
import android.view.LayoutInflater; |
|||
import android.view.inputmethod.EditorInfo; |
|||
import android.view.inputmethod.InputConnection; |
|||
import android.view.inputmethod.InputMethodManager; |
|||
import android.widget.LinearLayout; |
|||
import android.widget.PopupWindow; |
|||
import android.widget.ScrollView; |
|||
|
|||
import java.util.Objects; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
|
|||
public class EditorView extends LinearLayout { |
|||
|
|||
private SparseArray<String> colors = new SparseArray<>(); |
|||
|
|||
private TextInputLayout edittextWrapper; |
|||
private TextInputEditText editText; |
|||
private AppCompatImageButton emojiButton; |
|||
private AppCompatImageButton submitButton; |
|||
private EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner; |
|||
|
|||
public EditorView(Context context) { |
|||
super(context); |
|||
init(context, null); |
|||
} |
|||
|
|||
public EditorView(Context context, AttributeSet attrs) { |
|||
super(context, attrs); |
|||
init(context, attrs); |
|||
} |
|||
|
|||
public EditorView(Context context, AttributeSet attrs, int defStyleAttrs) { |
|||
super(context, attrs, defStyleAttrs); |
|||
init(context, attrs); |
|||
} |
|||
|
|||
private void init(Context context, AttributeSet attrs) { |
|||
LayoutInflater.from(context).inflate(R.layout.editor_view, this, true); |
|||
setOrientation(VERTICAL); |
|||
|
|||
edittextWrapper = findViewById(R.id.editor_edittext_wrapper); |
|||
editText = findViewById(R.id.editor_edittext); |
|||
|
|||
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EditorView, 0, 0); |
|||
try { |
|||
editText.setHint(a.getString(R.styleable.EditorView_hint)); |
|||
} finally { |
|||
a.recycle(); |
|||
} |
|||
|
|||
// without this, the editor gets default window background
|
|||
Drawable background = getBackground(); |
|||
for (int i = 0; i < getChildCount(); i++) { |
|||
getChildAt(i).setBackground(background); |
|||
} |
|||
|
|||
emojiButton = findViewById(R.id.emoji_keyboard_button); |
|||
|
|||
editText.setOnTouchListener((v, event) -> { |
|||
if (emojiKeyboardOwner.isEmojiKeyboardVisible()) return true; |
|||
return false; |
|||
}); |
|||
|
|||
emojiButton.setOnClickListener(view -> { |
|||
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); |
|||
assert imm != null; |
|||
if (emojiKeyboardOwner.isEmojiKeyboardVisible()) { |
|||
editText.requestFocus(); |
|||
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); |
|||
emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); |
|||
} else { |
|||
imm.hideSoftInputFromWindow(getWindowToken(), 0); |
|||
view.clearFocus(); |
|||
emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); |
|||
} |
|||
emojiKeyboardOwner.setEmojiKeyboardVisible(!emojiKeyboardOwner.isEmojiKeyboardVisible()); |
|||
}); |
|||
|
|||
submitButton = findViewById(R.id.submit_button); |
|||
findViewById(R.id.bold_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[b]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/b]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|||
}); |
|||
findViewById(R.id.italic_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[i]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/i]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|||
}); |
|||
findViewById(R.id.underline_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[u]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/u]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|||
}); |
|||
findViewById(R.id.strikethrough_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[s]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/s]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|||
}); |
|||
|
|||
colors.append(R.id.black, "black"); |
|||
colors.append(R.id.red, "red"); |
|||
colors.append(R.id.yellow, "yellow"); |
|||
colors.append(R.id.pink, "pink"); |
|||
colors.append(R.id.green, "green"); |
|||
colors.append(R.id.orange, "orange"); |
|||
colors.append(R.id.purple, "purple"); |
|||
colors.append(R.id.blue, "blue"); |
|||
colors.append(R.id.beige, "beige"); |
|||
colors.append(R.id.brown, "brown"); |
|||
colors.append(R.id.teal, "teal"); |
|||
colors.append(R.id.navy, "navy"); |
|||
colors.append(R.id.maroon, "maroon"); |
|||
colors.append(R.id.lime_green, "limegreen"); |
|||
|
|||
findViewById(R.id.text_color_button).setOnClickListener(view -> { |
|||
PopupWindow popupWindow = new PopupWindow(view.getContext()); |
|||
popupWindow.setHeight(LayoutParams.WRAP_CONTENT); |
|||
popupWindow.setWidth(LayoutParams.WRAP_CONTENT); |
|||
popupWindow.setFocusable(true); |
|||
ScrollView colorPickerScrollview = (ScrollView) LayoutInflater.from(context).inflate(R.layout.editor_view_color_picker, null); |
|||
LinearLayout colorPicker = (LinearLayout) colorPickerScrollview.getChildAt(0); |
|||
popupWindow.setContentView(colorPickerScrollview); |
|||
for (int i = 0; i < colorPicker.getChildCount(); i++) { |
|||
colorPicker.getChildAt(i).setOnClickListener(v -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[color=" + colors.get(v.getId()) + "]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/color]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); |
|||
popupWindow.dismiss(); |
|||
}); |
|||
} |
|||
popupWindow.showAsDropDown(view); |
|||
}); |
|||
findViewById(R.id.text_size_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[size=10pt]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/size]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|||
}); |
|||
findViewById(R.id.font_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[font=Verdana]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/font]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|||
}); |
|||
findViewById(R.id.unordered_list_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[list]\n[li]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/li]\n[li][/li]\n[/list]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() - 13 : editText.getSelectionStart() - 23); |
|||
}); |
|||
findViewById(R.id.align_left_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[left]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/left]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|||
}); |
|||
findViewById(R.id.align_center_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[center]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/center]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 9); |
|||
}); |
|||
findViewById(R.id.align_right_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[right]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/right]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); |
|||
}); |
|||
findViewById(R.id.link_button).setOnClickListener(view -> { |
|||
LinearLayout dialogBody = (LinearLayout) LayoutInflater.from(context) |
|||
.inflate(R.layout.dialog_create_link, null); |
|||
TextInputLayout linkUrl = dialogBody.findViewById(R.id.link_url_input); |
|||
linkUrl.setOnClickListener(view1 -> linkUrl.setError(null)); |
|||
TextInputLayout linkText = dialogBody.findViewById(R.id.link_text_input); |
|||
linkText.setOnClickListener(view2 -> linkText.setError(null)); |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
int start = editText.getSelectionStart(), end = editText.getSelectionEnd(); |
|||
if (editText.hasSelection()) { |
|||
linkText.getEditText().setText( |
|||
editText.getText().toString().substring(editText.getSelectionStart(), editText.getSelectionEnd())); |
|||
} |
|||
new AlertDialog.Builder(context, R.style.AppCompatAlertDialogStyleAccent) |
|||
.setTitle(R.string.dialog_create_link_title) |
|||
.setView(dialogBody) |
|||
.setPositiveButton(R.string.ok, (dialog, which) -> { |
|||
if (TextUtils.isEmpty(Objects.requireNonNull(linkUrl.getEditText()).getText().toString())) { |
|||
linkUrl.setError(context.getString(R.string.input_field_required)); |
|||
return; |
|||
} |
|||
if (TextUtils.isEmpty(Objects.requireNonNull(linkText.getEditText()).getText().toString())) { |
|||
linkUrl.setError(context.getString(R.string.input_field_required)); |
|||
return; |
|||
} |
|||
|
|||
if (hadTextSelection) editText.getText().delete(start, end); |
|||
getText().insert(editText.getSelectionStart(), "[url=" + |
|||
Objects.requireNonNull(linkUrl.getEditText()).getText().toString() + "]" + |
|||
Objects.requireNonNull(linkText.getEditText()).getText().toString() + "[/url]"); |
|||
}) |
|||
.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) |
|||
.show(); |
|||
}); |
|||
findViewById(R.id.quote_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[quote]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/quote]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); |
|||
}); |
|||
findViewById(R.id.code_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[code]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/code]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|||
}); |
|||
findViewById(R.id.math_button).setOnClickListener(view -> { |
|||
boolean hadTextSelection = editText.hasSelection(); |
|||
getText().insert(editText.getSelectionStart(), "[tex]"); |
|||
getText().insert(editText.getSelectionEnd(), "[/tex]"); |
|||
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 6); |
|||
}); |
|||
} |
|||
|
|||
public TextInputEditText getEditText() { |
|||
return editText; |
|||
} |
|||
|
|||
public Editable getText() { |
|||
return editText.getText(); |
|||
} |
|||
|
|||
public void setText(Editable text) { |
|||
editText.setText(text); |
|||
} |
|||
|
|||
public void setText(CharSequence text) { |
|||
editText.setText(text); |
|||
} |
|||
|
|||
public void setError(@Nullable CharSequence text) { |
|||
edittextWrapper.setError(text); |
|||
} |
|||
|
|||
public void setOnSubmitListener(OnClickListener onSubmitListener) { |
|||
submitButton.setOnClickListener(onSubmitListener); |
|||
} |
|||
|
|||
public void setEmojiKeyboardOwner(EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner) { |
|||
this.emojiKeyboardOwner = emojiKeyboardOwner; |
|||
} |
|||
|
|||
public InputConnection getInputConnection() { |
|||
return editText.onCreateInputConnection(new EditorInfo()); |
|||
} |
|||
|
|||
public void updateEmojiKeyboardVisibility() { |
|||
if (emojiKeyboardOwner.isEmojiKeyboardVisible()) |
|||
emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); |
|||
else |
|||
emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); |
|||
} |
|||
} |
@ -0,0 +1,241 @@ |
|||
package gr.thmmy.mthmmy.editorview; |
|||
|
|||
import android.content.Context; |
|||
import android.os.Handler; |
|||
import android.support.v7.widget.AppCompatImageButton; |
|||
import android.support.v7.widget.GridLayoutManager; |
|||
import android.support.v7.widget.RecyclerView; |
|||
import android.text.TextUtils; |
|||
import android.util.AttributeSet; |
|||
import android.view.LayoutInflater; |
|||
import android.view.MotionEvent; |
|||
import android.view.inputmethod.InputConnection; |
|||
import android.widget.LinearLayout; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
|
|||
public class EmojiKeyboard extends LinearLayout { |
|||
|
|||
// TODO: Sort emojis in a way that makes sense
|
|||
private final Emoji[] emojis = {new Emoji(R.drawable.emoji_smiley, ":)"), |
|||
new Emoji(R.drawable.emoji_wink, ";)"), |
|||
new Emoji(R.drawable.emoji_cheesy, ":D"), |
|||
new Emoji(R.drawable.emoji_grin, ";D"), |
|||
// removed repeated angry emoji
|
|||
new Emoji(R.drawable.emoji_angry, ">:("), |
|||
new Emoji(R.drawable.emoji_sad, ":("), |
|||
new Emoji(R.drawable.emoji_shocked, ":o"), |
|||
new Emoji(R.drawable.emoji_cool, "8))"), |
|||
new Emoji(R.drawable.emoji_huh, ":???:"), |
|||
new Emoji(R.drawable.emoji_rolleyes, "::)"), |
|||
new Emoji(R.drawable.emoji_tongue, ":P"), |
|||
new Emoji(R.drawable.emoji_embarrassed, ":-["), |
|||
new Emoji(R.drawable.emoji_lipsrsealed, ":-X"), |
|||
new Emoji(R.drawable.emoji_undecided, ":-\\\\"), |
|||
new Emoji(R.drawable.emoji_kiss, ":-*"), |
|||
new Emoji(R.drawable.emoji_cry, ":'("), |
|||
new Emoji(R.drawable.emoji_heart, "<3"), |
|||
// removed repeated lock emoji
|
|||
new Emoji(R.drawable.emoji_locked, "^lock^"), |
|||
new Emoji(R.drawable.emoji_roll_over, "^rollover^"), |
|||
new Emoji(R.drawable.emoji_redface, "^redface^"), |
|||
new Emoji(R.drawable.emoji_confused, "^confused^"), |
|||
new Emoji(R.drawable.emoji_innocent, "^innocent^"), |
|||
new Emoji(R.drawable.emoji_sleep, "^sleep^"), |
|||
new Emoji(R.drawable.emoji_lips_sealed, "^sealed^"), |
|||
new Emoji(R.drawable.emoji_cool2, "^cool^"), |
|||
new Emoji(R.drawable.emoji_monster, "^monster^"), |
|||
new Emoji(R.drawable.emoji_crazy, "^crazy^"), |
|||
new Emoji(R.drawable.emoji_mad, "^mad^"), |
|||
new Emoji(R.drawable.emoji_wav, "^wav^"), |
|||
new Emoji(R.drawable.emoji_binkybaby, "^binkybaby^"), |
|||
new Emoji(R.drawable.emoji_police, "^police^"), |
|||
new Emoji(R.drawable.emoji_dontknow, "^dontknow^"), |
|||
//removed repeated angry hot emoji
|
|||
new Emoji(R.drawable.emoji_angry_hot, "^angryhot^"), |
|||
new Emoji(R.drawable.emoji_foyska, "^fouska^"), |
|||
new Emoji(R.drawable.emoji_e10_7_3e, "^sfinaki^"), |
|||
new Emoji(R.drawable.emoji_bang_head, "^banghead^"), |
|||
new Emoji(R.drawable.emoji_crybaby, "^crybaby^"), |
|||
new Emoji(R.drawable.emoji_hello, "^hello^"), |
|||
new Emoji(R.drawable.emoji_jerk, "^jerk^"), |
|||
new Emoji(R.drawable.emoji_nono, "^nono^"), |
|||
new Emoji(R.drawable.emoji_notworthy, "^notworthy^"), |
|||
new Emoji(R.drawable.emoji_off_topic, "^off-topic^"), |
|||
new Emoji(R.drawable.emoji_puke, "^puke^"), |
|||
new Emoji(R.drawable.emoji_shout, "^shout^"), |
|||
new Emoji(R.drawable.emoji_slurp, "^slurp^"), |
|||
new Emoji(R.drawable.emoji_superconfused, "^superconfused^"), |
|||
new Emoji(R.drawable.emoji_superinnocent, "^superinnocent^"), |
|||
new Emoji(R.drawable.emoji_cell_phone, "^cellPhone^"), |
|||
new Emoji(R.drawable.emoji_idiot, "^idiot^"), |
|||
new Emoji(R.drawable.emoji_knuppel, "^knuppel^"), |
|||
new Emoji(R.drawable.emoji_tickedoff, "^tickedOff^"), |
|||
new Emoji(R.drawable.emoji_peace, "^peace^"), |
|||
new Emoji(R.drawable.emoji_suspicious, "^suspicious^"), |
|||
new Emoji(R.drawable.emoji_caffine, "^caffine^"), |
|||
new Emoji(R.drawable.emoji_argue, "^argue^"), |
|||
new Emoji(R.drawable.emoji_banned2, "^banned2^"), |
|||
new Emoji(R.drawable.emoji_banned, "^banned^"), |
|||
new Emoji(R.drawable.emoji_bath, "^bath^"), |
|||
new Emoji(R.drawable.emoji_beg, "^beg^"), |
|||
new Emoji(R.drawable.emoji_bluescreen, "^bluescreen^"), |
|||
new Emoji(R.drawable.emoji_boil, "^boil^"), |
|||
new Emoji(R.drawable.emoji_bye, "^bye^"), |
|||
new Emoji(R.drawable.emoji_callmerip, "^callmerip^"), |
|||
new Emoji(R.drawable.emoji_carnaval, "^carnaval^"), |
|||
new Emoji(R.drawable.emoji_clap, "^clap^"), |
|||
new Emoji(R.drawable.emoji_coffeepot, "^coffepot^"), |
|||
new Emoji(R.drawable.emoji_crap, "^crap^"), |
|||
new Emoji(R.drawable.emoji_curses, "^curses^"), |
|||
new Emoji(R.drawable.emoji_funny, "^funny^"), |
|||
new Emoji(R.drawable.emoji_guitar1, "^guitar^"), |
|||
new Emoji(R.drawable.emoji_icon_kissy, "^kissy^"), |
|||
new Emoji(R.drawable.emoji_band, "^band^"), |
|||
new Emoji(R.drawable.emoji_ivres, "^ivres^"), |
|||
new Emoji(R.drawable.emoji_kaloe, "^kaloe^"), |
|||
new Emoji(R.drawable.emoji_kremala, "^kremala^"), |
|||
new Emoji(R.drawable.emoji_moon, "^moon^"), |
|||
new Emoji(R.drawable.emoji_mopping, "^mopping^"), |
|||
new Emoji(R.drawable.emoji_mountza, "^mountza^"), |
|||
new Emoji(R.drawable.emoji_pcsleep, "^pcsleep^"), |
|||
new Emoji(R.drawable.emoji_pinokio, "^pinokio^"), |
|||
new Emoji(R.drawable.emoji_poke, "^poke^"), |
|||
new Emoji(R.drawable.emoji_seestars, "^seestars^"), |
|||
new Emoji(R.drawable.emoji_sfyri, "^sfyri^"), |
|||
new Emoji(R.drawable.emoji_spam2, "^spam^"), |
|||
new Emoji(R.drawable.emoji_esuper, "^super^"), |
|||
new Emoji(R.drawable.emoji_tafos, "^tafos^"), |
|||
new Emoji(R.drawable.emoji_tomatomourh, "^tomato^"), |
|||
new Emoji(R.drawable.emoji_ytold, "^ytold^"), |
|||
new Emoji(R.drawable.emoji_beer2, "^beer^"), |
|||
new Emoji(R.drawable.emoji_yu, "^yue^"), |
|||
new Emoji(R.drawable.emoji_a_eatpaper, "^eatpaper^"), |
|||
new Emoji(R.drawable.emoji_fritz, "^fritz^"), |
|||
new Emoji(R.drawable.emoji_wade, "^wade^"), |
|||
new Emoji(R.drawable.emoji_lypi, "^lypi^"), |
|||
new Emoji(R.drawable.emoji_megashok1wq, "^aytoxeir^"), |
|||
new Emoji(R.drawable.emoji_victory, "^victory^"), |
|||
new Emoji(R.drawable.emoji_filarakia, "^filarakia^"), |
|||
new Emoji(R.drawable.emoji_bonjour_97213, "^hat^"), |
|||
new Emoji(R.drawable.emoji_curtseyqi9, "^miss^"), |
|||
new Emoji(R.drawable.emoji_rofl, "^rolfmao^"), |
|||
new Emoji(R.drawable.emoji_question, "^que^"), |
|||
new Emoji(R.drawable.emoji_shifty, "^shifty^"), |
|||
new Emoji(R.drawable.emoji_shy, "^shy^"), |
|||
new Emoji(R.drawable.emoji_music, "^music_listen^"), |
|||
new Emoji(R.drawable.emoji_shamed_bag, "^bagface^"), |
|||
new Emoji(R.drawable.emoji_rotfl, "^rotate^"), |
|||
new Emoji(R.drawable.emoji_love, "^love^"), |
|||
new Emoji(R.drawable.emoji_speech, "^speech^"), |
|||
new Emoji(R.drawable.emoji_facepalm, "^facepalm^"), |
|||
new Emoji(R.drawable.emoji_shocked2, "^shocked^"), |
|||
new Emoji(R.drawable.emoji_extremely_shocked, "^ex_shocked^"), |
|||
new Emoji(R.drawable.emoji_smurf, "^smurf^") |
|||
}; |
|||
|
|||
InputConnection inputConnection; |
|||
|
|||
public EmojiKeyboard(Context context) { |
|||
this(context, null, 0); |
|||
} |
|||
|
|||
public EmojiKeyboard(Context context, AttributeSet attrs) { |
|||
this(context, attrs, 0); |
|||
} |
|||
|
|||
public EmojiKeyboard(Context context, AttributeSet attrs, int defStyleAttrs) { |
|||
super(context, attrs, defStyleAttrs); |
|||
init(context, attrs); |
|||
} |
|||
|
|||
public void init(Context context, AttributeSet attrs) { |
|||
LayoutInflater.from(context).inflate(R.layout.emoji_keyboard, this, true); |
|||
setOrientation(VERTICAL); |
|||
|
|||
RecyclerView emojiRecyclerview = findViewById(R.id.emoji_recyclerview); |
|||
emojiRecyclerview.setHasFixedSize(true); |
|||
GridLayoutManager emojiLayoutManager = new GridLayoutManager(context, 6); |
|||
emojiLayoutManager.setSpanSizeLookup(new EmojiColumnSpanLookup()); |
|||
emojiRecyclerview.setLayoutManager(emojiLayoutManager); |
|||
|
|||
EmojiKeyboardAdapter emojiKeyboardAdapter = new EmojiKeyboardAdapter(emojis); |
|||
emojiKeyboardAdapter.setOnEmojiClickListener((view, position) -> { |
|||
if (inputConnection == null) return; |
|||
String bbcode = emojis[position].getBbcode(); |
|||
inputConnection.commitText(" " + bbcode, 1); |
|||
}); |
|||
emojiRecyclerview.setAdapter(emojiKeyboardAdapter); |
|||
AppCompatImageButton backspaceButton = findViewById(R.id.backspace_button); |
|||
// backspace behavior
|
|||
final Handler handler = new Handler(); |
|||
Runnable longPressed = new Runnable() { |
|||
@Override |
|||
public void run() { |
|||
inputConnection.deleteSurroundingText(1, 0); |
|||
handler.postDelayed(this, 50); |
|||
} |
|||
}; |
|||
backspaceButton.setOnTouchListener((v, event) -> { |
|||
switch (event.getAction()) { |
|||
case MotionEvent.ACTION_DOWN: |
|||
CharSequence selectedText = inputConnection.getSelectedText(0); |
|||
if (TextUtils.isEmpty(selectedText)) |
|||
inputConnection.deleteSurroundingText(1, 0); |
|||
else |
|||
inputConnection.commitText("", 1); |
|||
handler.postDelayed(longPressed, 400); |
|||
break; |
|||
case MotionEvent.ACTION_UP: |
|||
handler.removeCallbacks(longPressed); |
|||
break; |
|||
} |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
public void setInputConnection(InputConnection inputConnection) { |
|||
this.inputConnection = inputConnection; |
|||
} |
|||
|
|||
public interface EmojiKeyboardOwner { |
|||
void setEmojiKeyboardVisible(boolean visible); |
|||
boolean isEmojiKeyboardVisible(); |
|||
void setEmojiKeyboardInputConnection(InputConnection ic); |
|||
} |
|||
|
|||
class Emoji { |
|||
final int src; |
|||
final String bbcode; |
|||
|
|||
public Emoji(int src, String bbcode) { |
|||
this.src = src; |
|||
this.bbcode = bbcode; |
|||
} |
|||
|
|||
public int getSrc() { |
|||
return src; |
|||
} |
|||
|
|||
public String getBbcode() { |
|||
return bbcode; |
|||
} |
|||
} |
|||
|
|||
class EmojiColumnSpanLookup extends GridLayoutManager.SpanSizeLookup { |
|||
|
|||
@Override |
|||
public int getSpanSize(int position) { |
|||
switch (emojis[position].getSrc()) { |
|||
case R.drawable.emoji_wav: |
|||
return 4; |
|||
case R.drawable.emoji_band: |
|||
return 3; |
|||
case R.drawable.emoji_pcsleep: |
|||
return 2; |
|||
default: |
|||
return 1; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,64 @@ |
|||
package gr.thmmy.mthmmy.editorview; |
|||
|
|||
import android.graphics.drawable.AnimationDrawable; |
|||
import android.support.annotation.NonNull; |
|||
import android.support.v7.widget.AppCompatImageButton; |
|||
import android.support.v7.widget.RecyclerView; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
|
|||
public class EmojiKeyboardAdapter extends RecyclerView.Adapter<EmojiKeyboardAdapter.EmojiViewHolder> { |
|||
private EmojiKeyboard.Emoji[] emojiIds; |
|||
private OnEmojiClickListener listener; |
|||
|
|||
public EmojiKeyboardAdapter(EmojiKeyboard.Emoji[] emojiIds) { |
|||
this.emojiIds = emojiIds; |
|||
} |
|||
|
|||
public void setOnEmojiClickListener(OnEmojiClickListener listener) { |
|||
this.listener = listener; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public EmojiViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
|||
AppCompatImageButton emojiButton = (AppCompatImageButton) LayoutInflater.from(parent.getContext()) |
|||
.inflate(R.layout.emoji_keyboard_grid_cell, parent, false); |
|||
return new EmojiViewHolder(emojiButton); |
|||
} |
|||
|
|||
@Override |
|||
public void onBindViewHolder(@NonNull EmojiViewHolder holder, int position) { |
|||
holder.emojiButton.setOnClickListener(view -> listener.onEmojiClick(view, position)); |
|||
} |
|||
|
|||
@Override |
|||
public void onViewAttachedToWindow(@NonNull EmojiViewHolder holder) { |
|||
holder.emojiButton.setImageResource(emojiIds[holder.getAdapterPosition()].getSrc()); |
|||
if (holder.emojiButton.getDrawable() instanceof AnimationDrawable) { |
|||
AnimationDrawable emojiAnimation = (AnimationDrawable) holder.emojiButton.getDrawable(); |
|||
emojiAnimation.start(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public int getItemCount() { |
|||
return emojiIds.length; |
|||
} |
|||
|
|||
static class EmojiViewHolder extends RecyclerView.ViewHolder { |
|||
AppCompatImageButton emojiButton; |
|||
|
|||
EmojiViewHolder(AppCompatImageButton emojiButton) { |
|||
super(emojiButton); |
|||
this.emojiButton = emojiButton; |
|||
} |
|||
} |
|||
|
|||
interface OnEmojiClickListener { |
|||
void onEmojiClick(View view, int position); |
|||
} |
|||
} |
@ -0,0 +1,42 @@ |
|||
package gr.thmmy.mthmmy.utils; |
|||
|
|||
import com.crashlytics.android.Crashlytics; |
|||
|
|||
import org.jsoup.nodes.Document; |
|||
import org.jsoup.nodes.Element; |
|||
import org.jsoup.select.Elements; |
|||
|
|||
import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; |
|||
|
|||
public class CrashReporter { |
|||
private static final int STRING_BATCH_LENGTH = 250; |
|||
|
|||
private CrashReporter() {} |
|||
|
|||
public static void reportDocument(Document document, String key) { |
|||
String documentString = document.toString(); |
|||
|
|||
ParseHelpers.Language language = ParseHelpers.Language.getLanguage(document); |
|||
Elements postRows; |
|||
if (language.is(ParseHelpers.Language.GREEK)) |
|||
postRows = document.select("form[id=quickModForm]>table>tbody>tr:matches(στις)"); |
|||
else |
|||
postRows = document.select("form[id=quickModForm]>table>tbody>tr:matches(on)"); |
|||
for (Element thisRow : postRows) { |
|||
String subject = thisRow.select("div[id^=subject_]").first().select("a").first().text(); |
|||
documentString = documentString.replace(subject, "subject"); |
|||
String post = thisRow.select("div").select(".post").first().text(); |
|||
documentString = documentString.replace(post, "post"); |
|||
} |
|||
|
|||
int batchCount = documentString.length() / STRING_BATCH_LENGTH; |
|||
for (int i = 0; i < batchCount; i++) { |
|||
String batch; |
|||
if (i != batchCount - 1) |
|||
batch = documentString.substring(i * STRING_BATCH_LENGTH, (i + 1) * STRING_BATCH_LENGTH); |
|||
else |
|||
batch = documentString.substring(i * STRING_BATCH_LENGTH); |
|||
Crashlytics.setString(key + "_" + i + 1, batch); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,240 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<animation-list |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:oneshot="false" > |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f0" |
|||
android:duration="500" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f1" |
|||
android:duration="500" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f2" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f3" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f4" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f5" |
|||
android:duration="500" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f6" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f7" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f8" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f9" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f10" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f11" |
|||
android:duration="500" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f12" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f13" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f14" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f15" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f16" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f17" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f18" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f19" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f20" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f21" |
|||
android:duration="500" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f22" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f23" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f24" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f25" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f26" |
|||
android:duration="400" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f27" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f28" |
|||
android:duration="400" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f29" |
|||
android:duration="300" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f30" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f31" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f32" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f33" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f34" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f35" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f36" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f37" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f38" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f39" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f40" |
|||
android:duration="300" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f41" |
|||
android:duration="50" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f42" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f43" |
|||
android:duration="10" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f44" |
|||
android:duration="10" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f45" |
|||
android:duration="300" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f46" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f47" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f48" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f49" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f50" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f51" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f52" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f53" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f54" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f55" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f56" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f57" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f58" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f59" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f60" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f61" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f62" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f63" |
|||
android:duration="200" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f64" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f65" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f66" |
|||
android:duration="300" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f67" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f68" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f69" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f70" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f71" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f72" |
|||
android:duration="150" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f73" |
|||
android:duration="700" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f74" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f75" |
|||
android:duration="700" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f76" |
|||
android:duration="100" /> |
|||
<item |
|||
android:drawable="@drawable/emoji_a_eatpaper_f77" |
|||
android:duration="1000" /> |
|||
|
|||
</animation-list> |
After Width: | Height: | Size: 636 B |
After Width: | Height: | Size: 603 B |
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 630 B |
After Width: | Height: | Size: 628 B |
After Width: | Height: | Size: 630 B |
After Width: | Height: | Size: 628 B |
After Width: | Height: | Size: 630 B |
After Width: | Height: | Size: 628 B |
After Width: | Height: | Size: 629 B |
After Width: | Height: | Size: 628 B |
After Width: | Height: | Size: 629 B |
After Width: | Height: | Size: 617 B |
After Width: | Height: | Size: 628 B |
After Width: | Height: | Size: 629 B |
After Width: | Height: | Size: 633 B |
After Width: | Height: | Size: 570 B |
After Width: | Height: | Size: 614 B |
After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 641 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 603 B |
After Width: | Height: | Size: 631 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 631 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 631 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 631 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 631 B |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 617 B |
After Width: | Height: | Size: 628 B |
After Width: | Height: | Size: 620 B |
After Width: | Height: | Size: 565 B |
After Width: | Height: | Size: 555 B |
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 604 B |
After Width: | Height: | Size: 573 B |
After Width: | Height: | Size: 605 B |
After Width: | Height: | Size: 536 B |
After Width: | Height: | Size: 517 B |
After Width: | Height: | Size: 614 B |
After Width: | Height: | Size: 527 B |
After Width: | Height: | Size: 516 B |
After Width: | Height: | Size: 526 B |
After Width: | Height: | Size: 517 B |
After Width: | Height: | Size: 517 B |
After Width: | Height: | Size: 465 B |
After Width: | Height: | Size: 466 B |
After Width: | Height: | Size: 534 B |
After Width: | Height: | Size: 521 B |
After Width: | Height: | Size: 525 B |
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 521 B |
After Width: | Height: | Size: 536 B |
After Width: | Height: | Size: 521 B |
After Width: | Height: | Size: 525 B |
After Width: | Height: | Size: 521 B |
After Width: | Height: | Size: 522 B |
After Width: | Height: | Size: 524 B |
After Width: | Height: | Size: 514 B |
After Width: | Height: | Size: 520 B |
After Width: | Height: | Size: 527 B |
After Width: | Height: | Size: 614 B |
After Width: | Height: | Size: 523 B |
After Width: | Height: | Size: 522 B |
After Width: | Height: | Size: 521 B |