|
|
|
|
@ -55,7 +55,17 @@ import java.util.Map;
|
|
|
|
|
*
|
|
|
|
|
* @see NoteEditActivity
|
|
|
|
|
*/
|
|
|
|
|
public class NoteEditText extends EditText {
|
|
|
|
|
import android.view.ScaleGestureDetector;
|
|
|
|
|
import android.view.GestureDetector;
|
|
|
|
|
import android.text.style.ImageSpan;
|
|
|
|
|
import net.micode.notes.tool.RichTextHelper;
|
|
|
|
|
import android.app.AlertDialog;
|
|
|
|
|
import android.widget.SeekBar;
|
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
|
|
|
|
|
|
public class NoteEditText extends EditText implements ScaleGestureDetector.OnScaleGestureListener {
|
|
|
|
|
// 日志标签
|
|
|
|
|
private static final String TAG = "NoteEditText";
|
|
|
|
|
// 当前EditText的索引
|
|
|
|
|
@ -63,6 +73,13 @@ public class NoteEditText extends EditText {
|
|
|
|
|
// 删除前的光标位置
|
|
|
|
|
private int mSelectionStartBeforeDelete;
|
|
|
|
|
|
|
|
|
|
// Scale Gesture Detector
|
|
|
|
|
private ScaleGestureDetector mScaleDetector;
|
|
|
|
|
private GestureDetector mGestureDetector;
|
|
|
|
|
private ImageSpan mSelectedImageSpan;
|
|
|
|
|
private int mInitialWidth;
|
|
|
|
|
private int mInitialHeight;
|
|
|
|
|
|
|
|
|
|
// 电话号码URI方案
|
|
|
|
|
private static final String SCHEME_TEL = "tel:" ;
|
|
|
|
|
// HTTP URI方案
|
|
|
|
|
@ -78,6 +95,74 @@ public class NoteEditText extends EditText {
|
|
|
|
|
sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onScale(ScaleGestureDetector detector) {
|
|
|
|
|
if (mSelectedImageSpan != null) {
|
|
|
|
|
float scaleFactor = detector.getScaleFactor();
|
|
|
|
|
int newWidth = (int) (mInitialWidth * scaleFactor);
|
|
|
|
|
int newHeight = (int) (mInitialHeight * scaleFactor);
|
|
|
|
|
|
|
|
|
|
// Constrain size
|
|
|
|
|
int maxWidth = getResources().getDisplayMetrics().widthPixels;
|
|
|
|
|
if (newWidth > maxWidth) {
|
|
|
|
|
newWidth = maxWidth;
|
|
|
|
|
newHeight = (int) (mInitialHeight * (maxWidth / (float) mInitialWidth));
|
|
|
|
|
}
|
|
|
|
|
if (newWidth < 100) newWidth = 100;
|
|
|
|
|
if (newHeight < 100) newHeight = 100;
|
|
|
|
|
|
|
|
|
|
if (mSelectedImageSpan.getDrawable() != null) {
|
|
|
|
|
mSelectedImageSpan.getDrawable().setBounds(0, 0, newWidth, newHeight);
|
|
|
|
|
// Force layout update
|
|
|
|
|
invalidate();
|
|
|
|
|
requestLayout();
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onScaleBegin(ScaleGestureDetector detector) {
|
|
|
|
|
float x = detector.getFocusX();
|
|
|
|
|
float y = detector.getFocusY();
|
|
|
|
|
|
|
|
|
|
x += getScrollX();
|
|
|
|
|
y += getScrollY();
|
|
|
|
|
x -= getTotalPaddingLeft();
|
|
|
|
|
y -= getTotalPaddingTop();
|
|
|
|
|
|
|
|
|
|
Layout layout = getLayout();
|
|
|
|
|
if (layout != null) {
|
|
|
|
|
int line = layout.getLineForVertical((int) y);
|
|
|
|
|
int offset = layout.getOffsetForHorizontal(line, x);
|
|
|
|
|
|
|
|
|
|
if (getText() instanceof Spanned) {
|
|
|
|
|
Spanned spanned = (Spanned) getText();
|
|
|
|
|
ImageSpan[] spans = spanned.getSpans(offset, offset, ImageSpan.class);
|
|
|
|
|
if (spans.length > 0) {
|
|
|
|
|
mSelectedImageSpan = spans[0];
|
|
|
|
|
if (mSelectedImageSpan.getDrawable() != null) {
|
|
|
|
|
Rect bounds = mSelectedImageSpan.getDrawable().getBounds();
|
|
|
|
|
mInitialWidth = bounds.width();
|
|
|
|
|
mInitialHeight = bounds.height();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onScaleEnd(ScaleGestureDetector detector) {
|
|
|
|
|
if (mSelectedImageSpan != null && mSelectedImageSpan.getDrawable() != null) {
|
|
|
|
|
Rect bounds = mSelectedImageSpan.getDrawable().getBounds();
|
|
|
|
|
RichTextHelper.updateImageSpanSize(this, mSelectedImageSpan, bounds.width(), bounds.height());
|
|
|
|
|
mSelectedImageSpan = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 文本视图变更监听器接口
|
|
|
|
|
* <p>
|
|
|
|
|
@ -123,6 +208,111 @@ public class NoteEditText extends EditText {
|
|
|
|
|
public NoteEditText(Context context) {
|
|
|
|
|
super(context, null);
|
|
|
|
|
mIndex = 0;
|
|
|
|
|
init(context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void init(Context context) {
|
|
|
|
|
mScaleDetector = new ScaleGestureDetector(context, this);
|
|
|
|
|
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onDoubleTap(MotionEvent e) {
|
|
|
|
|
float x = e.getX();
|
|
|
|
|
float y = e.getY();
|
|
|
|
|
|
|
|
|
|
x += getScrollX();
|
|
|
|
|
y += getScrollY();
|
|
|
|
|
x -= getTotalPaddingLeft();
|
|
|
|
|
y -= getTotalPaddingTop();
|
|
|
|
|
|
|
|
|
|
Layout layout = getLayout();
|
|
|
|
|
if (layout != null) {
|
|
|
|
|
int line = layout.getLineForVertical((int) y);
|
|
|
|
|
int offset = layout.getOffsetForHorizontal(line, x);
|
|
|
|
|
|
|
|
|
|
if (getText() instanceof Spanned) {
|
|
|
|
|
Spanned spanned = (Spanned) getText();
|
|
|
|
|
ImageSpan[] spans = spanned.getSpans(offset, offset, ImageSpan.class);
|
|
|
|
|
if (spans.length > 0) {
|
|
|
|
|
showResizeDialog(spans[0]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return super.onDoubleTap(e);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void showResizeDialog(final ImageSpan imageSpan) {
|
|
|
|
|
if (imageSpan.getDrawable() == null) return;
|
|
|
|
|
|
|
|
|
|
final Rect bounds = imageSpan.getDrawable().getBounds();
|
|
|
|
|
final int originalWidth = bounds.width();
|
|
|
|
|
final int originalHeight = bounds.height();
|
|
|
|
|
final float aspectRatio = (float) originalHeight / originalWidth;
|
|
|
|
|
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
|
|
|
|
builder.setTitle("Resize Image");
|
|
|
|
|
|
|
|
|
|
LinearLayout layout = new LinearLayout(getContext());
|
|
|
|
|
layout.setOrientation(LinearLayout.VERTICAL);
|
|
|
|
|
layout.setPadding(50, 20, 50, 20);
|
|
|
|
|
|
|
|
|
|
final TextView label = new TextView(getContext());
|
|
|
|
|
label.setText("Scale: 100%");
|
|
|
|
|
layout.addView(label);
|
|
|
|
|
|
|
|
|
|
final SeekBar seekBar = new SeekBar(getContext());
|
|
|
|
|
seekBar.setMax(200); // 0 to 200%
|
|
|
|
|
seekBar.setProgress(100);
|
|
|
|
|
layout.addView(seekBar);
|
|
|
|
|
|
|
|
|
|
builder.setView(layout);
|
|
|
|
|
|
|
|
|
|
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
|
|
|
|
// Minimum 10%
|
|
|
|
|
if (progress < 10) progress = 10;
|
|
|
|
|
|
|
|
|
|
float scale = progress / 100f;
|
|
|
|
|
int newWidth = (int) (originalWidth * scale);
|
|
|
|
|
int newHeight = (int) (newWidth * aspectRatio);
|
|
|
|
|
|
|
|
|
|
label.setText("Scale: " + progress + "%");
|
|
|
|
|
|
|
|
|
|
// Live preview
|
|
|
|
|
imageSpan.getDrawable().setBounds(0, 0, newWidth, newHeight);
|
|
|
|
|
invalidate();
|
|
|
|
|
requestLayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onStartTrackingTouch(SeekBar seekBar) {}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onStopTrackingTouch(SeekBar seekBar) {}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
Rect finalBounds = imageSpan.getDrawable().getBounds();
|
|
|
|
|
RichTextHelper.updateImageSpanSize(NoteEditText.this, imageSpan, finalBounds.width(), finalBounds.height());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
// Revert
|
|
|
|
|
imageSpan.getDrawable().setBounds(0, 0, originalWidth, originalHeight);
|
|
|
|
|
invalidate();
|
|
|
|
|
requestLayout();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -151,6 +341,7 @@ public class NoteEditText extends EditText {
|
|
|
|
|
*/
|
|
|
|
|
public NoteEditText(Context context, AttributeSet attrs) {
|
|
|
|
|
super(context, attrs, android.R.attr.editTextStyle);
|
|
|
|
|
init(context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -162,6 +353,7 @@ public class NoteEditText extends EditText {
|
|
|
|
|
*/
|
|
|
|
|
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
|
|
|
|
|
super(context, attrs, defStyle);
|
|
|
|
|
init(context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -174,6 +366,17 @@ public class NoteEditText extends EditText {
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
|
|
|
if (mScaleDetector != null) {
|
|
|
|
|
mScaleDetector.onTouchEvent(event);
|
|
|
|
|
if (mScaleDetector.isInProgress()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mGestureDetector != null) {
|
|
|
|
|
mGestureDetector.onTouchEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (event.getAction()) {
|
|
|
|
|
case MotionEvent.ACTION_DOWN:
|
|
|
|
|
// 获取触摸坐标
|
|
|
|
|
|