diff --git a/src/Notes-master/mainfests/AndroidManifest.xml b/src/Notes-master/mainfests/AndroidManifest.xml index a85867b..e099d24 100644 --- a/src/Notes-master/mainfests/AndroidManifest.xml +++ b/src/Notes-master/mainfests/AndroidManifest.xml @@ -17,6 +17,7 @@ + diff --git a/src/Notes-master/res/layout/note_edit.xml b/src/Notes-master/res/layout/note_edit.xml index 503fcb1..c686d32 100644 --- a/src/Notes-master/res/layout/note_edit.xml +++ b/src/Notes-master/res/layout/note_edit.xml @@ -56,16 +56,8 @@ android:layout_marginRight="8dip" android:textAppearance="@style/TextAppearanceSecondaryItem" /> - - +<<<<<<< HEAD +======= +>>>>>>> master +<<<<<<< HEAD +======= +>>>>>>> master + + + + + + + + + + + + + @@ -273,9 +323,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" + android:layout_marginRight="2dip" android:focusable="false" android:visibility="gone" - android:layout_marginRight="2dip" android:src="@drawable/selected" /> diff --git a/src/Notes-master/res/values-zh-rCN/strings.xml b/src/Notes-master/res/values-zh-rCN/strings.xml index 96599ab..67568ca 100644 --- a/src/Notes-master/res/values-zh-rCN/strings.xml +++ b/src/Notes-master/res/values-zh-rCN/strings.xml @@ -84,6 +84,13 @@ 要查看的便签不存在 不能为空便签设置闹钟提醒 不能将空便签发送到桌面 +<<<<<<< HEAD +======= + 清单模式下不支持格式化 + 拒绝许可,无法访问图像 + 插入失败,请再尝试一次 + 请先选择文本 +>>>>>>> master 导出成功 导出失败 已将文本文件(%1$s)输出至SD卡(%2$s)目录 diff --git a/src/Notes-master/res/values/strings.xml b/src/Notes-master/res/values/strings.xml index 170e4f0..bc9eb9a 100644 --- a/src/Notes-master/res/values/strings.xml +++ b/src/Notes-master/res/values/strings.xml @@ -88,6 +88,13 @@ The note is not exist Sorry, can not set clock on empty note Sorry, can not send and empty note to home +<<<<<<< HEAD +======= + Formatting is not supported in list mode + Please select text first + Permission denied, cannot access images + Failed to insert image, please try again +>>>>>>> master Export successful Export fail Export text file (%1$s) to SD (%2$s) directory diff --git a/src/Notes-master/src/net/micode/notes/tool/DataUtils.java b/src/Notes-master/src/net/micode/notes/tool/DataUtils.java index 717c14a..63b1790 100644 --- a/src/Notes-master/src/net/micode/notes/tool/DataUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/DataUtils.java @@ -81,11 +81,11 @@ public class DataUtils { // Query the note from note table cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), null, null, null, null); - + if (cursor != null && cursor.moveToFirst()) { // Read all columns from the note ContentValues trashValues = new ContentValues(); - + // Copy all columns from note to trash for (String column : cursor.getColumnNames()) { int columnIndex = cursor.getColumnIndex(column); @@ -109,12 +109,13 @@ public class DataUtils { } } } - + // Set deleted_date to current time trashValues.put("deleted_date", System.currentTimeMillis()); - + // Insert into trash table resolver.insert(Notes.CONTENT_TRASH_URI, trashValues); +<<<<<<< HEAD // 在删除note之前,先备份DATA表的数据 if (db != null) { @@ -161,9 +162,13 @@ public class DataUtils { } // Delete from note table (this will trigger deletion of DATA table via trigger) +======= + + // Delete from note table +>>>>>>> master resolver.delete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), null, null); } - + if (cursor != null) { cursor.close(); cursor = null; @@ -202,7 +207,7 @@ public class DataUtils { } public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, - long folderId) { + long folderId) { if (ids == null) { Log.d(TAG, "the ids is null"); return true; @@ -305,8 +310,8 @@ public class DataUtils { public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + - " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + - " AND " + NoteColumns.SNIPPET + "=?", + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.SNIPPET + "=?", new String[] { name }, null); boolean exist = false; if(cursor != null) { @@ -391,12 +396,16 @@ public class DataUtils { // Query the note from trash table cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_TRASH_URI, trashId), null, null, null, null); - + if (cursor != null && cursor.moveToFirst()) { // Read all columns from the trash note ContentValues noteValues = new ContentValues(); +<<<<<<< HEAD long originalNoteId = -1; +======= + +>>>>>>> master // Copy all columns from trash to note (except deleted_date) for (String column : cursor.getColumnNames()) { if ("deleted_date".equals(column)) { @@ -428,8 +437,9 @@ public class DataUtils { } } } - + // Insert back to note table +<<<<<<< HEAD Uri restoredUri = resolver.insert(Notes.CONTENT_NOTE_URI, noteValues); if (restoredUri == null) { Log.e(TAG, "Failed to restore note to note table"); @@ -498,9 +508,13 @@ public class DataUtils { } } +======= + resolver.insert(Notes.CONTENT_NOTE_URI, noteValues); + +>>>>>>> master // Delete from trash table resolver.delete(ContentUris.withAppendedId(Notes.CONTENT_TRASH_URI, trashId), null, null); - + return true; } return false; @@ -582,7 +596,7 @@ public class DataUtils { Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.NOTE_ID }, CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" - + CallNote.PHONE_NUMBER + ",?)", + + CallNote.PHONE_NUMBER + ",?)", new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, null); @@ -620,6 +634,8 @@ public class DataUtils { public static String getFormattedSnippet(String snippet) { if (snippet != null) { snippet = snippet.trim(); + // 替换[IMAGE]标签为友好的占位符 + snippet = snippet.replaceAll("\\[IMAGE\\].*?\\[/IMAGE\\]", "[图片]"); int index = snippet.indexOf('\n'); if (index != -1) { snippet = snippet.substring(0, index); diff --git a/src/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java b/src/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java index 7cfd52d..6115f83 100644 --- a/src/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java +++ b/src/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java @@ -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)