|
|
|
|
@ -27,14 +27,31 @@ import android.content.Context;
|
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
|
import android.content.pm.PackageManager;
|
|
|
|
|
import android.graphics.Paint;
|
|
|
|
|
import android.net.Uri;
|
|
|
|
|
import android.os.Build;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
import android.preference.PreferenceManager;
|
|
|
|
|
import android.provider.MediaStore;
|
|
|
|
|
import android.text.Spannable;
|
|
|
|
|
import android.text.SpannableString;
|
|
|
|
|
import android.text.SpannableStringBuilder;
|
|
|
|
|
import android.text.TextUtils;
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
import android.text.format.DateUtils;
|
|
|
|
|
import android.text.style.BackgroundColorSpan;
|
|
|
|
|
=======
|
|
|
|
|
import android.text.Editable;
|
|
|
|
|
import android.text.Html;
|
|
|
|
|
import android.text.format.DateUtils;
|
|
|
|
|
import android.text.style.BackgroundColorSpan;
|
|
|
|
|
import android.text.style.StyleSpan;
|
|
|
|
|
import android.text.style.UnderlineSpan;
|
|
|
|
|
import android.text.style.ImageSpan;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
|
import android.view.Menu;
|
|
|
|
|
@ -47,24 +64,25 @@ import android.widget.CheckBox;
|
|
|
|
|
import android.widget.CompoundButton;
|
|
|
|
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
|
|
|
|
import android.widget.EditText;
|
|
|
|
|
import android.widget.ImageButton;
|
|
|
|
|
import android.widget.ImageView;
|
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
import android.widget.ImageButton;
|
|
|
|
|
import android.provider.MediaStore;
|
|
|
|
|
import android.net.Uri;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import android.text.SpannableString;
|
|
|
|
|
import android.text.SpannableStringBuilder;
|
|
|
|
|
import android.text.Editable;
|
|
|
|
|
import android.text.style.ImageSpan;
|
|
|
|
|
import android.graphics.Typeface;
|
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
|
import android.graphics.BitmapFactory;
|
|
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
|
|
import android.content.ContentResolver;
|
|
|
|
|
import android.content.res.Resources;
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
|
import android.graphics.BitmapFactory;
|
|
|
|
|
import android.graphics.Color;
|
|
|
|
|
=======
|
|
|
|
|
// import android.support.annotation.NonNull;
|
|
|
|
|
import android.Manifest;
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
@ -178,8 +196,16 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
private SharedPreferences mSharedPrefs; // 共享偏好设置
|
|
|
|
|
private int mFontSizeId; // 字体大小ID
|
|
|
|
|
private ImageButton mBtnInsertImage; // 插入图片按钮 OMO
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
private String mText; // 用于存储富文本内容
|
|
|
|
|
private int mNoteLength; // 文本长度
|
|
|
|
|
=======
|
|
|
|
|
|
|
|
|
|
// 富文本工具栏按钮
|
|
|
|
|
private ImageButton mBtnBold; // 加粗按钮
|
|
|
|
|
private ImageButton mBtnItalic; // 斜体按钮
|
|
|
|
|
private ImageButton mBtnUnderline; // 下划线按钮
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
|
|
|
|
|
private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; // 字体大小偏好设置键
|
|
|
|
|
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; // 快捷图标标题最大长度
|
|
|
|
|
@ -373,6 +399,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
// 获取笔记原始内容(为空则赋空字符串,避免空指针)
|
|
|
|
|
String content = mWorkingNote.getContent() == null ? "" : mWorkingNote.getContent();
|
|
|
|
|
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
// 检查内容是否已经是HTML格式,如果是则直接加载
|
|
|
|
|
String finalHtml = content;
|
|
|
|
|
|
|
|
|
|
@ -405,6 +432,28 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
}
|
|
|
|
|
imgMatcher.appendTail(htmlContent); // 拼接剩余文本
|
|
|
|
|
finalHtml = htmlContent.toString();
|
|
|
|
|
=======
|
|
|
|
|
if (TextUtils.isEmpty(content)) {
|
|
|
|
|
mNoteEditor.setText("");
|
|
|
|
|
mNoteEditor.setSelection(0);
|
|
|
|
|
} else {
|
|
|
|
|
// 第一步:处理HTML编码字符,将&#xxx;转换为实际字符
|
|
|
|
|
String decodedContent = content;
|
|
|
|
|
try {
|
|
|
|
|
// 使用Html.fromHtml解码HTML编码字符
|
|
|
|
|
decodedContent = Html.fromHtml(content).toString();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error decoding HTML content: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 第二步:处理[IMAGE]标签,将其转换为ImageSpan
|
|
|
|
|
SpannableString spannable = convertTextToSpannableWithImages(decodedContent);
|
|
|
|
|
|
|
|
|
|
// 第三步:设置文本,确保文字和图片都能正常显示
|
|
|
|
|
mNoteEditor.setText(spannable);
|
|
|
|
|
// 将光标定位到文本末尾
|
|
|
|
|
mNoteEditor.setSelection(spannable.length());
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 用RichEditor加载HTML内容
|
|
|
|
|
@ -443,6 +492,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
return new SpannableString("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Converting text to Spannable with images: " + text);
|
|
|
|
|
|
|
|
|
|
// 创建一个新的SpannableStringBuilder
|
|
|
|
|
SpannableStringBuilder builder = new SpannableStringBuilder();
|
|
|
|
|
|
|
|
|
|
@ -451,6 +502,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
int imageStart = text.indexOf("[IMAGE]", startIndex);
|
|
|
|
|
|
|
|
|
|
while (imageStart != -1) {
|
|
|
|
|
Log.d(TAG, "Found [IMAGE] tag at position: " + imageStart);
|
|
|
|
|
|
|
|
|
|
// 添加[IMAGE]标签之前的文本
|
|
|
|
|
builder.append(text.substring(startIndex, imageStart));
|
|
|
|
|
|
|
|
|
|
@ -462,43 +515,97 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Found [/IMAGE] tag at position: " + imageEnd);
|
|
|
|
|
|
|
|
|
|
// 提取图片URI
|
|
|
|
|
String imageUri = text.substring(imageStart + "[IMAGE]".length(), imageEnd);
|
|
|
|
|
Log.d(TAG, "Found image URI: " + imageUri);
|
|
|
|
|
Log.d(TAG, "Extracted image URI: " + imageUri);
|
|
|
|
|
|
|
|
|
|
// 创建一个占位符字符串,用于插入ImageSpan
|
|
|
|
|
String placeholder = " ";
|
|
|
|
|
int placeholderStart = builder.length();
|
|
|
|
|
builder.append(placeholder);
|
|
|
|
|
// 保留原始的[IMAGE]uri[/IMAGE]标签,直接在上面添加ImageSpan
|
|
|
|
|
String fullImageTag = "[IMAGE]" + imageUri + "[/IMAGE]";
|
|
|
|
|
int tagStart = builder.length();
|
|
|
|
|
builder.append(fullImageTag);
|
|
|
|
|
|
|
|
|
|
// 尝试将图片URI转换为Drawable并创建ImageSpan
|
|
|
|
|
try {
|
|
|
|
|
// 确保URI是有效的
|
|
|
|
|
Uri uri = Uri.parse(imageUri);
|
|
|
|
|
if (uri == null) {
|
|
|
|
|
Log.e(TAG, "Invalid URI: " + imageUri);
|
|
|
|
|
// 更新索引,继续处理下一个标签
|
|
|
|
|
startIndex = imageEnd + "[/IMAGE]".length();
|
|
|
|
|
imageStart = text.indexOf("[IMAGE]", startIndex);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Attempting to load image from URI: " + uri.toString());
|
|
|
|
|
|
|
|
|
|
// 使用BitmapFactory直接加载图片,这是最可靠的方式
|
|
|
|
|
ContentResolver resolver = getContentResolver();
|
|
|
|
|
InputStream inputStream = resolver.openInputStream(Uri.parse(imageUri));
|
|
|
|
|
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
|
|
|
|
|
inputStream.close();
|
|
|
|
|
|
|
|
|
|
// 计算图片的合适大小,确保它能适应EditText的宽度
|
|
|
|
|
int screenWidth = getResources().getDisplayMetrics().widthPixels;
|
|
|
|
|
int imageWidth = bitmap.getWidth();
|
|
|
|
|
int imageHeight = bitmap.getHeight();
|
|
|
|
|
float scale = (float) screenWidth / (float) imageWidth;
|
|
|
|
|
int scaledHeight = (int) (imageHeight * scale);
|
|
|
|
|
|
|
|
|
|
// 缩放图片
|
|
|
|
|
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, screenWidth, scaledHeight, true);
|
|
|
|
|
Drawable drawable = new android.graphics.drawable.BitmapDrawable(getResources(), scaledBitmap);
|
|
|
|
|
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
|
|
|
|
|
|
|
|
|
|
// 创建ImageSpan并添加到SpannableStringBuilder中
|
|
|
|
|
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
|
|
|
|
|
builder.setSpan(imageSpan, placeholderStart, placeholderStart + placeholder.length(), SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
|
|
|
InputStream inputStream = null;
|
|
|
|
|
try {
|
|
|
|
|
inputStream = resolver.openInputStream(uri);
|
|
|
|
|
if (inputStream == null) {
|
|
|
|
|
Log.e(TAG, "Failed to open input stream for URI: " + uri.toString());
|
|
|
|
|
// 更新索引,继续处理下一个标签
|
|
|
|
|
startIndex = imageEnd + "[/IMAGE]".length();
|
|
|
|
|
imageStart = text.indexOf("[IMAGE]", startIndex);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解码图片
|
|
|
|
|
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
|
|
|
|
|
if (bitmap == null) {
|
|
|
|
|
Log.e(TAG, "Failed to decode bitmap from URI: " + uri.toString());
|
|
|
|
|
// 更新索引,继续处理下一个标签
|
|
|
|
|
startIndex = imageEnd + "[/IMAGE]".length();
|
|
|
|
|
imageStart = text.indexOf("[IMAGE]", startIndex);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Successfully decoded bitmap with dimensions: " + bitmap.getWidth() + "x" + bitmap.getHeight());
|
|
|
|
|
|
|
|
|
|
// 计算图片的合适大小,确保它能适应EditText的宽度
|
|
|
|
|
int screenWidth = getResources().getDisplayMetrics().widthPixels;
|
|
|
|
|
// 减去左右边距,确保图片能完整显示
|
|
|
|
|
int maxWidth = screenWidth - 40;
|
|
|
|
|
int imageWidth = bitmap.getWidth();
|
|
|
|
|
int imageHeight = bitmap.getHeight();
|
|
|
|
|
|
|
|
|
|
// 计算缩放比例
|
|
|
|
|
float scale = 1.0f;
|
|
|
|
|
if (imageWidth > maxWidth) {
|
|
|
|
|
scale = (float) maxWidth / (float) imageWidth;
|
|
|
|
|
}
|
|
|
|
|
Log.d(TAG, "Calculated scale: " + scale);
|
|
|
|
|
|
|
|
|
|
// 缩放图片(如果需要)
|
|
|
|
|
if (scale < 1.0f) {
|
|
|
|
|
bitmap = Bitmap.createScaledBitmap(bitmap, (int)(imageWidth * scale), (int)(imageHeight * scale), true);
|
|
|
|
|
Log.d(TAG, "Scaled bitmap to: " + bitmap.getWidth() + "x" + bitmap.getHeight());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建Drawable并设置边界
|
|
|
|
|
Drawable drawable = new android.graphics.drawable.BitmapDrawable(getResources(), bitmap);
|
|
|
|
|
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
|
|
|
|
|
|
|
|
|
|
// 创建ImageSpan并添加到SpannableStringBuilder中
|
|
|
|
|
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
|
|
|
|
|
builder.setSpan(imageSpan, tagStart, tagStart + fullImageTag.length(), SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
|
|
|
Log.d(TAG, "Successfully added ImageSpan for URI: " + imageUri);
|
|
|
|
|
} finally {
|
|
|
|
|
// 确保InputStream被正确关闭
|
|
|
|
|
if (inputStream != null) {
|
|
|
|
|
try {
|
|
|
|
|
inputStream.close();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error closing input stream: " + e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error loading image: " + e.toString());
|
|
|
|
|
// 如果加载图片失败,直接显示图片URI
|
|
|
|
|
builder.append("[IMAGE]");
|
|
|
|
|
builder.append(imageUri);
|
|
|
|
|
builder.append("[/IMAGE]");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新索引,继续查找下一个[IMAGE]标签
|
|
|
|
|
@ -509,6 +616,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
// 添加剩余的文本
|
|
|
|
|
builder.append(text.substring(startIndex));
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Final SpannableStringBuilder content: " + builder.toString());
|
|
|
|
|
return new SpannableString(builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -679,9 +787,28 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
if (mBtnInsertImage != null) {
|
|
|
|
|
mBtnInsertImage.setOnClickListener(this);
|
|
|
|
|
}
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
|
|
|
|
|
// 初始化富文本功能按钮
|
|
|
|
|
initRichEditorButtons();
|
|
|
|
|
=======
|
|
|
|
|
|
|
|
|
|
// 初始化富文本工具栏按钮
|
|
|
|
|
mBtnBold = (ImageButton) findViewById(R.id.btn_bold);
|
|
|
|
|
mBtnItalic = (ImageButton) findViewById(R.id.btn_italic);
|
|
|
|
|
mBtnUnderline = (ImageButton) findViewById(R.id.btn_underline);
|
|
|
|
|
|
|
|
|
|
// 为富文本工具栏按钮设置点击监听器
|
|
|
|
|
if (mBtnBold != null) {
|
|
|
|
|
mBtnBold.setOnClickListener(this);
|
|
|
|
|
}
|
|
|
|
|
if (mBtnItalic != null) {
|
|
|
|
|
mBtnItalic.setOnClickListener(this);
|
|
|
|
|
}
|
|
|
|
|
if (mBtnUnderline != null) {
|
|
|
|
|
mBtnUnderline.setOnClickListener(this);
|
|
|
|
|
}
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -1268,10 +1395,17 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
}
|
|
|
|
|
mWorkingNote.setWorkingText(sb.toString());
|
|
|
|
|
} else {
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
// 确保获取最新的富文本内容
|
|
|
|
|
String currentHtml = mNoteEditor.getHtml();
|
|
|
|
|
mWorkingNote.setWorkingText(currentHtml);
|
|
|
|
|
mText = currentHtml; // 更新mText变量,确保保存时使用最新内容
|
|
|
|
|
=======
|
|
|
|
|
// 对于普通模式,直接保存EditText中的原始文本
|
|
|
|
|
// 这样可以保留[IMAGE]标签,确保图片信息不会丢失
|
|
|
|
|
String content = mNoteEditor.getText().toString();
|
|
|
|
|
mWorkingNote.setWorkingText(content);
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
}
|
|
|
|
|
return hasChecked;
|
|
|
|
|
}
|
|
|
|
|
@ -1368,7 +1502,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
/**
|
|
|
|
|
* 从相册选择图片 OMO
|
|
|
|
|
*/
|
|
|
|
|
private static final int REQUEST_CODE_PERMISSION_STORAGE = 101;
|
|
|
|
|
|
|
|
|
|
private void pickImageFromGallery() {
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
try {
|
|
|
|
|
// 意图:打开系统相册选择图片
|
|
|
|
|
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
|
|
|
|
@ -1383,6 +1520,36 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
} catch (ActivityNotFoundException ex) {
|
|
|
|
|
showToast(R.string.error_note_not_exist);
|
|
|
|
|
Log.e(TAG, "No image picker available", ex);
|
|
|
|
|
=======
|
|
|
|
|
// 检查并申请存储权限
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
|
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
|
|
|
// 申请权限
|
|
|
|
|
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE_PERMISSION_STORAGE);
|
|
|
|
|
} else {
|
|
|
|
|
// 权限已授予,直接选择图片
|
|
|
|
|
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
|
|
|
|
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Android 6.0以下版本,直接选择图片
|
|
|
|
|
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
|
|
|
|
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理权限请求结果
|
|
|
|
|
@Override
|
|
|
|
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
|
|
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
|
|
|
if (requestCode == REQUEST_CODE_PERMISSION_STORAGE) {
|
|
|
|
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
|
|
|
// 权限被授予,执行图片选择
|
|
|
|
|
pickImageFromGallery();
|
|
|
|
|
} else {
|
|
|
|
|
// 权限被拒绝,显示提示
|
|
|
|
|
showToast(R.string.error_permission_denied);
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1393,6 +1560,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
@Override
|
|
|
|
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
if (requestCode == PHOTO_REQUEST && resultCode == RESULT_OK && data != null) {
|
|
|
|
|
Uri uri = data.getData();
|
|
|
|
|
String localImagePath = saveImageToLocal(uri);
|
|
|
|
|
@ -1438,6 +1606,60 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
builder.show();
|
|
|
|
|
=======
|
|
|
|
|
if (requestCode == REQUEST_CODE_PICK_IMAGE && resultCode == RESULT_OK && data != null) {
|
|
|
|
|
Log.d(TAG, "Image selected successfully, data: " + data.toString());
|
|
|
|
|
Uri imageUri = data.getData();
|
|
|
|
|
if (imageUri != null) {
|
|
|
|
|
Log.d(TAG, "Image URI: " + imageUri.toString());
|
|
|
|
|
|
|
|
|
|
// 获取当前编辑器内容
|
|
|
|
|
Editable editable = mNoteEditor.getText();
|
|
|
|
|
int currentPosition = mNoteEditor.getSelectionStart();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 1. 保存当前编辑器的原始内容,用于后续恢复
|
|
|
|
|
String originalContent = editable.toString();
|
|
|
|
|
int originalSelection = mNoteEditor.getSelectionStart();
|
|
|
|
|
|
|
|
|
|
// 2. 插入完整的[IMAGE]uri[/IMAGE]标签到原始内容中
|
|
|
|
|
String imagePath = "[IMAGE]" + imageUri.toString() + "[/IMAGE]";
|
|
|
|
|
StringBuilder sb = new StringBuilder(originalContent);
|
|
|
|
|
sb.insert(originalSelection, imagePath);
|
|
|
|
|
String newContentWithTags = sb.toString();
|
|
|
|
|
|
|
|
|
|
// 3. 首先将包含ImageSpan的SpannableString显示到编辑器中
|
|
|
|
|
SpannableString spannable = convertTextToSpannableWithImages(newContentWithTags);
|
|
|
|
|
mNoteEditor.setText(spannable);
|
|
|
|
|
|
|
|
|
|
// 4. 然后将原始的[IMAGE]标签内容设置到WorkingNote中
|
|
|
|
|
mWorkingNote.setWorkingText(newContentWithTags);
|
|
|
|
|
|
|
|
|
|
// 5. 保存笔记(注意:这里不再调用getWorkingText(),而是直接保存WorkingNote中的内容)
|
|
|
|
|
// 我们需要修改saveNote()方法,或者直接调用mWorkingNote.saveNote()
|
|
|
|
|
if (mWorkingNote.saveNote()) {
|
|
|
|
|
showToast(R.string.info_image_inserted);
|
|
|
|
|
} else {
|
|
|
|
|
showToast(R.string.error_image_insert_failed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6. 将光标移动到图片后面
|
|
|
|
|
int newPosition = originalSelection + imagePath.length();
|
|
|
|
|
mNoteEditor.setSelection(newPosition);
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error inserting image: " + e.toString());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
// 如果插入图片失败,显示错误信息
|
|
|
|
|
showToast(R.string.error_image_insert_failed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Image URI is null");
|
|
|
|
|
showToast(R.string.error_image_insert_failed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Log.d(TAG, "Image selection canceled or failed, resultCode: " + resultCode);
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1470,6 +1692,147 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
Toast.makeText(this, "图片保存失败", Toast.LENGTH_SHORT).show();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
=======
|
|
|
|
|
|
|
|
|
|
// 检查是否在清单模式,如果是则提示用户切换到普通模式
|
|
|
|
|
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
|
|
|
|
|
showToast(R.string.error_formatting_not_supported_in_list_mode);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Editable editable = mNoteEditor.getText();
|
|
|
|
|
if (editable == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int selectionStart = mNoteEditor.getSelectionStart();
|
|
|
|
|
int selectionEnd = mNoteEditor.getSelectionEnd();
|
|
|
|
|
|
|
|
|
|
// 如果没有选中文本,则选中光标所在的单词或当前字符
|
|
|
|
|
if (selectionStart == selectionEnd) {
|
|
|
|
|
// 尝试选中光标所在的单词
|
|
|
|
|
String text = editable.toString();
|
|
|
|
|
int start = selectionStart;
|
|
|
|
|
int end = selectionEnd;
|
|
|
|
|
|
|
|
|
|
// 向前查找单词开始位置
|
|
|
|
|
while (start > 0 && Character.isLetterOrDigit(text.charAt(start - 1))) {
|
|
|
|
|
start--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 向后查找单词结束位置
|
|
|
|
|
while (end < text.length() && Character.isLetterOrDigit(text.charAt(end))) {
|
|
|
|
|
end++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果找到了单词,则选中它;否则选中当前字符
|
|
|
|
|
if (start < end) {
|
|
|
|
|
selectionStart = start;
|
|
|
|
|
selectionEnd = end;
|
|
|
|
|
mNoteEditor.setSelection(selectionStart, selectionEnd);
|
|
|
|
|
} else {
|
|
|
|
|
// 如果没有找到单词,提示用户先选择文本
|
|
|
|
|
showToast(R.string.error_please_select_text);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确保选择范围有效
|
|
|
|
|
if (selectionStart < 0 || selectionEnd > editable.length() || selectionStart >= selectionEnd) {
|
|
|
|
|
showToast(R.string.error_please_select_text);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 应用样式
|
|
|
|
|
if (styleType == -1) {
|
|
|
|
|
// 下划线样式
|
|
|
|
|
UnderlineSpan[] underlineSpans = editable.getSpans(selectionStart, selectionEnd, UnderlineSpan.class);
|
|
|
|
|
if (underlineSpans.length > 0) {
|
|
|
|
|
// 移除下划线
|
|
|
|
|
for (UnderlineSpan span : underlineSpans) {
|
|
|
|
|
int spanStart = editable.getSpanStart(span);
|
|
|
|
|
int spanEnd = editable.getSpanEnd(span);
|
|
|
|
|
editable.removeSpan(span);
|
|
|
|
|
// 如果移除的span范围大于选中范围,需要重新应用样式到剩余部分
|
|
|
|
|
if (spanStart < selectionStart) {
|
|
|
|
|
editable.setSpan(new UnderlineSpan(), spanStart, selectionStart, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
if (spanEnd > selectionEnd) {
|
|
|
|
|
editable.setSpan(new UnderlineSpan(), selectionEnd, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 添加下划线
|
|
|
|
|
editable.setSpan(new UnderlineSpan(), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 加粗或斜体样式
|
|
|
|
|
StyleSpan[] styleSpans = editable.getSpans(selectionStart, selectionEnd, StyleSpan.class);
|
|
|
|
|
|
|
|
|
|
// 检查选中范围内是否已经有该样式
|
|
|
|
|
boolean hasStyle = false;
|
|
|
|
|
int existingStyle = 0;
|
|
|
|
|
|
|
|
|
|
// 收集选中范围内的所有样式
|
|
|
|
|
for (StyleSpan span : styleSpans) {
|
|
|
|
|
int spanStart = editable.getSpanStart(span);
|
|
|
|
|
int spanEnd = editable.getSpanEnd(span);
|
|
|
|
|
|
|
|
|
|
// 如果span与选中范围重叠
|
|
|
|
|
if (spanStart < selectionEnd && spanEnd > selectionStart) {
|
|
|
|
|
int spanStyle = span.getStyle();
|
|
|
|
|
existingStyle |= spanStyle;
|
|
|
|
|
|
|
|
|
|
// 检查是否包含目标样式
|
|
|
|
|
if ((spanStyle & styleType) == styleType) {
|
|
|
|
|
hasStyle = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 移除选中范围内的所有StyleSpan,以便重新应用
|
|
|
|
|
for (int i = styleSpans.length - 1; i >= 0; i--) {
|
|
|
|
|
StyleSpan span = styleSpans[i];
|
|
|
|
|
int spanStart = editable.getSpanStart(span);
|
|
|
|
|
int spanEnd = editable.getSpanEnd(span);
|
|
|
|
|
|
|
|
|
|
// 如果span与选中范围重叠
|
|
|
|
|
if (spanStart < selectionEnd && spanEnd > selectionStart) {
|
|
|
|
|
editable.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
// 处理span范围大于选中范围的情况,保留未选中部分的样式
|
|
|
|
|
int spanStyle = span.getStyle();
|
|
|
|
|
if (spanStart < selectionStart) {
|
|
|
|
|
// 保留选中范围之前的样式
|
|
|
|
|
editable.setSpan(new StyleSpan(spanStyle), spanStart, selectionStart, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
if (spanEnd > selectionEnd) {
|
|
|
|
|
// 保留选中范围之后的样式
|
|
|
|
|
editable.setSpan(new StyleSpan(spanStyle), selectionEnd, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 切换样式:如果有则移除,如果没有则添加
|
|
|
|
|
int finalStyle = existingStyle;
|
|
|
|
|
if (hasStyle) {
|
|
|
|
|
// 移除目标样式
|
|
|
|
|
finalStyle &= ~styleType;
|
|
|
|
|
} else {
|
|
|
|
|
// 添加目标样式
|
|
|
|
|
finalStyle |= styleType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 应用最终样式
|
|
|
|
|
if (finalStyle != 0) {
|
|
|
|
|
editable.setSpan(new StyleSpan(finalStyle), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保持选中状态
|
|
|
|
|
mNoteEditor.setSelection(selectionStart, selectionEnd);
|
|
|
|
|
>>>>>>> master
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 自定义方法:给RichEditor设置字体大小(对应原EditText的setTextAppearance)
|
|
|
|
|
|