diff --git a/src/Notes-master/Notes-master.rar b/src/Notes-master/Notes-master.rar
deleted file mode 100644
index c3186b6..0000000
Binary files a/src/Notes-master/Notes-master.rar and /dev/null differ
diff --git a/src/Notes-master/res/layout/note_edit.xml b/src/Notes-master/res/layout/note_edit.xml
index abde9ae..abec1dc 100644
--- a/src/Notes-master/res/layout/note_edit.xml
+++ b/src/Notes-master/res/layout/note_edit.xml
@@ -67,20 +67,11 @@
android:layout_marginRight="8dip" />
-
-
-
+
+
+
+
+
+
+
+
+
要查看的便签不存在
不能为空便签设置闹钟提醒
不能将空便签发送到桌面
+ 清单模式下不支持格式化
+ 请先选择文本
导出成功
导出失败
已将文本文件(%1$s)输出至SD卡(%2$s)目录
@@ -137,6 +139,14 @@
请输入密码
密码错误,请重试
密码不能为空
+
+ 加粗
+ 斜体
+ 下划线
+ 符号列表
+ 编号列表
+ 文字颜色
+ 背景颜色
- %1$s 条符合“%2$s”的搜索结果
diff --git a/src/Notes-master/res/values/strings.xml b/src/Notes-master/res/values/strings.xml
index 170e4f0..9889716 100644
--- a/src/Notes-master/res/values/strings.xml
+++ b/src/Notes-master/res/values/strings.xml
@@ -88,6 +88,8 @@
The note is not exist
Sorry, can not set clock on empty note
Sorry, can not send and empty note to home
+ Formatting is not supported in list mode
+ Please select text first
Export successful
Export fail
Export text file (%1$s) to SD (%2$s) directory
@@ -144,6 +146,14 @@
Enter password please
Error, try again
The password can not be empty
+
+ Bold
+ Italic
+ Underline
+ Bullet list
+ Numbered list
+ Text color
+ Background color
- %1$s result for \"%2$s\"
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 4d39639..944d043 100644
--- a/src/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java
+++ b/src/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java
@@ -33,8 +33,12 @@ import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
+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.graphics.Typeface;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -168,6 +172,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private SharedPreferences mSharedPrefs; // 共享偏好设置
private int mFontSizeId; // 字体大小ID
private ImageButton mBtnInsertImage; // 插入图片按钮 OMO
+
+ // 富文本工具栏按钮
+ private ImageButton mBtnBold; // 加粗按钮
+ private ImageButton mBtnItalic; // 斜体按钮
+ private ImageButton mBtnUnderline; // 下划线按钮
private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; // 字体大小偏好设置键
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; // 快捷图标标题最大长度
@@ -351,11 +360,84 @@ public class NoteEditActivity extends Activity implements OnClickListener,
String content = mWorkingNote.getContent();
Log.d(TAG, "Initializing note content: " + content);
- // 将文本内容转换为包含ImageSpan的SpannableString
- SpannableString spannableString = convertTextToSpannableWithImages(content);
- mNoteEditor.setText(spannableString);
- // 将光标定位到文本末尾
- mNoteEditor.setSelection(spannableString.length());
+ if (TextUtils.isEmpty(content)) {
+ mNoteEditor.setText("");
+ mNoteEditor.setSelection(0);
+ } else {
+ Spannable spannable;
+
+ // 检查是否是HTML格式(包含HTML标签)
+ if (content.contains("<") && content.contains(">")) {
+ try {
+ // 从HTML格式恢复SpannableString,保留样式(加粗、斜体、下划线)
+ // Html.fromHtml会自动将HTML标签转换为对应的Span
+ spannable = (Spannable) Html.fromHtml(content);
+ } catch (Exception e) {
+ // 如果HTML解析失败,使用普通文本
+ Log.e(TAG, "Error parsing HTML content: " + e.getMessage());
+ spannable = new SpannableString(content);
+ }
+ } else {
+ // 普通文本格式,直接创建SpannableString
+ spannable = new SpannableString(content);
+ }
+
+ // 处理图片:将包含[IMAGE]标签的文本转换为包含ImageSpan的SpannableString
+ // 注意:convertTextToSpannableWithImages会处理[IMAGE]标记,但会保留文本内容
+ String textContent = spannable.toString();
+ SpannableString finalSpannable = convertTextToSpannableWithImages(textContent);
+
+ // 将样式从原始Spannable复制到处理后的SpannableString
+ // 由于convertTextToSpannableWithImages可能改变了文本长度(用空格替换了[IMAGE]标签),
+ // 我们需要基于文本内容来映射样式位置
+ if (textContent.length() == finalSpannable.length()) {
+ // 文本长度相同,直接复制样式
+ StyleSpan[] styleSpans = spannable.getSpans(0, spannable.length(), StyleSpan.class);
+ UnderlineSpan[] underlineSpans = spannable.getSpans(0, spannable.length(), UnderlineSpan.class);
+
+ for (StyleSpan span : styleSpans) {
+ int start = spannable.getSpanStart(span);
+ int end = spannable.getSpanEnd(span);
+ if (start >= 0 && end <= finalSpannable.length() && start < end) {
+ finalSpannable.setSpan(new StyleSpan(span.getStyle()), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ for (UnderlineSpan span : underlineSpans) {
+ int start = spannable.getSpanStart(span);
+ int end = spannable.getSpanEnd(span);
+ if (start >= 0 && end <= finalSpannable.length() && start < end) {
+ finalSpannable.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+ } else {
+ // 文本长度不同,说明有图片被处理了
+ // 这种情况下,样式位置需要重新计算
+ // 为了简化,我们基于原始文本位置映射样式(可能会有偏差,但应该能处理大部分情况)
+ StyleSpan[] styleSpans = spannable.getSpans(0, spannable.length(), StyleSpan.class);
+ UnderlineSpan[] underlineSpans = spannable.getSpans(0, spannable.length(), UnderlineSpan.class);
+
+ for (StyleSpan span : styleSpans) {
+ int start = Math.max(0, Math.min(spannable.getSpanStart(span), finalSpannable.length()));
+ int end = Math.max(start, Math.min(spannable.getSpanEnd(span), finalSpannable.length()));
+ if (start < end) {
+ finalSpannable.setSpan(new StyleSpan(span.getStyle()), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ for (UnderlineSpan span : underlineSpans) {
+ int start = Math.max(0, Math.min(spannable.getSpanStart(span), finalSpannable.length()));
+ int end = Math.max(start, Math.min(spannable.getSpanEnd(span), finalSpannable.length()));
+ if (start < end) {
+ finalSpannable.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+ }
+
+ mNoteEditor.setText(finalSpannable);
+ // 将光标定位到文本末尾
+ mNoteEditor.setSelection(finalSpannable.length());
+ }
}
// 隐藏所有背景选择的选中状态
@@ -597,6 +679,22 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (mBtnInsertImage != null) {
mBtnInsertImage.setOnClickListener(this);
}
+
+ // 初始化富文本工具栏按钮
+ 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);
+ }
}
/**
@@ -674,6 +772,15 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else if (id == R.id.btn_insert_image) {
// 处理插入图片按钮点击事件 OMO
pickImageFromGallery();
+ } else if (id == R.id.btn_bold) {
+ // 富文本工具栏 - 加粗按钮
+ applyBoldStyle();
+ } else if (id == R.id.btn_italic) {
+ // 富文本工具栏 - 斜体按钮
+ applyItalicStyle();
+ } else if (id == R.id.btn_underline) {
+ // 富文本工具栏 - 下划线按钮
+ applyUnderlineStyle();
}
}
@@ -1159,7 +1266,16 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
mWorkingNote.setWorkingText(sb.toString());
} else {
- mWorkingNote.setWorkingText(mNoteEditor.getText().toString());
+ // 保存时,将SpannableString转换为HTML格式以保留样式信息
+ Spannable spannable = mNoteEditor.getText();
+ if (spannable != null && spannable.length() > 0) {
+ // 将Spannable转换为HTML格式,保留加粗、斜体、下划线等样式
+ // Html.toHtml会自动处理StyleSpan和UnderlineSpan
+ String htmlContent = Html.toHtml(spannable);
+ mWorkingNote.setWorkingText(htmlContent);
+ } else {
+ mWorkingNote.setWorkingText("");
+ }
}
return hasChecked;
}
@@ -1298,4 +1414,173 @@ public class NoteEditActivity extends Activity implements OnClickListener,
Log.d(TAG, "Image selection canceled or failed, resultCode: " + resultCode);
}
}
+
+ /**
+ * 应用文本样式(加粗、斜体、下划线)
+ * @param styleType 样式类型:Typeface.BOLD, Typeface.ITALIC, 或 -1 表示下划线
+ */
+ private void applyTextStyle(int styleType) {
+ if (mNoteEditor == null) {
+ return;
+ }
+
+ // 检查是否在清单模式,如果是则提示用户切换到普通模式
+ 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);
+ }
+
+ /**
+ * 应用加粗样式
+ */
+ private void applyBoldStyle() {
+ applyTextStyle(Typeface.BOLD);
+ }
+
+ /**
+ * 应用斜体样式
+ */
+ private void applyItalicStyle() {
+ applyTextStyle(Typeface.ITALIC);
+ }
+
+ /**
+ * 应用下划线样式
+ */
+ private void applyUnderlineStyle() {
+ applyTextStyle(-1); // -1 表示下划线
+ }
}