|
|
|
|
@ -234,14 +234,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
private EditText mTagInput; // 标签输入框
|
|
|
|
|
private Button mAddTagButton; // 添加标签按钮
|
|
|
|
|
private ArrayList<String> mTagsList; // 标签列表
|
|
|
|
|
|
|
|
|
|
// 视图缓存,减少对象创建
|
|
|
|
|
private ArrayList<View> mViewCache = new ArrayList<>();
|
|
|
|
|
private static final int MAX_CACHE_SIZE = 10; // 最大缓存大小
|
|
|
|
|
|
|
|
|
|
// 延迟保存相关
|
|
|
|
|
private android.os.Handler mSaveNoteHandler = new android.os.Handler();
|
|
|
|
|
private TextView mSaveHint; // 保存成功提示视图
|
|
|
|
|
|
|
|
|
|
// 搜索历史相关
|
|
|
|
|
private static final String PREFERENCE_SEARCH_HISTORY = "search_history"; // 搜索历史偏好设置键
|
|
|
|
|
@ -1345,114 +1337,58 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
|
Log.d(TAG, "switchToListMode started, text length: " + (text != null ? text.length() : 0));
|
|
|
|
|
|
|
|
|
|
// 处理null文本,避免空指针异常
|
|
|
|
|
// 处理null文本,避免空指针异常(OMO)
|
|
|
|
|
final String processedText = text != null ? text : "";
|
|
|
|
|
|
|
|
|
|
// 优化:直接在主线程处理,减少线程切换开销
|
|
|
|
|
// 对于大多数情况,文本分割和视图创建的开销很小
|
|
|
|
|
// 只有在文本特别长时才需要考虑后台线程
|
|
|
|
|
if (processedText.length() > 10000) {
|
|
|
|
|
// 对于长文本,使用后台线程
|
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
final String[] items = processTextForListMode(processedText);
|
|
|
|
|
Log.d(TAG, "switchToListMode: split into " + items.length + " items");
|
|
|
|
|
|
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
createListModeViews(items);
|
|
|
|
|
long endTime = System.currentTimeMillis();
|
|
|
|
|
Log.d(TAG, "switchToListMode completed in " + (endTime - startTime) + "ms");
|
|
|
|
|
// 预处理:在后台线程中分割文本和准备数据
|
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
final String[] items = processedText.split("\n"); // 按行分割文本
|
|
|
|
|
Log.d(TAG, "switchToListMode: split into " + items.length + " items");
|
|
|
|
|
|
|
|
|
|
// 切换回主线程更新UI
|
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
// 批量创建和添加视图,减少布局重绘
|
|
|
|
|
mEditTextList.removeAllViews(); // 清空编辑文本列表
|
|
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
|
View lastItem = null;
|
|
|
|
|
|
|
|
|
|
// 先创建所有视图
|
|
|
|
|
ArrayList<View> viewsToAdd = new ArrayList<>();
|
|
|
|
|
for (String item : items) {
|
|
|
|
|
if(!TextUtils.isEmpty(item)) {
|
|
|
|
|
View listItem = getListItem(item, index);
|
|
|
|
|
viewsToAdd.add(listItem);
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}).start();
|
|
|
|
|
} else {
|
|
|
|
|
// 对于短文本,直接在主线程处理
|
|
|
|
|
final String[] items = processTextForListMode(processedText);
|
|
|
|
|
Log.d(TAG, "switchToListMode: split into " + items.length + " items");
|
|
|
|
|
createListModeViews(items);
|
|
|
|
|
long endTime = System.currentTimeMillis();
|
|
|
|
|
Log.d(TAG, "switchToListMode completed in " + (endTime - startTime) + "ms");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理文本,为清单模式做准备
|
|
|
|
|
* @param text 原始文本
|
|
|
|
|
* @return 处理后的文本数组
|
|
|
|
|
*/
|
|
|
|
|
private String[] processTextForListMode(String text) {
|
|
|
|
|
// 移除HTML标签,只保留纯文本
|
|
|
|
|
String plainText = removeHtmlTags(text);
|
|
|
|
|
// 按行分割
|
|
|
|
|
return plainText.split("\n");
|
|
|
|
|
}
|
|
|
|
|
// 添加最后一个空列表项
|
|
|
|
|
lastItem = getListItem("", index);
|
|
|
|
|
viewsToAdd.add(lastItem);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 移除HTML标签,只保留纯文本
|
|
|
|
|
* @param html HTML文本
|
|
|
|
|
* @return 纯文本
|
|
|
|
|
*/
|
|
|
|
|
private String removeHtmlTags(String html) {
|
|
|
|
|
// 简单的HTML标签移除,适合大多数情况
|
|
|
|
|
if (TextUtils.isEmpty(html)) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
// 移除常见HTML标签
|
|
|
|
|
String plainText = html.replaceAll("<[^>]+>", "");
|
|
|
|
|
// 处理HTML实体
|
|
|
|
|
plainText = plainText.replaceAll(" ", " ");
|
|
|
|
|
plainText = plainText.replaceAll("<", "<");
|
|
|
|
|
plainText = plainText.replaceAll(">", ">");
|
|
|
|
|
plainText = plainText.replaceAll("&", "&");
|
|
|
|
|
return plainText;
|
|
|
|
|
}
|
|
|
|
|
// 一次性添加所有视图到容器
|
|
|
|
|
for (View view : viewsToAdd) {
|
|
|
|
|
mEditTextList.addView(view);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 创建清单模式的视图
|
|
|
|
|
* @param items 文本项数组
|
|
|
|
|
*/
|
|
|
|
|
private void createListModeViews(String[] items) {
|
|
|
|
|
// 回收现有视图到缓存,减少内存占用
|
|
|
|
|
int childCount = mEditTextList.getChildCount();
|
|
|
|
|
for (int i = childCount - 1; i >= 0; i--) {
|
|
|
|
|
View view = mEditTextList.getChildAt(i);
|
|
|
|
|
recycleView(view);
|
|
|
|
|
}
|
|
|
|
|
// 清空编辑文本列表
|
|
|
|
|
mEditTextList.removeAllViews();
|
|
|
|
|
|
|
|
|
|
// 批量创建视图
|
|
|
|
|
ArrayList<View> viewsToAdd = new ArrayList<>();
|
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
|
|
for (String item : items) {
|
|
|
|
|
if (!TextUtils.isEmpty(item)) {
|
|
|
|
|
View listItem = getListItem(item, index);
|
|
|
|
|
viewsToAdd.add(listItem);
|
|
|
|
|
index++;
|
|
|
|
|
// 设置焦点
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) lastItem.getTag();
|
|
|
|
|
holder.etEditText.requestFocus();
|
|
|
|
|
|
|
|
|
|
mNoteEditor.setVisibility(View.GONE); // 隐藏普通编辑器
|
|
|
|
|
mEditTextList.setVisibility(View.VISIBLE); // 显示清单编辑器
|
|
|
|
|
|
|
|
|
|
long endTime = System.currentTimeMillis();
|
|
|
|
|
Log.d(TAG, "switchToListMode completed in " + (endTime - startTime) + "ms");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加最后一个空列表项
|
|
|
|
|
View lastItem = getListItem("", index);
|
|
|
|
|
viewsToAdd.add(lastItem);
|
|
|
|
|
|
|
|
|
|
// 批量添加视图,减少布局重绘
|
|
|
|
|
for (View view : viewsToAdd) {
|
|
|
|
|
mEditTextList.addView(view);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置焦点
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) lastItem.getTag();
|
|
|
|
|
holder.etEditText.requestFocus();
|
|
|
|
|
|
|
|
|
|
// 显示/隐藏编辑器
|
|
|
|
|
mNoteEditor.setVisibility(View.GONE);
|
|
|
|
|
mEditTextList.setVisibility(View.VISIBLE);
|
|
|
|
|
}).start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -1510,22 +1446,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
* @return 列表项视图
|
|
|
|
|
*/
|
|
|
|
|
private View getListItem(String item, int index) {
|
|
|
|
|
// 优先从缓存中获取视图,减少布局inflate开销
|
|
|
|
|
View view = null;
|
|
|
|
|
if (!mViewCache.isEmpty()) {
|
|
|
|
|
view = mViewCache.remove(0);
|
|
|
|
|
} else {
|
|
|
|
|
view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);
|
|
|
|
|
}
|
|
|
|
|
View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);
|
|
|
|
|
|
|
|
|
|
// 创建并缓存ViewHolder
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder == null) {
|
|
|
|
|
holder = new ListItemViewHolder();
|
|
|
|
|
holder.etEditText = (NoteEditText) view.findViewById(R.id.et_edit_text);
|
|
|
|
|
holder.cbEditItem = (CheckBox) view.findViewById(R.id.cb_edit_item);
|
|
|
|
|
view.setTag(holder);
|
|
|
|
|
}
|
|
|
|
|
ListItemViewHolder holder = new ListItemViewHolder();
|
|
|
|
|
holder.etEditText = (NoteEditText) view.findViewById(R.id.et_edit_text);
|
|
|
|
|
holder.cbEditItem = (CheckBox) view.findViewById(R.id.cb_edit_item);
|
|
|
|
|
view.setTag(holder);
|
|
|
|
|
|
|
|
|
|
final NoteEditText edit = holder.etEditText;
|
|
|
|
|
edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
|
|
|
|
|
@ -1535,20 +1462,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
|
|
|
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
|
|
|
if (isChecked) {
|
|
|
|
|
// 添加删除线和灰色效果
|
|
|
|
|
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
|
|
|
|
edit.setTextColor(Color.GRAY);
|
|
|
|
|
// 将已完成项目移到列表底部
|
|
|
|
|
moveCompletedItemToBottom(edit);
|
|
|
|
|
} else {
|
|
|
|
|
// 移除删除线和恢复颜色
|
|
|
|
|
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
|
|
|
|
|
edit.setTextColor(Color.BLACK);
|
|
|
|
|
// 将未完成项目移到列表顶部
|
|
|
|
|
moveUncompletedItemToTop(edit);
|
|
|
|
|
}
|
|
|
|
|
// 延迟保存,避免频繁操作导致卡顿
|
|
|
|
|
saveNoteDelayed();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@ -1556,120 +1473,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
if (item.startsWith(TAG_CHECKED)) {
|
|
|
|
|
cb.setChecked(true);
|
|
|
|
|
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
|
|
|
|
edit.setTextColor(Color.GRAY);
|
|
|
|
|
item = item.substring(TAG_CHECKED.length(), item.length()).trim();
|
|
|
|
|
} else if (item.startsWith(TAG_UNCHECKED)) {
|
|
|
|
|
cb.setChecked(false);
|
|
|
|
|
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
|
|
|
|
|
edit.setTextColor(Color.BLACK);
|
|
|
|
|
item = item.substring(TAG_UNCHECKED.length(), item.length()).trim();
|
|
|
|
|
} else {
|
|
|
|
|
// 重置为默认状态
|
|
|
|
|
cb.setChecked(false);
|
|
|
|
|
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
|
|
|
|
|
edit.setTextColor(Color.BLACK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置列表项点击事件监听器,用于标记项目为已完成状态
|
|
|
|
|
view.setOnClickListener(new OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
// 添加点击反馈效果
|
|
|
|
|
v.setBackgroundColor(Color.parseColor("#E0E0E0"));
|
|
|
|
|
v.postDelayed(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
v.setBackgroundColor(Color.TRANSPARENT);
|
|
|
|
|
}
|
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
|
|
// 处理列表项点击事件,标记项目为已完成状态
|
|
|
|
|
CheckBox checkBox = (CheckBox) v.findViewById(R.id.cb_edit_item);
|
|
|
|
|
checkBox.setChecked(!checkBox.isChecked());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置复选框点击事件监听器
|
|
|
|
|
cb.setOnClickListener(new OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
// 直接切换选中状态,避免与列表项点击事件冲突
|
|
|
|
|
cb.setChecked(!cb.isChecked());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置编辑文本点击事件监听器,用于进入详细编辑模式
|
|
|
|
|
edit.setOnClickListener(new OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
// 阻止事件冒泡,避免触发列表项的点击事件
|
|
|
|
|
v.setClickable(true);
|
|
|
|
|
v.setFocusable(true);
|
|
|
|
|
v.setFocusableInTouchMode(true);
|
|
|
|
|
|
|
|
|
|
// 添加点击反馈效果
|
|
|
|
|
edit.setBackgroundColor(Color.parseColor("#F0F0F0"));
|
|
|
|
|
edit.postDelayed(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
edit.setBackgroundColor(Color.TRANSPARENT);
|
|
|
|
|
}
|
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
|
|
// 处理编辑文本点击事件,进入详细编辑模式
|
|
|
|
|
edit.requestFocus();
|
|
|
|
|
edit.setSelection(edit.length());
|
|
|
|
|
// 显示软键盘
|
|
|
|
|
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 为编辑文本添加文本变化监听器,确保修改能够被保存
|
|
|
|
|
edit.addTextChangedListener(new android.text.TextWatcher() {
|
|
|
|
|
@Override
|
|
|
|
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void afterTextChanged(android.text.Editable s) {
|
|
|
|
|
// 文本变化后延迟保存笔记,避免频繁操作导致卡顿
|
|
|
|
|
saveNoteDelayed();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置列表项长按事件监听器
|
|
|
|
|
edit.setOnLongClickListener(new View.OnLongClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onLongClick(View v) {
|
|
|
|
|
try {
|
|
|
|
|
// 添加长按反馈效果
|
|
|
|
|
edit.setBackgroundColor(Color.parseColor("#D0D0D0"));
|
|
|
|
|
edit.postDelayed(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
edit.setBackgroundColor(Color.TRANSPARENT);
|
|
|
|
|
}
|
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
|
|
// 处理长按事件,将清单标记为已完成状态
|
|
|
|
|
View parentView = (View) v.getParent();
|
|
|
|
|
if (parentView != null) {
|
|
|
|
|
CheckBox checkBox = (CheckBox) parentView.findViewById(R.id.cb_edit_item);
|
|
|
|
|
if (checkBox != null) {
|
|
|
|
|
checkBox.setChecked(!checkBox.isChecked());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error in long click listener: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
edit.setOnTextViewChangeListener(this);
|
|
|
|
|
edit.setIndex(index);
|
|
|
|
|
edit.setText(getHighlightQueryResult(item, mUserQuery));
|
|
|
|
|
@ -1698,161 +1508,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将已完成的项目移到列表底部
|
|
|
|
|
* @param edit 编辑文本框
|
|
|
|
|
*/
|
|
|
|
|
private void moveCompletedItemToBottom(NoteEditText edit) {
|
|
|
|
|
try {
|
|
|
|
|
int childCount = mEditTextList.getChildCount();
|
|
|
|
|
if (childCount <= 1 || edit == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找到当前项目的索引
|
|
|
|
|
int currentIndex = -1;
|
|
|
|
|
for (int i = 0; i < childCount; i++) {
|
|
|
|
|
View view = mEditTextList.getChildAt(i);
|
|
|
|
|
if (view != null) {
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder != null && holder.etEditText == edit) {
|
|
|
|
|
currentIndex = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentIndex == -1 || currentIndex == childCount - 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找到第一个未完成的项目索引
|
|
|
|
|
int firstUncompletedIndex = -1;
|
|
|
|
|
for (int i = currentIndex + 1; i < childCount; i++) {
|
|
|
|
|
View view = mEditTextList.getChildAt(i);
|
|
|
|
|
if (view != null) {
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder != null && holder.cbEditItem != null && !holder.cbEditItem.isChecked()) {
|
|
|
|
|
firstUncompletedIndex = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (firstUncompletedIndex != -1) {
|
|
|
|
|
// 保存当前项目
|
|
|
|
|
View currentView = mEditTextList.getChildAt(currentIndex);
|
|
|
|
|
if (currentView != null) {
|
|
|
|
|
mEditTextList.removeViewAt(currentIndex);
|
|
|
|
|
// 插入到第一个未完成项目之前
|
|
|
|
|
mEditTextList.addView(currentView, firstUncompletedIndex - 1);
|
|
|
|
|
// 更新索引
|
|
|
|
|
updateItemIndices();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error in moveCompletedItemToBottom: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将未完成的项目移到列表顶部
|
|
|
|
|
* @param edit 编辑文本框
|
|
|
|
|
*/
|
|
|
|
|
private void moveUncompletedItemToTop(NoteEditText edit) {
|
|
|
|
|
try {
|
|
|
|
|
int childCount = mEditTextList.getChildCount();
|
|
|
|
|
if (childCount <= 1 || edit == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找到当前项目的索引
|
|
|
|
|
int currentIndex = -1;
|
|
|
|
|
for (int i = 0; i < childCount; i++) {
|
|
|
|
|
View view = mEditTextList.getChildAt(i);
|
|
|
|
|
if (view != null) {
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder != null && holder.etEditText == edit) {
|
|
|
|
|
currentIndex = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentIndex == -1 || currentIndex == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找到最后一个已完成的项目索引
|
|
|
|
|
int lastCompletedIndex = -1;
|
|
|
|
|
for (int i = 0; i < currentIndex; i++) {
|
|
|
|
|
View view = mEditTextList.getChildAt(i);
|
|
|
|
|
if (view != null) {
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder != null && holder.cbEditItem != null && holder.cbEditItem.isChecked()) {
|
|
|
|
|
lastCompletedIndex = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存当前项目
|
|
|
|
|
View currentView = mEditTextList.getChildAt(currentIndex);
|
|
|
|
|
if (currentView != null) {
|
|
|
|
|
mEditTextList.removeViewAt(currentIndex);
|
|
|
|
|
// 插入到最后一个已完成项目之后
|
|
|
|
|
mEditTextList.addView(currentView, lastCompletedIndex + 1);
|
|
|
|
|
// 更新索引
|
|
|
|
|
updateItemIndices();
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error in moveUncompletedItemToTop: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 更新所有项目的索引
|
|
|
|
|
*/
|
|
|
|
|
private void updateItemIndices() {
|
|
|
|
|
try {
|
|
|
|
|
int childCount = mEditTextList.getChildCount();
|
|
|
|
|
for (int i = 0; i < childCount; i++) {
|
|
|
|
|
View view = mEditTextList.getChildAt(i);
|
|
|
|
|
if (view != null) {
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder != null && holder.etEditText != null) {
|
|
|
|
|
holder.etEditText.setIndex(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error in updateItemIndices: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 回收视图到缓存
|
|
|
|
|
* @param view 要回收的视图
|
|
|
|
|
*/
|
|
|
|
|
private void recycleView(View view) {
|
|
|
|
|
if (view != null && mViewCache.size() < MAX_CACHE_SIZE) {
|
|
|
|
|
// 清除视图的内容和监听器,避免内存泄漏
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder != null) {
|
|
|
|
|
holder.etEditText.setText("");
|
|
|
|
|
holder.etEditText.setOnTextViewChangeListener(null);
|
|
|
|
|
holder.cbEditItem.setOnCheckedChangeListener(null);
|
|
|
|
|
}
|
|
|
|
|
mViewCache.add(view);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 清空视图缓存
|
|
|
|
|
*/
|
|
|
|
|
private void clearViewCache() {
|
|
|
|
|
mViewCache.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 清单模式改变时调用
|
|
|
|
|
* 实现NoteSettingChangedListener接口
|
|
|
|
|
@ -1925,35 +1580,26 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
private boolean getWorkingText() {
|
|
|
|
|
boolean hasChecked = false;
|
|
|
|
|
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
|
|
|
|
|
// 优化:使用StringBuilder的初始容量,减少扩容开销
|
|
|
|
|
StringBuilder sb = new StringBuilder(mEditTextList.getChildCount() * 50); // 预估每个项目平均50字符
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
for (int i = 0; i < mEditTextList.getChildCount(); i++) {
|
|
|
|
|
View view = mEditTextList.getChildAt(i);
|
|
|
|
|
if (view != null) {
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
if (holder != null && holder.etEditText != null && holder.cbEditItem != null) {
|
|
|
|
|
NoteEditText edit = holder.etEditText;
|
|
|
|
|
if (!TextUtils.isEmpty(edit.getText())) {
|
|
|
|
|
if (holder.cbEditItem.isChecked()) {
|
|
|
|
|
sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n");
|
|
|
|
|
hasChecked = true;
|
|
|
|
|
} else {
|
|
|
|
|
sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ListItemViewHolder holder = (ListItemViewHolder) view.getTag();
|
|
|
|
|
NoteEditText edit = holder.etEditText;
|
|
|
|
|
if (!TextUtils.isEmpty(edit.getText())) {
|
|
|
|
|
if (holder.cbEditItem.isChecked()) {
|
|
|
|
|
sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n");
|
|
|
|
|
hasChecked = true;
|
|
|
|
|
} else {
|
|
|
|
|
sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mWorkingNote.setWorkingText(sb.toString());
|
|
|
|
|
} else {
|
|
|
|
|
// 对于富文本模式,保存当前的HTML内容,包括Base64图片
|
|
|
|
|
// 优化:避免不必要的日志输出,减少IO开销
|
|
|
|
|
if (mNoteEditor != null) {
|
|
|
|
|
String currentHtml = mNoteEditor.getHtml();
|
|
|
|
|
if (currentHtml != null) {
|
|
|
|
|
mWorkingNote.setWorkingText(currentHtml);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
String currentHtml = mNoteEditor.getHtml();
|
|
|
|
|
Log.d(TAG, "getWorkingText called for rich text mode, saving HTML content: " + currentHtml);
|
|
|
|
|
mWorkingNote.setWorkingText(currentHtml);
|
|
|
|
|
}
|
|
|
|
|
return hasChecked;
|
|
|
|
|
}
|
|
|
|
|
@ -2202,71 +1848,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|
|
|
|
|
Toast.makeText(this, resId, duration).show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 延迟保存笔记,避免频繁操作导致卡顿
|
|
|
|
|
*/
|
|
|
|
|
private void saveNoteDelayed() {
|
|
|
|
|
// 移除之前的延迟保存任务
|
|
|
|
|
if (mSaveNoteHandler != null) {
|
|
|
|
|
mSaveNoteHandler.removeCallbacksAndMessages(null);
|
|
|
|
|
}
|
|
|
|
|
// 延迟500毫秒保存,避免频繁操作导致卡顿
|
|
|
|
|
mSaveNoteHandler.postDelayed(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
if (saveNote()) {
|
|
|
|
|
// 保存成功的简短提示
|
|
|
|
|
showSaveSuccessHint();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, 500);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示保存成功的简短提示
|
|
|
|
|
*/
|
|
|
|
|
private void showSaveSuccessHint() {
|
|
|
|
|
if (mSaveHint == null) {
|
|
|
|
|
mSaveHint = new TextView(this);
|
|
|
|
|
mSaveHint.setText("已保存");
|
|
|
|
|
mSaveHint.setTextColor(Color.GRAY);
|
|
|
|
|
mSaveHint.setTextSize(12);
|
|
|
|
|
mSaveHint.setPadding(10, 5, 10, 5);
|
|
|
|
|
mSaveHint.setGravity(Gravity.CENTER);
|
|
|
|
|
mSaveHint.setBackgroundColor(Color.parseColor("#E0E0E0"));
|
|
|
|
|
mSaveHint.setAlpha(0.0f);
|
|
|
|
|
|
|
|
|
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
|
|
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
|
|
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
|
|
|
);
|
|
|
|
|
params.gravity = Gravity.CENTER;
|
|
|
|
|
params.topMargin = 10;
|
|
|
|
|
mEditTextList.addView(mSaveHint, params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示动画
|
|
|
|
|
mSaveHint.animate()
|
|
|
|
|
.alpha(1.0f)
|
|
|
|
|
.setDuration(300)
|
|
|
|
|
.withEndAction(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
// 延迟后隐藏
|
|
|
|
|
mSaveHint.postDelayed(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
mSaveHint.animate()
|
|
|
|
|
.alpha(0.0f)
|
|
|
|
|
.setDuration(300)
|
|
|
|
|
.start();
|
|
|
|
|
}
|
|
|
|
|
}, 1000);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 从相册选择图片 OMO
|
|
|
|
|
*/
|
|
|
|
|
|