|
|
|
|
@ -110,6 +110,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
public TextView tvModified; // 修改时间显示
|
|
|
|
|
public ImageView ivAlertIcon; // 提醒图标
|
|
|
|
|
public TextView tvAlertDate; // 提醒日期显示
|
|
|
|
|
public ImageButton ibUndo; // 撤销按钮
|
|
|
|
|
public ImageButton ibRedo; // 重做按钮
|
|
|
|
|
public ImageView ibSetBgColor; // 设置背景色按钮
|
|
|
|
|
public ImageButton ibInsertImage; // 插入图片按钮
|
|
|
|
|
public TextView tvTitleHint; // 标题提示文字
|
|
|
|
|
@ -190,6 +192,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
private LinearLayout mEditTextList; // 编辑列表(用于checklist模式)
|
|
|
|
|
private String mUserQuery; // 用户查询(用于搜索高亮)
|
|
|
|
|
private Pattern mPattern; // 搜索模式(用于搜索高亮)
|
|
|
|
|
|
|
|
|
|
// 撤销/重做相关
|
|
|
|
|
private static final int MAX_HISTORY_SIZE = 50; // 最大历史记录数量
|
|
|
|
|
private java.util.Stack<String> mUndoStack; // 撤销栈
|
|
|
|
|
private java.util.Stack<String> mRedoStack; // 重做栈
|
|
|
|
|
private boolean mIsRestoringFromHistory; // 是否正在从历史记录恢复文本
|
|
|
|
|
private String mLastSavedText; // 最后保存的文本
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 初始化活动 onCreate 方法
|
|
|
|
|
@ -553,6 +562,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date);
|
|
|
|
|
mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon);
|
|
|
|
|
mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date);
|
|
|
|
|
mNoteHeaderHolder.ibUndo = (ImageButton) findViewById(R.id.btn_undo);
|
|
|
|
|
mNoteHeaderHolder.ibUndo.setOnClickListener(this);
|
|
|
|
|
mNoteHeaderHolder.ibRedo = (ImageButton) findViewById(R.id.btn_redo);
|
|
|
|
|
mNoteHeaderHolder.ibRedo.setOnClickListener(this);
|
|
|
|
|
mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color);
|
|
|
|
|
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);
|
|
|
|
|
mNoteHeaderHolder.ibInsertImage = (ImageButton) findViewById(R.id.add_img_btn);
|
|
|
|
|
@ -616,21 +629,50 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
// 初始化编辑列表
|
|
|
|
|
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);
|
|
|
|
|
|
|
|
|
|
// 添加编辑器文本监听器,实现实时字数更新
|
|
|
|
|
// 初始化撤销/重做栈
|
|
|
|
|
mUndoStack = new java.util.Stack<String>();
|
|
|
|
|
mRedoStack = new java.util.Stack<String>();
|
|
|
|
|
mIsRestoringFromHistory = false;
|
|
|
|
|
|
|
|
|
|
// 记录初始文本
|
|
|
|
|
mLastSavedText = mNoteEditor.getText().toString();
|
|
|
|
|
mUndoStack.push(mLastSavedText);
|
|
|
|
|
|
|
|
|
|
// 添加编辑器文本监听器,实现实时字数更新和undo/redo状态监听
|
|
|
|
|
mNoteEditor.addTextChangedListener(new TextWatcher() {
|
|
|
|
|
@Override
|
|
|
|
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
|
|
|
// 只在非历史恢复模式下记录历史
|
|
|
|
|
if (!mIsRestoringFromHistory) {
|
|
|
|
|
String currentText = s.toString();
|
|
|
|
|
// 总是记录历史记录,因为文本即将改变
|
|
|
|
|
mUndoStack.push(currentText);
|
|
|
|
|
// 限制栈大小
|
|
|
|
|
if (mUndoStack.size() > MAX_HISTORY_SIZE) {
|
|
|
|
|
mUndoStack.remove(0);
|
|
|
|
|
}
|
|
|
|
|
// 清空重做栈
|
|
|
|
|
mRedoStack.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
|
|
|
updateWordCount();
|
|
|
|
|
updateUndoRedoButtons();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void afterTextChanged(Editable s) {
|
|
|
|
|
// 只在非历史恢复模式下更新最后保存的文本
|
|
|
|
|
if (!mIsRestoringFromHistory) {
|
|
|
|
|
mLastSavedText = s.toString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 初始更新undo/redo按钮状态
|
|
|
|
|
updateUndoRedoButtons();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -683,7 +725,17 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
*/
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
int id = v.getId();
|
|
|
|
|
if (id == R.id.btn_set_bg_color) {
|
|
|
|
|
if (id == R.id.btn_undo) {
|
|
|
|
|
// 执行撤销操作
|
|
|
|
|
if (canUndo()) {
|
|
|
|
|
undo();
|
|
|
|
|
}
|
|
|
|
|
} else if (id == R.id.btn_redo) {
|
|
|
|
|
// 执行重做操作
|
|
|
|
|
if (canRedo()) {
|
|
|
|
|
redo();
|
|
|
|
|
}
|
|
|
|
|
} else if (id == R.id.btn_set_bg_color) {
|
|
|
|
|
mNoteBgColorSelector.setVisibility(View.VISIBLE);
|
|
|
|
|
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
|
|
|
|
|
- View.VISIBLE);
|
|
|
|
|
@ -1223,7 +1275,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
content = mNoteEditor.getText().toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int wordCount = content != null ? content.length() : 0;
|
|
|
|
|
// 过滤掉所有 [IMAGE:图片路径] 格式的图片标记,只统计纯文本字符数
|
|
|
|
|
int wordCount = calculateTextLength(content);
|
|
|
|
|
mNoteHeaderHolder.tvWordCount.setText(String.valueOf(wordCount));
|
|
|
|
|
|
|
|
|
|
if (wordCount > 5000) {
|
|
|
|
|
@ -1235,6 +1288,125 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 计算文本长度,排除所有 [IMAGE:图片路径] 格式的图片标记
|
|
|
|
|
* @param text 包含图片标记的文本
|
|
|
|
|
* @return 纯文本字符数
|
|
|
|
|
*/
|
|
|
|
|
private int calculateTextLength(String text) {
|
|
|
|
|
if (TextUtils.isEmpty(text)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int length = 0;
|
|
|
|
|
int startIndex = 0;
|
|
|
|
|
int imageStart = text.indexOf("[IMAGE:", startIndex);
|
|
|
|
|
|
|
|
|
|
while (imageStart != -1) {
|
|
|
|
|
// 统计图片标记前的文本长度
|
|
|
|
|
length += imageStart - startIndex;
|
|
|
|
|
|
|
|
|
|
// 查找图片标记的结束位置
|
|
|
|
|
int imageEnd = text.indexOf("]", imageStart);
|
|
|
|
|
if (imageEnd == -1) {
|
|
|
|
|
// 如果没有找到结束标记,说明格式不正确,统计剩余所有文本
|
|
|
|
|
length += text.length() - imageStart;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新起始位置到图片标记结束后
|
|
|
|
|
startIndex = imageEnd + 1;
|
|
|
|
|
|
|
|
|
|
// 查找下一个图片标记
|
|
|
|
|
imageStart = text.indexOf("[IMAGE:", startIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 统计最后一个图片标记后的文本长度
|
|
|
|
|
length += text.length() - startIndex;
|
|
|
|
|
|
|
|
|
|
return length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 更新撤销和重做按钮的状态
|
|
|
|
|
*/
|
|
|
|
|
private void updateUndoRedoButtons() {
|
|
|
|
|
if (mNoteHeaderHolder != null) {
|
|
|
|
|
boolean canUndo = canUndo();
|
|
|
|
|
boolean canRedo = canRedo();
|
|
|
|
|
|
|
|
|
|
mNoteHeaderHolder.ibUndo.setEnabled(canUndo);
|
|
|
|
|
mNoteHeaderHolder.ibRedo.setEnabled(canRedo);
|
|
|
|
|
|
|
|
|
|
// 设置按钮透明度,禁用时半透明
|
|
|
|
|
mNoteHeaderHolder.ibUndo.setAlpha(canUndo ? 1.0f : 0.5f);
|
|
|
|
|
mNoteHeaderHolder.ibRedo.setAlpha(canRedo ? 1.0f : 0.5f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查是否可以撤销
|
|
|
|
|
* @return 是否可以撤销
|
|
|
|
|
*/
|
|
|
|
|
private boolean canUndo() {
|
|
|
|
|
return mUndoStack.size() > 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查是否可以重做
|
|
|
|
|
* @return 是否可以重做
|
|
|
|
|
*/
|
|
|
|
|
private boolean canRedo() {
|
|
|
|
|
return !mRedoStack.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 执行撤销操作
|
|
|
|
|
*/
|
|
|
|
|
private void undo() {
|
|
|
|
|
if (canUndo()) {
|
|
|
|
|
// 将当前文本加入重做栈
|
|
|
|
|
mRedoStack.push(mNoteEditor.getText().toString());
|
|
|
|
|
|
|
|
|
|
// 弹出上一个文本
|
|
|
|
|
mUndoStack.pop();
|
|
|
|
|
|
|
|
|
|
// 恢复上一个文本
|
|
|
|
|
String previousText = mUndoStack.peek();
|
|
|
|
|
mIsRestoringFromHistory = true;
|
|
|
|
|
mNoteEditor.setText(previousText);
|
|
|
|
|
mNoteEditor.setSelection(previousText.length());
|
|
|
|
|
mLastSavedText = previousText;
|
|
|
|
|
mIsRestoringFromHistory = false;
|
|
|
|
|
|
|
|
|
|
// 更新按钮状态
|
|
|
|
|
updateUndoRedoButtons();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 执行重做操作
|
|
|
|
|
*/
|
|
|
|
|
private void redo() {
|
|
|
|
|
if (canRedo()) {
|
|
|
|
|
// 将当前文本加入撤销栈
|
|
|
|
|
mUndoStack.push(mNoteEditor.getText().toString());
|
|
|
|
|
|
|
|
|
|
// 弹出下一个文本
|
|
|
|
|
String nextText = mRedoStack.pop();
|
|
|
|
|
|
|
|
|
|
// 恢复下一个文本
|
|
|
|
|
mIsRestoringFromHistory = true;
|
|
|
|
|
mNoteEditor.setText(nextText);
|
|
|
|
|
mNoteEditor.setSelection(nextText.length());
|
|
|
|
|
mLastSavedText = nextText;
|
|
|
|
|
mIsRestoringFromHistory = false;
|
|
|
|
|
|
|
|
|
|
// 更新按钮状态
|
|
|
|
|
updateUndoRedoButtons();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean saveNote() {
|
|
|
|
|
getWorkingText();
|
|
|
|
|
String title = mNoteHeaderHolder.etTitle.getText().toString();
|
|
|
|
|
|