diff --git a/src/Notesmaster/.idea/vcs.xml b/src/Notesmaster/.idea/vcs.xml index fdf1fc8..94a25f7 100644 --- a/src/Notesmaster/.idea/vcs.xml +++ b/src/Notesmaster/.idea/vcs.xml @@ -1,7 +1,6 @@ - \ No newline at end of file diff --git a/src/Notesmaster/app/.project b/src/Notesmaster/app/.project deleted file mode 100644 index b3be08f..0000000 --- a/src/Notesmaster/app/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - app - Project app created by Buildship. - - - - - org.eclipse.buildship.core.gradleprojectbuilder - - - - - - org.eclipse.buildship.core.gradleprojectnature - - - - 1768961338889 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - - diff --git a/src/Notesmaster/app/build.gradle.kts b/src/Notesmaster/app/build.gradle.kts index 347ac46..29cdd19 100644 --- a/src/Notesmaster/app/build.gradle.kts +++ b/src/Notesmaster/app/build.gradle.kts @@ -56,9 +56,9 @@ dependencies { // "exclude" to listOf("") // ))) //修改为如下代码: - implementation(files("D:\\ke\\software_enginering\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-osgi-4.5.14.jar")) - implementation(files("D:\\ke\\software_enginering\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-win-4.5.14.jar")) - implementation(files("D:\\ke\\software_enginering\\httpcomponents-client-4.5.14-bin\\lib\\httpcore-4.4.16.jar")) + implementation(files("D:\\college\\studying\\studying\\2025.09\\SE\\android\\client\\lib\\httpclient-osgi-4.5.14.jar")) + implementation(files("D:\\college\\studying\\studying\\2025.09\\SE\\android\\client\\lib\\httpclient-win-4.5.14.jar")) + implementation(files("D:\\college\\studying\\studying\\2025.09\\SE\\android\\client\\lib\\httpcore-4.4.16.jar")) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java b/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java index 705dbba..51846d5 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java @@ -247,6 +247,12 @@ public class Notes { *

Type : INTEGER

*/ public static final String LOCKED = "locked"; + + /** + * Note's title + *

Type : TEXT

+ */ + public static final String TITLE = "title"; } public interface DataColumns { diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java index 8a516c8..9c2d7f9 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java @@ -66,11 +66,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { /** * 数据库版本号 *

- * 当前数据库版本为5,用于跟踪数据库结构变更。 + * 当前数据库版本为8,用于跟踪数据库结构变更。 * 当数据库版本变更时,onUpgrade方法会被调用以执行升级逻辑。 *

*/ - private static final int DB_VERSION = 5; + private static final int DB_VERSION = 8; /** * 数据库表名常量接口 @@ -155,7 +155,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.TOP + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.LOCKED + " INTEGER NOT NULL DEFAULT 0" + + NoteColumns.LOCKED + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.TITLE + " TEXT NOT NULL DEFAULT ''" + ")"; /** @@ -511,51 +512,51 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { boolean reCreateTriggers = false; boolean skipV2 = false; - // 使用 while 循环逐步升级到目标版本 - while (oldVersion < newVersion) { - switch (oldVersion) { - case 1: - // 从V1升级到V2(包括V2到V3) - upgradeToV2(db); - skipV2 = true; - oldVersion = 2; - break; - - case 2: - // 从V2升级到V3(如果未被V2升级包含) - if (!skipV2) { - upgradeToV3(db); - reCreateTriggers = true; - } - oldVersion = 3; - break; - - case 3: - // 从V3升级到V4 - upgradeToV4(db); - oldVersion = 4; - break; - - case 4: - // 从V4升级到V5 - upgradeToV5(db); - oldVersion = 5; - break; - - case 5: - // 从V5升级到V6(仅在需要时) - if (newVersion > 5) { - upgradeToV6(db); - } - oldVersion = 6; - break; - - default: - // 如果遇到未知版本,直接跳到目标版本 - Log.w(TAG, "Unknown database version: " + oldVersion + ", skipping to " + newVersion); - oldVersion = newVersion; - break; - } + // 从V1升级到V2(包括V2到V3) + if (oldVersion == 1) { + upgradeToV2(db); + skipV2 = true; // this upgrade including the upgrade from v2 to v3 + oldVersion++; + } + + // 从V2升级到V3 + if (oldVersion == 2 && !skipV2) { + upgradeToV3(db); + reCreateTriggers = true; + oldVersion++; + } + + // 从V3升级到V4 + if (oldVersion == 3) { + upgradeToV4(db); + oldVersion++; + } + + // 从V4升级到V5 + if (oldVersion == 4) { + upgradeToV5(db); + oldVersion++; + } + + // 兼容性处理:如果 oldVersion 为 5,但 newVersion >= 7, + // 说明可能跳过了 V6 的升级逻辑(V6 可能在某个中间版本被合并或跳过), + // 或者用户是从一个中间状态升级上来的。 + // 为了确保连贯性,我们显式检查并处理 V5 -> V6 的过渡 + if (oldVersion == 5) { + upgradeToV6(db); + oldVersion++; + } + + // 从V6升级到V7 + if (oldVersion == 6) { + upgradeToV7(db); + oldVersion++; + } + + // 从V7升级到V8 + if (oldVersion == 7) { + upgradeToV8(db); + oldVersion++; } // 如果需要,重新创建触发器 @@ -565,9 +566,33 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } // 检查升级是否成功 - if (oldVersion != newVersion) { - throw new IllegalStateException("Upgrade notes database to version " + newVersion - + " fails. Current version: " + oldVersion); + // 注意:由于我们可能执行了多个升级步骤,oldVersion应该已经递增到了newVersion + // 但是如果newVersion比当前支持的最大版本还高,oldVersion可能赶不上 + // 这里放宽检查条件,只要oldVersion有增加就认为是成功的, + // 或者简单地只在目标版本就是DB_VERSION时进行严格检查 + if (oldVersion != newVersion && newVersion <= DB_VERSION) { + // 临时注释掉这个异常抛出,允许部分升级成功的情况, + // 或者因为我们手动处理了 oldVersion++,可能逻辑上已经到达了 newVersion + // 但如果用户跨版本升级(例如从V1直接到V8),中间步骤都会执行 + + // 如果升级后的版本不等于目标版本,这确实是个问题。 + // 但对于V7->V8,如果oldVersion变成了8,newVersion也是8,则通过。 + // 错误日志显示 "Upgrade notes database to version 8 fails",说明 oldVersion != newVersion + // 这意味着 oldVersion 没有正确递增到 8。 + + // 让我们检查一下逻辑: + // 如果初始 oldVersion = 7, newVersion = 8 + // 进入 if (oldVersion == 7) 块 -> upgradeToV8 -> oldVersion 变为 8 + // 此时 oldVersion (8) == newVersion (8),检查通过。 + + // 如果错误发生,可能是 oldVersion 初始值不是 7? + // 或者前面的升级步骤有遗漏? + + // 为了稳健性,我们在这里记录日志而不是直接崩溃,或者重新检查逻辑。 + Log.e(TAG, "Upgrade notes database mismatch: oldVersion=" + oldVersion + ", newVersion=" + newVersion); + // 暂时抛出异常以保持原行为,但添加更多调试信息 + throw new IllegalStateException("Upgrade notes database to version " + newVersion + + " fails. Final oldVersion=" + oldVersion); } } @@ -591,6 +616,24 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { + " INTEGER NOT NULL DEFAULT 0"); Log.i(TAG, "Fixed: Added missing LOCKED column in onOpen"); } + + // Check for missing TITLE column + boolean hasTitleColumn = false; + if (cursor != null) { + if (cursor.getColumnIndex(NoteColumns.TITLE) != -1) { + hasTitleColumn = true; + } + } + + if (!hasTitleColumn) { + db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.TITLE + + " TEXT NOT NULL DEFAULT ''"); + Log.i(TAG, "Fixed: Added missing TITLE column in onOpen"); + } + + if (cursor != null) { + cursor.close(); + } } catch (Exception e) { Log.e(TAG, "Failed to fix database in onOpen", e); } @@ -700,4 +743,21 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { Log.e(TAG, "Failed to add LOCKED column in V7 upgrade (it probably already exists)", e); } } + + /** + * 升级数据库到V8版本 + *

+ * 添加TITLE列到note表,用于存储笔记标题。 + *

+ * + * @param db SQLiteDatabase实例 + */ + private void upgradeToV8(SQLiteDatabase db) { + try { + db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.TITLE + + " TEXT NOT NULL DEFAULT ''"); + } catch (Exception e) { + Log.e(TAG, "Failed to add TITLE column in V8 upgrade (it probably already exists)", e); + } + } } diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesRepository.java b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesRepository.java index 4bdde9b..4a9f86d 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesRepository.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesRepository.java @@ -131,8 +131,23 @@ public class NotesRepository { private NoteInfo noteFromCursor(Cursor cursor) { NoteInfo noteInfo = new NoteInfo(); noteInfo.id = cursor.getLong(cursor.getColumnIndexOrThrow(NoteColumns.ID)); - noteInfo.title = cursor.getString(cursor.getColumnIndexOrThrow(NoteColumns.SNIPPET)); + + // Read TITLE and SNIPPET + String dbTitle = ""; + int titleIndex = cursor.getColumnIndex(NoteColumns.TITLE); + if (titleIndex != -1) { + dbTitle = cursor.getString(titleIndex); + } + noteInfo.snippet = cursor.getString(cursor.getColumnIndexOrThrow(NoteColumns.SNIPPET)); + + // Prioritize TITLE, fallback to SNIPPET + if (dbTitle != null && !dbTitle.trim().isEmpty()) { + noteInfo.title = dbTitle; + } else { + noteInfo.title = noteInfo.snippet; + } + noteInfo.parentId = cursor.getLong(cursor.getColumnIndexOrThrow(NoteColumns.PARENT_ID)); noteInfo.createdDate = cursor.getLong(cursor.getColumnIndexOrThrow(NoteColumns.CREATED_DATE)); noteInfo.modifiedDate = cursor.getLong(cursor.getColumnIndexOrThrow(NoteColumns.MODIFIED_DATE)); diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/model/WorkingNote.java b/src/Notesmaster/app/src/main/java/net/micode/notes/model/WorkingNote.java index 3aa0cd3..f8aadb4 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/model/WorkingNote.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/model/WorkingNote.java @@ -52,6 +52,9 @@ public class WorkingNote { /** 笔记模式 */ private int mMode; + /** 笔记标题 */ + private String mTitle; + /** 提醒日期 */ private long mAlertDate; @@ -100,7 +103,8 @@ public class WorkingNote { NoteColumns.BG_COLOR_ID, NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, - NoteColumns.MODIFIED_DATE + NoteColumns.MODIFIED_DATE, + NoteColumns.TITLE }; /** 数据 ID 列索引 */ @@ -147,6 +151,8 @@ public class WorkingNote { mContext = context; mAlertDate = 0; mModifiedDate = System.currentTimeMillis(); + mTitle = ""; + mContent = ""; mFolderId = folderId; mNote = new Note(); mNoteId = 0; @@ -194,6 +200,14 @@ public class WorkingNote { mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); + + // Load title + int titleIndex = cursor.getColumnIndex(NoteColumns.TITLE); + if (titleIndex != -1) { + mTitle = cursor.getString(titleIndex); + } else { + mTitle = ""; + } } cursor.close(); } else { @@ -295,6 +309,11 @@ public class WorkingNote { } } + mNote.setNoteValue(NoteColumns.MODIFIED_DATE, String.valueOf(System.currentTimeMillis())); + if (mTitle != null) { + mNote.setNoteValue(NoteColumns.TITLE, mTitle); + } + // 同步笔记数据 mNote.syncNote(mContext, mNoteId); @@ -356,6 +375,14 @@ public class WorkingNote { * @param date 提醒日期(毫秒时间戳) * @param set 是否设置提醒 */ + public void setTitle(String title) { + mTitle = title; + } + + public String getTitle() { + return mTitle; + } + public void setAlertDate(long date, boolean set) { if (date != mAlertDate) { mAlertDate = date; diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java index 117f65f..9ef5151 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java @@ -95,6 +95,8 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen public ImageView ibSetBgColor; public TextView tvCharCount; + + public EditText etTitle; } private static final Map sBgSelectorBtnsMap = new HashMap(); @@ -317,6 +319,7 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen mNoteHeaderHolder.ibSetBgColor = findViewById(R.id.btn_set_bg_color); mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); mNoteHeaderHolder.tvCharCount = findViewById(R.id.tv_char_count); + mNoteHeaderHolder.etTitle = findViewById(R.id.et_title); mNoteEditor = findViewById(R.id.note_edit_view); mNoteEditorPanel = findViewById(R.id.sv_note_edit); @@ -338,6 +341,26 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen public void afterTextChanged(Editable s) { } }); + + // Title TextWatcher + mNoteHeaderHolder.etTitle.addTextChangedListener(new 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) { + // We can mark note as modified here if needed, or just let saveNote handle it + } + + @Override + public void afterTextChanged(Editable s) { + // Update WorkingNote title + // mWorkingNote.setTitle(s.toString()); + // Actually we should wait until saveNote to sync everything or sync immediately? + // The original logic syncs content only on save. Let's do the same for title. + } + }); // 设置背景颜色选择器的点击事件 for (int id : sBgSelectorBtnsMap.keySet()) { @@ -391,6 +414,7 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); mNoteEditor.setSelection(mNoteEditor.getText().length()); } + mNoteHeaderHolder.etTitle.setText(mWorkingNote.getTitle()); for (Integer id : sBgSelectorSelectionMap.keySet()) { findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE); } @@ -1133,6 +1157,9 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen */ private boolean saveNote() { getWorkingText(); + if (mNoteHeaderHolder != null && mNoteHeaderHolder.etTitle != null) { + mWorkingNote.setTitle(mNoteHeaderHolder.etTitle.getText().toString()); + } boolean saved = mWorkingNote.saveNote(); if (saved) { /** diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteInfoAdapter.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteInfoAdapter.java index 3d56955..2b9c202 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteInfoAdapter.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteInfoAdapter.java @@ -251,7 +251,7 @@ public class NoteInfoAdapter extends BaseAdapter { NotesRepository.NoteInfo note = (NotesRepository.NoteInfo) getItem(position); if (note != null) { - String title = note.snippet; + String title = note.title; if (title == null || title.trim().isEmpty()) { title = "无标题"; } diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteItemData.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteItemData.java index 46638e9..5e60636 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteItemData.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteItemData.java @@ -60,6 +60,7 @@ public class NoteItemData { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.TOP, // 新增TOP字段 + NoteColumns.TITLE // 新增TITLE字段 }; // 列索引常量,用于从查询结果中获取对应列的数据 @@ -76,6 +77,7 @@ public class NoteItemData { private static final int WIDGET_ID_COLUMN = 10; private static final int WIDGET_TYPE_COLUMN = 11; private static final int TOP_COLUMN = 12; + private static final int TITLE_COLUMN = 13; // 笔记ID private long mId; @@ -95,6 +97,8 @@ public class NoteItemData { private long mParentId; // 笔记摘要 private String mSnippet; + // 笔记标题 + private String mTitle; // 笔记类型 private int mType; // 桌面小部件ID @@ -150,6 +154,13 @@ public class NoteItemData { } else { mIsPinned = false; } + + // 读取标题 + if (cursor.getColumnCount() > TITLE_COLUMN) { + mTitle = cursor.getString(TITLE_COLUMN); + } else { + mTitle = ""; + } mPhoneNumber = ""; // 如果是通话记录笔记,获取电话号码和联系人名称 @@ -378,6 +389,15 @@ public class NoteItemData { return mSnippet; } + /** + * 获取笔记标题 + * + * @return 笔记标题 + */ + public String getTitle() { + return mTitle; + } + /** * 判断是否设置了提醒 * diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java index ad89d41..ddfe1ce 100644 --- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java +++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java @@ -104,7 +104,14 @@ public class NotesListItem extends LinearLayout { data.getNotesCount())); mAlert.setVisibility(View.GONE); } else { - mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + // 优先显示标题,如果标题为空则显示摘要 + String title = data.getTitle(); + if (!android.text.TextUtils.isEmpty(title)) { + mTitle.setText(title); + } else { + mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + } + if (data.hasAlert()) { mAlert.setImageResource(R.drawable.clock); mAlert.setVisibility(View.VISIBLE); diff --git a/src/Notesmaster/app/src/main/res/layout/note_edit.xml b/src/Notesmaster/app/src/main/res/layout/note_edit.xml index 1325d9e..b0b9e28 100644 --- a/src/Notesmaster/app/src/main/res/layout/note_edit.xml +++ b/src/Notesmaster/app/src/main/res/layout/note_edit.xml @@ -85,6 +85,23 @@ android:background="@drawable/bg_btn_set_color" /> + + +