diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 2443da8..bffc164 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -162,6 +162,25 @@
android:theme="@android:style/Theme.Holo.Light" >
+
+
+
+
+
+
diff --git a/src/main/java/net/micode/notes/data/Notes.java b/src/main/java/net/micode/notes/data/Notes.java
index 2475b1a..a204483 100644
--- a/src/main/java/net/micode/notes/data/Notes.java
+++ b/src/main/java/net/micode/notes/data/Notes.java
@@ -39,10 +39,12 @@ public class Notes {
* - TYPE_NOTE:普通便签
* - TYPE_FOLDER:文件夹
* - TYPE_SYSTEM:系统文件夹
+ * - TYPE_TODO:代办事项
*/
public static final int TYPE_NOTE = 0; // 普通便签类型
public static final int TYPE_FOLDER = 1; // 文件夹类型
public static final int TYPE_SYSTEM = 2; // 系统文件夹类型
+ public static final int TYPE_TODO = 3; // 代办事项类型
/**
* 系统文件夹ID常量
@@ -265,6 +267,12 @@ public class Notes {
* 类型 : TEXT
*/
public static final String TAGS = "tags";
+
+ /**
+ * 通用数据列1,用于存储代办事项的状态
+ * 类型: INTEGER
+ */
+ public static final String DATA1 = "data1";
}
/**
@@ -365,6 +373,14 @@ public class Notes {
* Checklist模式常量
*/
public static final int MODE_CHECK_LIST = 1;
+
+ /**
+ * 代办事项状态常量
+ * - STATUS_INCOMPLETE:未完成
+ * - STATUS_COMPLETED:已完成
+ */
+ public static final int STATUS_INCOMPLETE = 0;
+ public static final int STATUS_COMPLETED = 1;
/**
* 文本便签集合的MIME类型
diff --git a/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
index 0d6067d..39bf475 100644
--- a/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
+++ b/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
@@ -36,7 +36,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
// 数据库版本号
- private static final int DB_VERSION = 9;
+ private static final int DB_VERSION = 10;
// 数据库表名定义
public interface TABLE {
@@ -95,7 +95,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
NoteColumns.PIN_PRIORITY + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.IS_LOCKED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.LOCK_PASSWORD + " TEXT NOT NULL DEFAULT ''," +
- NoteColumns.TAGS + " TEXT NOT NULL DEFAULT ''" +
+ NoteColumns.TAGS + " TEXT NOT NULL DEFAULT ''," +
+ NoteColumns.DATA1 + " INTEGER NOT NULL DEFAULT 0" +
")";
// 创建数据表的SQL语句
@@ -442,6 +443,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
upgradeToV9(db);
oldVersion++;
}
+
+ if (oldVersion == 9) {
+ upgradeToV10(db);
+ oldVersion++;
+ }
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
@@ -563,4 +569,15 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.TAGS
+ " TEXT NOT NULL DEFAULT ''");
}
+
+ /**
+ * 将数据库从v9升级到v10
+ * 此版本升级添加了DATA1字段,用于存储代办事项的状态
+ * @param db SQLite数据库实例
+ */
+ private void upgradeToV10(SQLiteDatabase db) {
+ // 为笔记表添加DATA1字段
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.DATA1
+ + " INTEGER NOT NULL DEFAULT 0");
+ }
}
diff --git a/src/main/java/net/micode/notes/ui/NotesListActivity.java b/src/main/java/net/micode/notes/ui/NotesListActivity.java
index 7c7df77..35f8bfb 100644
--- a/src/main/java/net/micode/notes/ui/NotesListActivity.java
+++ b/src/main/java/net/micode/notes/ui/NotesListActivity.java
@@ -55,6 +55,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
+import android.view.GestureDetector;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
@@ -130,9 +131,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private NoteItemData mFocusNoteDataItem;
- private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?";
+ private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=? AND " + NoteColumns.TYPE + "<>" + Notes.TYPE_TODO;
- private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>" + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR (" + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + NoteColumns.NOTES_COUNT + ">0)";
+ private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>" + Notes.TYPE_SYSTEM + " AND " + NoteColumns.TYPE + "<>" + Notes.TYPE_TODO + " AND " + NoteColumns.PARENT_ID + "=?) OR (" + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + NoteColumns.NOTES_COUNT + ">0)";
private final static int REQUEST_CODE_OPEN_NODE = 102;
private final static int REQUEST_CODE_NEW_NODE = 103;
@@ -265,6 +266,16 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
startAsyncNotesListQuery();
}
+ // 手势检测相关变量
+ private GestureDetector mGestureDetector;
+ private static final int SWIPE_MIN_DISTANCE = 120;
+ private static final int SWIPE_MAX_OFF_PATH = 250;
+ private static final int SWIPE_THRESHOLD_VELOCITY = 200;
+
+ // 界面切换相关变量
+ private TextView mNotesTab;
+ private TextView mTodoTab;
+
private void initResources() {
mContentResolver = this.getContentResolver();
mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
@@ -276,7 +287,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mNotesListView.setOnItemLongClickListener(this);
mNotesListAdapter = new NotesListAdapter(this);
mNotesListView.setAdapter(mNotesListAdapter);
- mAddNewNote = (Button) findViewById(R.id.btn_new_note);
+ mAddNewNote = (Button) findViewById(R.id.btn_add_note);
mAddNewNote.setOnClickListener(this);
mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
mDispatch = false;
@@ -286,6 +297,54 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mState = ListEditState.NOTE_LIST;
mModeCallBack = new ModeCallback();
+ // 初始化界面切换栏
+ mNotesTab = (TextView) findViewById(R.id.notes_tab);
+ mTodoTab = (TextView) findViewById(R.id.todo_tab);
+ mNotesTab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // 已经在便签界面,不需要切换
+ }
+ });
+ mTodoTab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // 切换到代办界面
+ Intent intent = new Intent(NotesListActivity.this, TodoListActivity.class);
+ startActivity(intent);
+ overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
+ }
+ });
+
+ // 初始化手势检测器
+ mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ try {
+ if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
+ return false;
+ // 右滑手势:从便签界面切换到代办界面
+ if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ Intent intent = new Intent(NotesListActivity.this, TodoListActivity.class);
+ startActivity(intent);
+ overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
+ return true;
+ }
+ } catch (Exception e) {
+ // 异常处理
+ }
+ return false;
+ }
+ });
+
+ // 为ListView添加手势监听
+ mNotesListView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return mGestureDetector.onTouchEvent(event);
+ }
+ });
+
// 初始化搜索栏组件
mSearchBar = (LinearLayout) findViewById(R.id.search_bar);
mSearchEditText = (EditText) findViewById(R.id.search_edit_text);
@@ -795,7 +854,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
public void onClick(View v) {
- if (v.getId() == R.id.btn_new_note) {
+ if (v.getId() == R.id.btn_add_note) {
createNewNote();
}
}
diff --git a/src/main/java/net/micode/notes/ui/TodoEditActivity.java b/src/main/java/net/micode/notes/ui/TodoEditActivity.java
new file mode 100644
index 0000000..c1b0ae3
--- /dev/null
+++ b/src/main/java/net/micode/notes/ui/TodoEditActivity.java
@@ -0,0 +1,180 @@
+package net.micode.notes.ui;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+import net.micode.notes.R;
+import net.micode.notes.data.Notes;
+import net.micode.notes.data.Notes.NoteColumns;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TodoEditActivity extends Activity implements View.OnClickListener {
+ // 界面元素
+ private ScrollView mScrollView;
+ private LinearLayout mInputContainer;
+ private Button mDoneButton;
+
+ // 内容解析器
+ private ContentResolver mContentResolver;
+
+ // 输入框列表
+ private List mInputs;
+
+ // 要编辑的代办事项ID(如果是编辑模式)
+ private long mTodoId;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.todo_edit);
+
+ initResources();
+ initInputs();
+ }
+
+ private void initResources() {
+ mContentResolver = getContentResolver();
+ mScrollView = findViewById(R.id.todo_edit_scroll);
+ mInputContainer = findViewById(R.id.todo_edit_container);
+ mDoneButton = findViewById(R.id.todo_edit_done_btn);
+ mDoneButton.setOnClickListener(this);
+
+ // 获取传递过来的代办事项ID(如果是编辑模式)
+ mTodoId = getIntent().getLongExtra("todo_id", -1);
+
+ // 初始化输入框列表
+ mInputs = new ArrayList<>();
+ EditText firstInput = findViewById(R.id.todo_edit_first_input);
+ mInputs.add(firstInput);
+
+ // 设置第一个输入框的键盘事件
+ setInputKeyListener(firstInput);
+ }
+
+ private void initInputs() {
+ if (mTodoId != -1) {
+ // 编辑模式:加载现有代办事项
+ Cursor cursor = mContentResolver.query(Notes.CONTENT_NOTE_URI,
+ new String[]{NoteColumns.SNIPPET}, NoteColumns.ID + "=?",
+ new String[]{String.valueOf(mTodoId)}, null);
+
+ if (cursor != null && cursor.moveToFirst()) {
+ String content = cursor.getString(0);
+ mInputs.get(0).setText(content);
+ cursor.close();
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == R.id.todo_edit_done_btn) {
+ // 保存所有代办事项
+ saveTodos();
+ }
+ }
+
+ // 设置输入框的键盘事件
+ private void setInputKeyListener(EditText input) {
+ input.setOnEditorActionListener((v, actionId, event) -> {
+ boolean handled = false;
+ if (actionId == EditorInfo.IME_ACTION_NEXT ||
+ (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN)) {
+ // 处理回车事件
+ handleEnterKey(input);
+ handled = true;
+ }
+ return handled;
+ });
+ }
+
+ // 处理回车事件
+ private void handleEnterKey(EditText currentInput) {
+ String text = currentInput.getText().toString().trim();
+ if (!text.isEmpty()) {
+ // 添加新的输入框
+ addNewInput();
+ }
+ }
+
+ // 添加新的输入框
+ private void addNewInput() {
+ // 创建新的输入框
+ EditText newInput = (EditText) LayoutInflater.from(this).inflate(
+ R.layout.todo_edit_input, null);
+
+ // 设置输入框属性
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ params.bottomMargin = getResources().getDimensionPixelSize(R.dimen.todo_edit_input_margin_bottom);
+ newInput.setLayoutParams(params);
+
+ // 设置键盘事件
+ setInputKeyListener(newInput);
+
+ // 添加到容器和列表
+ mInputContainer.addView(newInput);
+ mInputs.add(newInput);
+
+ // 滚动到新输入框
+ mScrollView.post(() -> mScrollView.fullScroll(ScrollView.FOCUS_DOWN));
+ }
+
+ // 保存所有代办事项
+ private void saveTodos() {
+ for (EditText input : mInputs) {
+ String content = input.getText().toString().trim();
+ if (!content.isEmpty()) {
+ if (mTodoId != -1) {
+ // 编辑模式:更新现有代办事项
+ updateTodo(mTodoId, content);
+ } else {
+ // 新建模式:创建新的代办事项
+ createTodo(content);
+ }
+ }
+ }
+
+ // 返回代办界面
+ setResult(RESULT_OK);
+ finish();
+ }
+
+ // 创建新的代办事项
+ private void createTodo(String content) {
+ ContentValues values = new ContentValues();
+ values.put(NoteColumns.PARENT_ID, Notes.ID_ROOT_FOLDER);
+ values.put(NoteColumns.CREATED_DATE, System.currentTimeMillis());
+ values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
+ values.put(NoteColumns.SNIPPET, content);
+ values.put(NoteColumns.TYPE, Notes.TYPE_TODO);
+ values.put(NoteColumns.DATA1, Notes.TextNote.STATUS_INCOMPLETE); // 未完成状态
+
+ mContentResolver.insert(Notes.CONTENT_NOTE_URI, values);
+ }
+
+ // 更新现有代办事项
+ private void updateTodo(long id, String content) {
+ ContentValues values = new ContentValues();
+ values.put(NoteColumns.SNIPPET, content);
+ values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
+
+ mContentResolver.update(Notes.CONTENT_NOTE_URI, values,
+ NoteColumns.ID + "=?", new String[]{String.valueOf(id)});
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/micode/notes/ui/TodoListActivity.java b/src/main/java/net/micode/notes/ui/TodoListActivity.java
new file mode 100644
index 0000000..7da6b78
--- /dev/null
+++ b/src/main/java/net/micode/notes/ui/TodoListActivity.java
@@ -0,0 +1,505 @@
+package net.micode.notes.ui;
+
+import android.app.Activity;
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.view.ActionMode;
+import android.view.GestureDetector;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import net.micode.notes.R;
+import net.micode.notes.data.Notes;
+import net.micode.notes.data.Notes.NoteColumns;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TodoListActivity extends Activity implements View.OnClickListener {
+ // 手势检测相关变量
+ private GestureDetector mGestureDetector;
+ private static final int SWIPE_MIN_DISTANCE = 120;
+ private static final int SWIPE_MAX_OFF_PATH = 250;
+ private static final int SWIPE_THRESHOLD_VELOCITY = 200;
+
+ // 界面元素
+ private TextView mNotesTab;
+ private TextView mTodoTab;
+ private TextView mEmptyHint;
+ private ListView mIncompleteList;
+ private ListView mCompleteList;
+ private View mDivider;
+ private LinearLayout mCompleteSection;
+ private Button mAddTodoButton;
+
+ // 数据适配器
+ private TodoAdapter mIncompleteAdapter;
+ private TodoAdapter mCompleteAdapter;
+
+ // 数据列表
+ private List mIncompleteItems;
+ private List mCompleteItems;
+
+ // 内容解析器和异步查询处理器
+ private ContentResolver mContentResolver;
+ private BackgroundQueryHandler mBackgroundQueryHandler;
+
+ // 请求码
+ private static final int REQUEST_CODE_NEW_TODO = 100;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.todo_list);
+
+ initResources();
+ initGestureDetector();
+ initData();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ startAsyncTodoQuery();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_NEW_TODO) {
+ // 刷新代办事项列表
+ startAsyncTodoQuery();
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ private void initResources() {
+ mContentResolver = getContentResolver();
+ mBackgroundQueryHandler = new BackgroundQueryHandler(mContentResolver);
+
+ // 初始化界面元素
+ mEmptyHint = (TextView) findViewById(R.id.todo_empty_hint);
+ mIncompleteList = (ListView) findViewById(R.id.todo_incomplete_list);
+ mCompleteList = (ListView) findViewById(R.id.todo_complete_list);
+ mDivider = findViewById(R.id.todo_divider);
+ mCompleteSection = (LinearLayout) findViewById(R.id.todo_complete_section);
+ mAddTodoButton = (Button) findViewById(R.id.btn_add_todo);
+
+ // 初始化界面切换栏
+ mNotesTab = (TextView) findViewById(R.id.notes_tab);
+ mTodoTab = (TextView) findViewById(R.id.todo_tab);
+
+ // 设置点击事件
+ mNotesTab.setOnClickListener(this);
+ mTodoTab.setOnClickListener(this);
+ mAddTodoButton.setOnClickListener(this);
+
+ // 初始化数据适配器
+ mIncompleteItems = new ArrayList<>();
+ mCompleteItems = new ArrayList<>();
+ mIncompleteAdapter = new TodoAdapter(mIncompleteItems, false);
+ mCompleteAdapter = new TodoAdapter(mCompleteItems, true);
+ mIncompleteList.setAdapter(mIncompleteAdapter);
+ mCompleteList.setAdapter(mCompleteAdapter);
+
+ // 设置列表点击事件
+ mIncompleteList.setOnItemClickListener((parent, view, position, id) -> {
+ if (mIsMultiSelectMode) {
+ // 多选模式下,切换选中状态
+ TodoItem item = mIncompleteItems.get(position);
+ item.isSelected = !item.isSelected;
+ mIncompleteAdapter.notifyDataSetChanged();
+ updateSelectedItems();
+ } else {
+ // 非多选模式下,进入编辑模式
+ TodoItem item = mIncompleteItems.get(position);
+ Intent intent = new Intent(TodoListActivity.this, TodoEditActivity.class);
+ intent.putExtra("todo_id", item.id);
+ startActivityForResult(intent, REQUEST_CODE_NEW_TODO);
+ }
+ });
+
+ mCompleteList.setOnItemClickListener((parent, view, position, id) -> {
+ if (mIsMultiSelectMode) {
+ // 多选模式下,切换选中状态
+ TodoItem item = mCompleteItems.get(position);
+ item.isSelected = !item.isSelected;
+ mCompleteAdapter.notifyDataSetChanged();
+ updateSelectedItems();
+ } else {
+ // 非多选模式下,进入编辑模式
+ TodoItem item = mCompleteItems.get(position);
+ Intent intent = new Intent(TodoListActivity.this, TodoEditActivity.class);
+ intent.putExtra("todo_id", item.id);
+ startActivityForResult(intent, REQUEST_CODE_NEW_TODO);
+ }
+ });
+
+ // 设置列表长按事件
+ mIncompleteList.setOnItemLongClickListener((parent, view, position, id) -> {
+ startMultiSelectMode();
+ TodoItem item = mIncompleteItems.get(position);
+ item.isSelected = true;
+ mIncompleteAdapter.notifyDataSetChanged();
+ updateSelectedItems();
+ return true;
+ });
+
+ mCompleteList.setOnItemLongClickListener((parent, view, position, id) -> {
+ startMultiSelectMode();
+ TodoItem item = mCompleteItems.get(position);
+ item.isSelected = true;
+ mCompleteAdapter.notifyDataSetChanged();
+ updateSelectedItems();
+ return true;
+ });
+ }
+
+ private void initGestureDetector() {
+ // 初始化手势检测器
+ mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ try {
+ if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
+ return false;
+ // 左滑手势:从代办界面切换回便签界面
+ if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ Intent intent = new Intent(TodoListActivity.this, NotesListActivity.class);
+ startActivity(intent);
+ overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
+ return true;
+ }
+ } catch (Exception e) {
+ // 异常处理
+ }
+ return false;
+ }
+ });
+
+ // 为整个界面添加手势监听
+ findViewById(R.id.todo_incomplete_section).setOnTouchListener((v, event) -> mGestureDetector.onTouchEvent(event));
+ findViewById(R.id.todo_complete_section).setOnTouchListener((v, event) -> mGestureDetector.onTouchEvent(event));
+ }
+
+ private void initData() {
+ // 初始化数据,这里可以添加一些示例数据
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == R.id.notes_tab) {
+ // 切换到便签界面
+ Intent intent = new Intent(TodoListActivity.this, NotesListActivity.class);
+ startActivity(intent);
+ overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
+ } else if (v.getId() == R.id.todo_tab) {
+ // 已经在代办界面,不需要切换
+ } else if (v.getId() == R.id.btn_add_todo) {
+ // 跳转到新建代办事项界面
+ Intent newTodoIntent = new Intent(TodoListActivity.this, TodoEditActivity.class);
+ startActivityForResult(newTodoIntent, REQUEST_CODE_NEW_TODO);
+ }
+ }
+
+ private void startAsyncTodoQuery() {
+ // 查询未完成的代办事项
+ String selection = NoteColumns.TYPE + "=" + Notes.TYPE_TODO + " AND " + NoteColumns.DATA1 + "=" + Notes.TextNote.STATUS_INCOMPLETE;
+ mBackgroundQueryHandler.startQuery(0, null, Notes.CONTENT_NOTE_URI,
+ new String[]{NoteColumns.ID, NoteColumns.SNIPPET}, selection, null,
+ NoteColumns.CREATED_DATE + " ASC");
+
+ // 查询已完成的代办事项
+ selection = NoteColumns.TYPE + "=" + Notes.TYPE_TODO + " AND " + NoteColumns.DATA1 + "=" + Notes.TextNote.STATUS_COMPLETED;
+ mBackgroundQueryHandler.startQuery(1, null, Notes.CONTENT_NOTE_URI,
+ new String[]{NoteColumns.ID, NoteColumns.SNIPPET}, selection, null,
+ NoteColumns.CREATED_DATE + " ASC");
+ }
+
+ private void updateUI() {
+ // 更新未完成列表
+ if (mIncompleteItems.isEmpty()) {
+ mEmptyHint.setVisibility(View.VISIBLE);
+ mIncompleteList.setVisibility(View.GONE);
+ } else {
+ mEmptyHint.setVisibility(View.GONE);
+ mIncompleteList.setVisibility(View.VISIBLE);
+ }
+ mIncompleteAdapter.notifyDataSetChanged();
+
+ // 更新已完成列表
+ if (mCompleteItems.isEmpty()) {
+ mDivider.setVisibility(View.GONE);
+ mCompleteSection.setVisibility(View.GONE);
+ } else {
+ mDivider.setVisibility(View.VISIBLE);
+ mCompleteSection.setVisibility(View.VISIBLE);
+ }
+ mCompleteAdapter.notifyDataSetChanged();
+ }
+
+ // 代办事项数据类
+ private static class TodoItem {
+ long id;
+ String content;
+ boolean isCompleted;
+ boolean isSelected;
+
+ TodoItem(long id, String content, boolean isCompleted) {
+ this.id = id;
+ this.content = content;
+ this.isCompleted = isCompleted;
+ this.isSelected = false;
+ }
+ }
+
+ // 多选模式相关变量
+ private boolean mIsMultiSelectMode = false;
+ private ArrayList mSelectedIds = new ArrayList<>();
+ private ActionMode mActionMode;
+
+ // 代办事项适配器
+ private class TodoAdapter extends BaseAdapter {
+ private List mItems;
+ private boolean mIsCompletedSection;
+
+ TodoAdapter(List items, boolean isCompletedSection) {
+ mItems = items;
+ mIsCompletedSection = isCompletedSection;
+ }
+
+ @Override
+ public int getCount() {
+ return mItems.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mItems.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mItems.get(position).id;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder;
+ if (convertView == null) {
+ convertView = LayoutInflater.from(TodoListActivity.this).inflate(R.layout.todo_item, null);
+ holder = new ViewHolder();
+ holder.checkbox = convertView.findViewById(R.id.todo_item_checkbox);
+ holder.selectbox = convertView.findViewById(R.id.todo_item_selectbox);
+ holder.content = convertView.findViewById(R.id.todo_item_content);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ TodoItem item = mItems.get(position);
+ holder.content.setText(item.content);
+
+ if (mIsMultiSelectMode) {
+ // 多选模式下,显示方框选择框,隐藏圆形选择框
+ holder.checkbox.setVisibility(View.GONE);
+ holder.selectbox.setVisibility(View.VISIBLE);
+ holder.selectbox.setChecked(item.isSelected);
+
+ // 设置方框选择框点击事件
+ holder.selectbox.setTag(item);
+ holder.selectbox.setOnClickListener(v -> {
+ CheckBox checkBox = (CheckBox) v;
+ TodoItem todoItem = (TodoItem) checkBox.getTag();
+ todoItem.isSelected = checkBox.isChecked();
+ updateSelectedItems();
+ });
+ } else {
+ // 非多选模式下,显示圆形选择框,隐藏方框选择框
+ holder.checkbox.setVisibility(View.VISIBLE);
+ holder.selectbox.setVisibility(View.GONE);
+ holder.checkbox.setChecked(item.isCompleted);
+
+ // 设置文本颜色
+ if (item.isCompleted) {
+ holder.content.setTextColor(getResources().getColor(android.R.color.darker_gray));
+ } else {
+ holder.content.setTextColor(getResources().getColor(android.R.color.black));
+ }
+
+ // 设置圆形选择框点击事件
+ holder.checkbox.setTag(item);
+ holder.checkbox.setOnClickListener(v -> {
+ CheckBox checkBox = (CheckBox) v;
+ TodoItem todoItem = (TodoItem) checkBox.getTag();
+ todoItem.isCompleted = checkBox.isChecked();
+ updateTodoStatus(todoItem);
+ });
+ }
+
+ return convertView;
+ }
+
+ // 设置选中状态
+ public void setSelected(int position, boolean selected) {
+ if (position >= 0 && position < mItems.size()) {
+ mItems.get(position).isSelected = selected;
+ notifyDataSetChanged();
+ }
+ }
+
+ // 获取选中的项目
+ public ArrayList getSelectedIds() {
+ ArrayList selectedIds = new ArrayList<>();
+ for (TodoItem item : mItems) {
+ if (item.isSelected) {
+ selectedIds.add(item.id);
+ }
+ }
+ return selectedIds;
+ }
+
+ // 清除所有选中状态
+ public void clearSelection() {
+ for (TodoItem item : mItems) {
+ item.isSelected = false;
+ }
+ notifyDataSetChanged();
+ }
+
+ private class ViewHolder {
+ CheckBox checkbox; // 圆形选择框,用于标记完成状态
+ CheckBox selectbox; // 方框选择框,用于多选模式
+ TextView content;
+ }
+ }
+
+ // 更新代办事项状态
+ private void updateTodoStatus(TodoItem item) {
+ ContentValues values = new ContentValues();
+ values.put(NoteColumns.DATA1, item.isCompleted ? Notes.TextNote.STATUS_COMPLETED : Notes.TextNote.STATUS_INCOMPLETE);
+ values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
+
+ mContentResolver.update(Notes.CONTENT_NOTE_URI, values,
+ NoteColumns.ID + "=?", new String[]{String.valueOf(item.id)});
+
+ // 刷新列表
+ startAsyncTodoQuery();
+ }
+
+ // 开始多选模式
+ private void startMultiSelectMode() {
+ if (!mIsMultiSelectMode) {
+ mIsMultiSelectMode = true;
+ mActionMode = startActionMode(new ActionMode.Callback() {
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // 这里使用已有的note_list_options菜单
+ getMenuInflater().inflate(R.menu.note_list_options, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ if (item.getItemId() == R.id.delete) {
+ batchDelete();
+ mode.finish();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ mIsMultiSelectMode = false;
+ mSelectedIds.clear();
+ mIncompleteAdapter.clearSelection();
+ mCompleteAdapter.clearSelection();
+ mActionMode = null;
+ }
+ });
+ }
+ }
+
+ // 更新选中的项目
+ private void updateSelectedItems() {
+ mSelectedIds.clear();
+ mSelectedIds.addAll(mIncompleteAdapter.getSelectedIds());
+ mSelectedIds.addAll(mCompleteAdapter.getSelectedIds());
+
+ if (mActionMode != null) {
+ if (mSelectedIds.isEmpty()) {
+ mActionMode.finish();
+ } else {
+ // 使用占位符字符串,后续可以在strings.xml中添加
+ mActionMode.setTitle("已选择 " + mSelectedIds.size() + " 项");
+ }
+ }
+ }
+
+ // 批量删除选中的项目
+ private void batchDelete() {
+ if (!mSelectedIds.isEmpty()) {
+ for (long id : mSelectedIds) {
+ mContentResolver.delete(Notes.CONTENT_NOTE_URI,
+ NoteColumns.ID + "=?", new String[]{String.valueOf(id)});
+ }
+ // 刷新列表
+ startAsyncTodoQuery();
+ }
+ }
+
+ // 异步查询处理器
+ private class BackgroundQueryHandler extends AsyncQueryHandler {
+ BackgroundQueryHandler(ContentResolver contentResolver) {
+ super(contentResolver);
+ }
+
+ @Override
+ protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ if (cursor != null) {
+ try {
+ if (token == 0) {
+ // 处理未完成代办事项
+ mIncompleteItems.clear();
+ while (cursor.moveToNext()) {
+ long id = cursor.getLong(0);
+ String content = cursor.getString(1);
+ mIncompleteItems.add(new TodoItem(id, content, false));
+ }
+ } else if (token == 1) {
+ // 处理已完成代办事项
+ mCompleteItems.clear();
+ while (cursor.moveToNext()) {
+ long id = cursor.getLong(0);
+ String content = cursor.getString(1);
+ mCompleteItems.add(new TodoItem(id, content, true));
+ }
+ // 更新UI
+ updateUI();
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/res/anim/slide_in_left.xml b/src/main/res/anim/slide_in_left.xml
new file mode 100644
index 0000000..58f88a8
--- /dev/null
+++ b/src/main/res/anim/slide_in_left.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/anim/slide_in_right.xml b/src/main/res/anim/slide_in_right.xml
new file mode 100644
index 0000000..aea1f5d
--- /dev/null
+++ b/src/main/res/anim/slide_in_right.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/anim/slide_out_left.xml b/src/main/res/anim/slide_out_left.xml
new file mode 100644
index 0000000..4fef5cb
--- /dev/null
+++ b/src/main/res/anim/slide_out_left.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/anim/slide_out_right.xml b/src/main/res/anim/slide_out_right.xml
new file mode 100644
index 0000000..de15bd9
--- /dev/null
+++ b/src/main/res/anim/slide_out_right.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/drawable/ic_add_circle.xml b/src/main/res/drawable/ic_add_circle.xml
new file mode 100644
index 0000000..f60051c
--- /dev/null
+++ b/src/main/res/drawable/ic_add_circle.xml
@@ -0,0 +1,30 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/drawable/ic_done_circle.xml b/src/main/res/drawable/ic_done_circle.xml
new file mode 100644
index 0000000..d357380
--- /dev/null
+++ b/src/main/res/drawable/ic_done_circle.xml
@@ -0,0 +1,6 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/res/drawable/selected_tab_bg.xml b/src/main/res/drawable/selected_tab_bg.xml
new file mode 100644
index 0000000..a5a5721
--- /dev/null
+++ b/src/main/res/drawable/selected_tab_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/drawable/todo_checkbox.xml b/src/main/res/drawable/todo_checkbox.xml
new file mode 100644
index 0000000..78a0900
--- /dev/null
+++ b/src/main/res/drawable/todo_checkbox.xml
@@ -0,0 +1,26 @@
+
+
+
+ -
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/drawable/todo_edit_input_bg.xml b/src/main/res/drawable/todo_edit_input_bg.xml
new file mode 100644
index 0000000..b2ed3bb
--- /dev/null
+++ b/src/main/res/drawable/todo_edit_input_bg.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/drawable/unselected_tab_bg.xml b/src/main/res/drawable/unselected_tab_bg.xml
new file mode 100644
index 0000000..edc3849
--- /dev/null
+++ b/src/main/res/drawable/unselected_tab_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/note_list.xml b/src/main/res/layout/note_list.xml
index 2c4b3a6..c9afa71 100644
--- a/src/main/res/layout/note_list.xml
+++ b/src/main/res/layout/note_list.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-
+ android:orientation="vertical"
+ android:layout_above="@+id/view_switcher">
+
-
+ android:layout_alignParentRight="true"
+ android:layout_above="@+id/view_switcher"
+ android:layout_marginRight="16dp"
+ android:layout_marginBottom="16dp" />
+
diff --git a/src/main/res/layout/todo_edit.xml b/src/main/res/layout/todo_edit.xml
new file mode 100644
index 0000000..5e64ee1
--- /dev/null
+++ b/src/main/res/layout/todo_edit.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/todo_edit_input.xml b/src/main/res/layout/todo_edit_input.xml
new file mode 100644
index 0000000..2a5fc70
--- /dev/null
+++ b/src/main/res/layout/todo_edit_input.xml
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/todo_item.xml b/src/main/res/layout/todo_item.xml
new file mode 100644
index 0000000..4c947ea
--- /dev/null
+++ b/src/main/res/layout/todo_item.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/todo_list.xml b/src/main/res/layout/todo_list.xml
new file mode 100644
index 0000000..e70433c
--- /dev/null
+++ b/src/main/res/layout/todo_list.xml
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/values/dimens.xml b/src/main/res/values/dimens.xml
index 194e84f..7d25bb9 100644
--- a/src/main/res/values/dimens.xml
+++ b/src/main/res/values/dimens.xml
@@ -21,4 +21,5 @@
20sp
17sp
14sp
+ 12dp
\ No newline at end of file