新增回退功能 #14

Merged
psq5hzxpo merged 1 commits from luhaozhe_branch into master 1 month ago

@ -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();

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#757575"
android:pathData="M8.59,16.59L10,18l6,-6l-6,-6l-1.41,1.41L13.17,12z"/>
</vector>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#757575"
android:pathData="M15.41,7.41L14,6l-6,6l6,6l1.41,-1.41L10.83,12z"/>
</vector>

@ -58,11 +58,31 @@
android:layout_marginRight="8dip"
android:textAppearance="@style/TextAppearanceSecondaryItem" />
<ImageButton
android:id="@+id/btn_undo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:background="@drawable/bg_btn_set_color"
android:padding="12dp"
android:contentDescription="@string/menu_undo"
android:src="@drawable/ic_undo" />
<ImageButton
android:id="@+id/btn_redo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:background="@drawable/bg_btn_set_color"
android:padding="12dp"
android:contentDescription="@string/menu_redo"
android:src="@drawable/ic_redo" />
<ImageButton
android:id="@+id/btn_set_bg_color"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:background="@drawable/bg_btn_set_color"
android:padding="12dp" />
<ImageButton

@ -208,6 +208,8 @@
<string name="menu_italic">Italic</string>
<string name="menu_normal">Normal</string>
<string name="menu_insert_image">Insert Image</string>
<string name="menu_undo">Undo</string>
<string name="menu_redo">Redo</string>
<!-- Image insertion strings -->
<string name="error_insert_image_failed">Failed to insert image</string>

Loading…
Cancel
Save