|
@ -8,6 +8,7 @@ import android.content.Context; |
|
|
import android.content.res.TypedArray; |
|
|
import android.content.res.TypedArray; |
|
|
import android.graphics.drawable.Drawable; |
|
|
import android.graphics.drawable.Drawable; |
|
|
import android.os.AsyncTask; |
|
|
import android.os.AsyncTask; |
|
|
|
|
|
import android.os.Build; |
|
|
import android.text.Editable; |
|
|
import android.text.Editable; |
|
|
import android.text.TextUtils; |
|
|
import android.text.TextUtils; |
|
|
import android.util.AttributeSet; |
|
|
import android.util.AttributeSet; |
|
@ -126,184 +127,244 @@ public class EditorView extends LinearLayout implements EmojiInputField { |
|
|
getResources().getDimension(R.dimen.editor_format_button_margin_between); |
|
|
getResources().getDimension(R.dimen.editor_format_button_margin_between); |
|
|
int columns = (int) Math.floor(displayMetrics.widthPixels / itemWidth); |
|
|
int columns = (int) Math.floor(displayMetrics.widthPixels / itemWidth); |
|
|
formatButtonsRecyclerview.setLayoutManager(new GridLayoutManager(context, columns)); |
|
|
formatButtonsRecyclerview.setLayoutManager(new GridLayoutManager(context, columns)); |
|
|
formatButtonsRecyclerview.setAdapter(new FormatButtonsAdapter((view, drawableId) -> { |
|
|
formatButtonsRecyclerview.setAdapter( |
|
|
switch (drawableId) { |
|
|
new FormatButtonsAdapter( |
|
|
case R.drawable.ic_format_bold: { |
|
|
(view, drawableId) -> { |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
boolean hadTextSelection; |
|
|
getText().insert(editText.getSelectionStart(), "[b]"); |
|
|
switch (drawableId) { |
|
|
getText().insert(editText.getSelectionEnd(), "[/b]"); |
|
|
case R.drawable.ic_format_bold: |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
break; |
|
|
getText().insert(editText.getSelectionStart(), "[b]"); |
|
|
} |
|
|
getText().insert(editText.getSelectionEnd(), "[/b]"); |
|
|
case R.drawable.ic_format_italic: { |
|
|
editText.setSelection( |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
hadTextSelection |
|
|
getText().insert(editText.getSelectionStart(), "[i]"); |
|
|
? editText.getSelectionEnd() |
|
|
getText().insert(editText.getSelectionEnd(), "[/i]"); |
|
|
: editText.getSelectionStart() - 4); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|
|
break; |
|
|
break; |
|
|
case R.drawable.ic_format_italic: |
|
|
} |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
case R.drawable.ic_format_underlined: { |
|
|
getText().insert(editText.getSelectionStart(), "[i]"); |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
getText().insert(editText.getSelectionEnd(), "[/i]"); |
|
|
getText().insert(editText.getSelectionStart(), "[u]"); |
|
|
editText.setSelection( |
|
|
getText().insert(editText.getSelectionEnd(), "[/u]"); |
|
|
hadTextSelection |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|
|
? editText.getSelectionEnd() |
|
|
break; |
|
|
: editText.getSelectionStart() - 4); |
|
|
} |
|
|
break; |
|
|
case R.drawable.ic_strikethrough_s: { |
|
|
case R.drawable.ic_format_underlined: |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
getText().insert(editText.getSelectionStart(), "[s]"); |
|
|
getText().insert(editText.getSelectionStart(), "[u]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/s]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/u]"); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 4); |
|
|
editText.setSelection( |
|
|
break; |
|
|
hadTextSelection |
|
|
} |
|
|
? editText.getSelectionEnd() |
|
|
case R.drawable.ic_format_color_text: { |
|
|
: editText.getSelectionStart() - 4); |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
break; |
|
|
int selectionStart = editText.getSelectionStart(); |
|
|
case R.drawable.ic_strikethrough_s: |
|
|
int selectionEnd = editText.getSelectionEnd(); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
PopupWindow popupWindow = new PopupWindow(view.getContext()); |
|
|
getText().insert(editText.getSelectionStart(), "[s]"); |
|
|
popupWindow.setHeight(LayoutParams.WRAP_CONTENT); |
|
|
getText().insert(editText.getSelectionEnd(), "[/s]"); |
|
|
popupWindow.setWidth(LayoutParams.WRAP_CONTENT); |
|
|
editText.setSelection( |
|
|
popupWindow.setFocusable(true); |
|
|
hadTextSelection |
|
|
ScrollView colorPickerScrollview = (ScrollView) LayoutInflater.from(context).inflate(R.layout.editor_view_color_picker, null); |
|
|
? editText.getSelectionEnd() |
|
|
LinearLayout colorPicker = (LinearLayout) colorPickerScrollview.getChildAt(0); |
|
|
: editText.getSelectionStart() - 4); |
|
|
popupWindow.setContentView(colorPickerScrollview); |
|
|
break; |
|
|
for (int i = 0; i < colorPicker.getChildCount(); i++) { |
|
|
case R.drawable.ic_format_color_text: |
|
|
TextView child = (TextView) colorPicker.getChildAt(i); |
|
|
int selectionStart = editText.getSelectionStart(); |
|
|
child.setOnClickListener(v -> { |
|
|
int selectionEnd = editText.getSelectionEnd(); |
|
|
boolean hadTextSelection2 = editText.hasSelection(); |
|
|
PopupWindow popupWindow = new PopupWindow(view.getContext()); |
|
|
getText().insert(editText.getSelectionStart(), "[color=" + colors.get(v.getId()) + "]"); |
|
|
popupWindow.setHeight(LayoutParams.WRAP_CONTENT); |
|
|
getText().insert(editText.getSelectionEnd(), "[/color]"); |
|
|
popupWindow.setWidth(LayoutParams.WRAP_CONTENT); |
|
|
editText.setSelection(hadTextSelection2 ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); |
|
|
popupWindow.setFocusable(true); |
|
|
popupWindow.dismiss(); |
|
|
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++) { |
|
|
|
|
|
TextView child = (TextView) colorPicker.getChildAt(i); |
|
|
|
|
|
child.setOnClickListener( |
|
|
|
|
|
v -> { |
|
|
|
|
|
boolean hadTextSelection2 = editText.hasSelection(); |
|
|
|
|
|
getText() |
|
|
|
|
|
.insert( |
|
|
|
|
|
editText.getSelectionStart(), |
|
|
|
|
|
"[color=" + colors.get(v.getId()) + "]"); |
|
|
|
|
|
getText().insert(editText.getSelectionEnd(), "[/color]"); |
|
|
|
|
|
editText.setSelection( |
|
|
|
|
|
hadTextSelection2 |
|
|
|
|
|
? editText.getSelectionEnd() |
|
|
|
|
|
: editText.getSelectionStart() - 8); |
|
|
|
|
|
popupWindow.dismiss(); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
popupWindow.showAsDropDown(view); |
|
|
popupWindow.showAsDropDown(view); |
|
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { |
|
|
new AsyncTask<Void, Void, Void>() { |
|
|
new AsyncTask<Void, Void, Void>() { |
|
|
@Override |
|
|
@Override |
|
|
protected Void doInBackground(Void... voids) { |
|
|
protected Void doInBackground(Void... voids) { |
|
|
try { |
|
|
try { |
|
|
Thread.sleep(100); |
|
|
Thread.sleep(100); |
|
|
} catch (InterruptedException e) { |
|
|
} catch (InterruptedException e) { |
|
|
Timber.e(e); |
|
|
Timber.e(e); |
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
protected void onPostExecute(Void aVoid) { |
|
|
protected void onPostExecute(Void aVoid) { |
|
|
editText.setSelection(selectionStart, selectionEnd); |
|
|
editText.setSelection(selectionStart, selectionEnd); |
|
|
} |
|
|
} |
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
|
|
break; |
|
|
} |
|
|
} |
|
|
break; |
|
|
case R.drawable.ic_format_size: { |
|
|
case R.drawable.ic_format_size: |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
getText().insert(editText.getSelectionStart(), "[size=10pt]"); |
|
|
getText().insert(editText.getSelectionStart(), "[size=10pt]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/size]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/size]"); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|
|
editText.setSelection( |
|
|
break; |
|
|
hadTextSelection |
|
|
} |
|
|
? editText.getSelectionEnd() |
|
|
case R.drawable.ic_text_format: { |
|
|
: editText.getSelectionStart() - 7); |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
break; |
|
|
getText().insert(editText.getSelectionStart(), "[font=Verdana]"); |
|
|
case R.drawable.ic_text_format: |
|
|
getText().insert(editText.getSelectionEnd(), "[/font]"); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|
|
getText().insert(editText.getSelectionStart(), "[font=Verdana]"); |
|
|
break; |
|
|
getText().insert(editText.getSelectionEnd(), "[/font]"); |
|
|
} |
|
|
editText.setSelection( |
|
|
case R.drawable.ic_format_list_bulleted: { |
|
|
hadTextSelection |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
? editText.getSelectionEnd() |
|
|
getText().insert(editText.getSelectionStart(), "[list]\n[li]"); |
|
|
: editText.getSelectionStart() - 7); |
|
|
getText().insert(editText.getSelectionEnd(), "[/li]\n[li][/li]\n[/list]"); |
|
|
break; |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() - 13 : editText.getSelectionStart() - 23); |
|
|
case R.drawable.ic_format_list_bulleted: |
|
|
break; |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
} |
|
|
getText().insert(editText.getSelectionStart(), "[list]\n[li]"); |
|
|
case R.drawable.ic_format_align_left: { |
|
|
getText().insert(editText.getSelectionEnd(), "[/li]\n[li][/li]\n[/list]"); |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
editText.setSelection( |
|
|
getText().insert(editText.getSelectionStart(), "[left]"); |
|
|
hadTextSelection |
|
|
getText().insert(editText.getSelectionEnd(), "[/left]"); |
|
|
? editText.getSelectionEnd() - 13 |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|
|
: editText.getSelectionStart() - 23); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
case R.drawable.ic_format_align_left: |
|
|
case R.drawable.ic_format_align_center: { |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
getText().insert(editText.getSelectionStart(), "[left]"); |
|
|
getText().insert(editText.getSelectionStart(), "[center]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/left]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/center]"); |
|
|
editText.setSelection( |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 9); |
|
|
hadTextSelection |
|
|
break; |
|
|
? editText.getSelectionEnd() |
|
|
} |
|
|
: editText.getSelectionStart() - 7); |
|
|
case R.drawable.ic_format_align_right: { |
|
|
break; |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
case R.drawable.ic_format_align_center: |
|
|
getText().insert(editText.getSelectionStart(), "[right]"); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
getText().insert(editText.getSelectionEnd(), "[/right]"); |
|
|
getText().insert(editText.getSelectionStart(), "[center]"); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); |
|
|
getText().insert(editText.getSelectionEnd(), "[/center]"); |
|
|
break; |
|
|
editText.setSelection( |
|
|
} |
|
|
hadTextSelection |
|
|
case R.drawable.ic_insert_link: { |
|
|
? editText.getSelectionEnd() |
|
|
LinearLayout dialogBody = (LinearLayout) LayoutInflater.from(context) |
|
|
: editText.getSelectionStart() - 9); |
|
|
.inflate(R.layout.dialog_create_link, null); |
|
|
break; |
|
|
TextInputLayout linkUrl = dialogBody.findViewById(R.id.link_url_input); |
|
|
case R.drawable.ic_format_align_right: |
|
|
linkUrl.setOnClickListener(view1 -> linkUrl.setError(null)); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
TextInputLayout linkText = dialogBody.findViewById(R.id.link_text_input); |
|
|
getText().insert(editText.getSelectionStart(), "[right]"); |
|
|
linkText.setOnClickListener(view2 -> linkText.setError(null)); |
|
|
getText().insert(editText.getSelectionEnd(), "[/right]"); |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
editText.setSelection( |
|
|
int start = editText.getSelectionStart(), end = editText.getSelectionEnd(); |
|
|
hadTextSelection |
|
|
if (editText.hasSelection()) { |
|
|
? editText.getSelectionEnd() |
|
|
linkText.getEditText().setText( |
|
|
: editText.getSelectionStart() - 8); |
|
|
editText.getText().toString().substring(editText.getSelectionStart(), editText.getSelectionEnd())); |
|
|
break; |
|
|
} |
|
|
case R.drawable.ic_insert_link: |
|
|
AlertDialog linkDialog = new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) |
|
|
LinearLayout dialogBody = |
|
|
.setTitle(R.string.dialog_create_link_title) |
|
|
(LinearLayout) |
|
|
.setView(dialogBody) |
|
|
LayoutInflater.from(context).inflate(R.layout.dialog_create_link, null); |
|
|
.setPositiveButton(R.string.ok, null) |
|
|
TextInputLayout linkUrl = dialogBody.findViewById(R.id.link_url_input); |
|
|
.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) |
|
|
linkUrl.setOnClickListener(view1 -> linkUrl.setError(null)); |
|
|
.create(); |
|
|
TextInputLayout linkText = dialogBody.findViewById(R.id.link_text_input); |
|
|
linkDialog.setOnShowListener(dialogInterface -> { |
|
|
linkText.setOnClickListener(view2 -> linkText.setError(null)); |
|
|
|
|
|
hadTextSelection = editText.hasSelection(); |
|
|
|
|
|
int start = editText.getSelectionStart(), end = editText.getSelectionEnd(); |
|
|
|
|
|
if (editText.hasSelection()) { |
|
|
|
|
|
linkText |
|
|
|
|
|
.getEditText() |
|
|
|
|
|
.setText( |
|
|
|
|
|
editText |
|
|
|
|
|
.getText() |
|
|
|
|
|
.toString() |
|
|
|
|
|
.substring( |
|
|
|
|
|
editText.getSelectionStart(), editText.getSelectionEnd())); |
|
|
|
|
|
} |
|
|
|
|
|
AlertDialog linkDialog = |
|
|
|
|
|
new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) |
|
|
|
|
|
.setTitle(R.string.dialog_create_link_title) |
|
|
|
|
|
.setView(dialogBody) |
|
|
|
|
|
.setPositiveButton(R.string.ok, null) |
|
|
|
|
|
.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) |
|
|
|
|
|
.create(); |
|
|
|
|
|
linkDialog.setOnShowListener( |
|
|
|
|
|
dialogInterface -> { |
|
|
Button button = linkDialog.getButton(AlertDialog.BUTTON_POSITIVE); |
|
|
Button button = linkDialog.getButton(AlertDialog.BUTTON_POSITIVE); |
|
|
button.setOnClickListener(view12 -> { |
|
|
button.setOnClickListener( |
|
|
if (TextUtils.isEmpty(Objects.requireNonNull(linkUrl.getEditText()).getText().toString())) { |
|
|
view12 -> { |
|
|
|
|
|
if (TextUtils.isEmpty( |
|
|
|
|
|
Objects.requireNonNull(linkUrl.getEditText()) |
|
|
|
|
|
.getText() |
|
|
|
|
|
.toString())) { |
|
|
linkUrl.setError(context.getString(R.string.input_field_required)); |
|
|
linkUrl.setError(context.getString(R.string.input_field_required)); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (hadTextSelection) editText.getText().delete(start, end); |
|
|
if (hadTextSelection) editText.getText().delete(start, end); |
|
|
if (!TextUtils.isEmpty(linkText.getEditText().getText())) { |
|
|
if (!TextUtils.isEmpty(linkText.getEditText().getText())) { |
|
|
getText().insert(editText.getSelectionStart(), "[url=" + |
|
|
getText() |
|
|
linkUrl.getEditText().getText().toString() + "]" + |
|
|
.insert( |
|
|
linkText.getEditText().getText().toString() + "[/url]"); |
|
|
editText.getSelectionStart(), |
|
|
} |
|
|
"[url=" |
|
|
else |
|
|
+ linkUrl.getEditText().getText().toString() |
|
|
getText().insert(editText.getSelectionStart(), "[url]" + |
|
|
+ "]" |
|
|
linkUrl.getEditText().getText().toString() + "[/url]"); |
|
|
+ linkText.getEditText().getText().toString() |
|
|
linkDialog.dismiss(); |
|
|
+ "[/url]"); |
|
|
}); |
|
|
} else |
|
|
}); |
|
|
getText() |
|
|
linkDialog.show(); |
|
|
.insert( |
|
|
break; |
|
|
editText.getSelectionStart(), |
|
|
} |
|
|
"[url]" |
|
|
case R.drawable.ic_format_quote: { |
|
|
+ linkUrl.getEditText().getText().toString() |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
+ "[/url]"); |
|
|
getText().insert(editText.getSelectionStart(), "[quote]"); |
|
|
linkDialog.dismiss(); |
|
|
getText().insert(editText.getSelectionEnd(), "[/quote]"); |
|
|
}); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 8); |
|
|
}); |
|
|
break; |
|
|
linkDialog.show(); |
|
|
} |
|
|
break; |
|
|
case R.drawable.ic_code: { |
|
|
case R.drawable.ic_format_quote: |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
getText().insert(editText.getSelectionStart(), "[code]"); |
|
|
getText().insert(editText.getSelectionStart(), "[quote]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/code]"); |
|
|
getText().insert(editText.getSelectionEnd(), "[/quote]"); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 7); |
|
|
editText.setSelection( |
|
|
break; |
|
|
hadTextSelection |
|
|
} |
|
|
? editText.getSelectionEnd() |
|
|
case R.drawable.ic_functions: { |
|
|
: editText.getSelectionStart() - 8); |
|
|
boolean hadTextSelection = editText.hasSelection(); |
|
|
break; |
|
|
getText().insert(editText.getSelectionStart(), "[tex]"); |
|
|
case R.drawable.ic_code: |
|
|
getText().insert(editText.getSelectionEnd(), "[/tex]"); |
|
|
hadTextSelection = editText.hasSelection(); |
|
|
editText.setSelection(hadTextSelection ? editText.getSelectionEnd() : editText.getSelectionStart() - 6); |
|
|
getText().insert(editText.getSelectionStart(), "[code]"); |
|
|
break; |
|
|
getText().insert(editText.getSelectionEnd(), "[/code]"); |
|
|
} |
|
|
editText.setSelection( |
|
|
default: throw new IllegalArgumentException("Unknown format button click"); |
|
|
hadTextSelection |
|
|
} |
|
|
? editText.getSelectionEnd() |
|
|
})); |
|
|
: editText.getSelectionStart() - 7); |
|
|
|
|
|
break; |
|
|
|
|
|
case R.drawable.ic_functions: |
|
|
|
|
|
hadTextSelection = editText.hasSelection(); |
|
|
|
|
|
getText().insert(editText.getSelectionStart(), "[tex]"); |
|
|
|
|
|
getText().insert(editText.getSelectionEnd(), "[/tex]"); |
|
|
|
|
|
editText.setSelection( |
|
|
|
|
|
hadTextSelection |
|
|
|
|
|
? editText.getSelectionEnd() |
|
|
|
|
|
: editText.getSelectionStart() - 6); |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
throw new IllegalArgumentException("Unknown format button click"); |
|
|
|
|
|
} |
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
emojiButton.setOnClickListener(view -> { |
|
|
emojiButton.setOnClickListener(view -> { |
|
|
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); |
|
|
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); |
|
|