From 4f078b40cddcb11e4270cfec4636e1babf204f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B6=E4=BF=8A=E5=AE=87?= <2643473564@qq.com> Date: Mon, 26 Jan 2026 14:43:44 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=90=88=E5=B9=B6=E5=86=B2?= =?UTF-8?q?=E7=AA=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/AndroidManifest.xml | 9 +- .../java/net/micode/notes/data/Notes.java | 7 + .../notes/data/NotesDatabaseHelper.java | 69 ++++- .../net/micode/notes/data/NotesProvider.java | 6 +- .../net/micode/notes/model/NoteTemplate.java | 119 -------- .../notes/model/RecentlyDeletedManager.java | 230 +++++++++++++++ .../micode/notes/model/TemplateManager.java | 271 ------------------ .../net/micode/notes/ui/NoteEditActivity.java | 33 --- .../notes/ui/TemplateSelectActivity.java | 207 ------------- .../notes/worker/TrashCleanupWorker.java | 15 +- src/main/res/drawable/template_item_bg.xml | 21 -- src/main/res/drawable/template_type_bg.xml | 9 - src/main/res/layout/template_item.xml | 43 --- src/main/res/layout/template_select.xml | 59 ---- src/main/res/menu/note_edit.xml | 4 - src/main/res/menu/note_list_options.xml | 6 + src/main/res/values/arrays.xml | 21 ++ src/main/res/values/strings.xml | 15 +- src/main/res/xml/preferences.xml | 11 + src/main/res/xml/searchable.xml | 2 +- 20 files changed, 364 insertions(+), 793 deletions(-) delete mode 100644 src/main/java/net/micode/notes/model/NoteTemplate.java create mode 100644 src/main/java/net/micode/notes/model/RecentlyDeletedManager.java delete mode 100644 src/main/java/net/micode/notes/model/TemplateManager.java delete mode 100644 src/main/java/net/micode/notes/ui/TemplateSelectActivity.java delete mode 100644 src/main/res/drawable/template_item_bg.xml delete mode 100644 src/main/res/drawable/template_type_bg.xml delete mode 100644 src/main/res/layout/template_item.xml delete mode 100644 src/main/res/layout/template_select.xml diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 2350512..cb43220 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -48,7 +48,7 @@ - + > @@ -67,13 +67,6 @@ android:resource="@xml/searchable" /> - - - 0表示便签锁,1表示文件夹锁

*/ public static final String LOCK_TYPE = "lock_type"; + + /** + * 便签或文件夹被删除的时间 + *

类型: INTEGER (long)

+ *

0表示未被删除,其他值表示删除时间戳

+ */ + public static final String DELETED_DATE = "deleted_date"; } public interface DataColumns { diff --git a/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java index ce29b9f..4edf21d 100644 --- a/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java @@ -35,7 +35,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { // 数据库文件名 private static final String DB_NAME = "note.db"; // 数据库版本号,用于升级控制 - private static final int DB_VERSION = 6; + private static final int DB_VERSION = 7; /** * 数据库表名常量定义 @@ -78,7 +78,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.PINNED + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.IS_LOCKED + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.LOCK_PASSWORD + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.LOCK_TYPE + " INTEGER NOT NULL DEFAULT 0" + + NoteColumns.LOCK_TYPE + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.DELETED_DATE + " INTEGER NOT NULL DEFAULT 0" + ")"; /** @@ -263,6 +264,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); + db.execSQL("DROP TRIGGER IF EXISTS record_deleted_date_on_trash"); + db.execSQL("DROP TRIGGER IF EXISTS clear_deleted_date_on_restore"); db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); @@ -271,6 +274,28 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); + + // 创建记录删除时间触发器 + db.execSQL("CREATE TRIGGER record_deleted_date_on_trash " + + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " AND old." + NoteColumns.PARENT_ID + "!=" + Notes.ID_TRASH_FOLER + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.DELETED_DATE + "=strftime('%s','now') * 1000" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.ID + ";" + + " END"); + + // 创建清除删除时间触发器 + db.execSQL("CREATE TRIGGER clear_deleted_date_on_restore " + + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " WHEN new." + NoteColumns.PARENT_ID + "!=" + Notes.ID_TRASH_FOLER + + " AND old." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.DELETED_DATE + "=0" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.ID + ";" + + " END"); } /** @@ -394,6 +419,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { oldVersion++; } + // 版本6升级到版本7:添加删除时间字段和相关触发器 + if (oldVersion == 6) { + upgradeToV7(db); + oldVersion++; + } + // 如果需要,重新创建触发器 if (reCreateTriggers) { reCreateNoteTableTriggers(db); @@ -403,7 +434,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { // 验证升级是否完成 if (oldVersion != newVersion) { throw new IllegalStateException("Upgrade notes database to version " + newVersion - + "fails"); + + " fails"); } } @@ -467,4 +498,36 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCK_TYPE + " INTEGER NOT NULL DEFAULT 0"); } + + /** + * 升级到版本7:添加删除时间字段和相关触发器,用于最近删除功能 + * @param db 数据库实例 + */ + private void upgradeToV7(SQLiteDatabase db) { + // 添加DELETED_DATE字段,用于记录便签被删除的时间 + db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.DELETED_DATE + + " INTEGER NOT NULL DEFAULT 0"); + + // 创建触发器:当便签被移动到回收站时,自动记录删除时间 + db.execSQL("CREATE TRIGGER record_deleted_date_on_trash " + + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " AND old." + NoteColumns.PARENT_ID + "!=" + Notes.ID_TRASH_FOLER + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.DELETED_DATE + "=strftime('%s','now') * 1000" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.ID + ";" + + " END"); + + // 创建触发器:当便签从回收站恢复时,自动清除删除时间 + db.execSQL("CREATE TRIGGER clear_deleted_date_on_restore " + + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " WHEN new." + NoteColumns.PARENT_ID + "!=" + Notes.ID_TRASH_FOLER + + " AND old." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.DELETED_DATE + "=0" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.ID + ";" + + " END"); + } } \ No newline at end of file diff --git a/src/main/java/net/micode/notes/data/NotesProvider.java b/src/main/java/net/micode/notes/data/NotesProvider.java index 678534f..ceb1020 100644 --- a/src/main/java/net/micode/notes/data/NotesProvider.java +++ b/src/main/java/net/micode/notes/data/NotesProvider.java @@ -169,7 +169,11 @@ public class NotesProvider extends ContentProvider { searchString = uri.getPathSegments().get(1); } } else { - searchString = uri.getQueryParameter("pattern"); + // 支持Android搜索框架的标准参数名"query"和当前实现使用的"pattern" + searchString = uri.getQueryParameter(SearchManager.QUERY); + if (TextUtils.isEmpty(searchString)) { + searchString = uri.getQueryParameter("pattern"); + } } // 如果搜索关键词为空,返回null diff --git a/src/main/java/net/micode/notes/model/NoteTemplate.java b/src/main/java/net/micode/notes/model/NoteTemplate.java deleted file mode 100644 index c956f7d..0000000 --- a/src/main/java/net/micode/notes/model/NoteTemplate.java +++ /dev/null @@ -1,119 +0,0 @@ -package net.micode.notes.model; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.TextUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -/** - * 笔记模板数据模型类,用于存储和管理笔记模板 - */ -public class NoteTemplate { - public static final String TYPE_SYSTEM = "system"; - public static final String TYPE_CUSTOM = "custom"; - - private long id; - private String name; - private String content; - private String type; - private long createTime; - private long updateTime; - - public NoteTemplate() { - this.createTime = System.currentTimeMillis(); - this.updateTime = System.currentTimeMillis(); - } - - public NoteTemplate(long id, String name, String content, String type, long createTime, long updateTime) { - this.id = id; - this.name = name; - this.content = content; - this.type = type; - this.createTime = createTime; - this.updateTime = updateTime; - } - - // Getters and Setters - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public long getCreateTime() { - return createTime; - } - - public void setCreateTime(long createTime) { - this.createTime = createTime; - } - - public long getUpdateTime() { - return updateTime; - } - - public void setUpdateTime(long updateTime) { - this.updateTime = updateTime; - } - - /** - * 将模板对象转换为JSON对象 - */ - public JSONObject toJson() throws JSONException { - JSONObject json = new JSONObject(); - json.put("id", id); - json.put("name", name); - json.put("content", content); - json.put("type", type); - json.put("createTime", createTime); - json.put("updateTime", updateTime); - return json; - } - - /** - * 从JSON对象创建模板对象 - */ - public static NoteTemplate fromJson(JSONObject json) throws JSONException { - NoteTemplate template = new NoteTemplate(); - template.setId(json.getLong("id")); - template.setName(json.getString("name")); - template.setContent(json.getString("content")); - template.setType(json.getString("type")); - template.setCreateTime(json.getLong("createTime")); - template.setUpdateTime(json.getLong("updateTime")); - return template; - } -} diff --git a/src/main/java/net/micode/notes/model/RecentlyDeletedManager.java b/src/main/java/net/micode/notes/model/RecentlyDeletedManager.java new file mode 100644 index 0000000..c025468 --- /dev/null +++ b/src/main/java/net/micode/notes/model/RecentlyDeletedManager.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.model; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.util.Log; + +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.tool.DataUtils; + +import java.util.HashSet; + +/** + * 最近删除管理器,负责管理最近删除的便签和文件夹 + * 采用单例模式设计,提供获取最近删除项、恢复项、永久删除项、清空回收站等功能 + */ +public class RecentlyDeletedManager { + // 默认保留天数,超过此天数的已删除项将被自动清理 + public static final int DEFAULT_RETENTION_DAYS = 30; + // 清理任务间隔(每天) + public static final long CLEANUP_INTERVAL = 24 * 60 * 60 * 1000; + + private Context mContext; + private ContentResolver mContentResolver; + + // 单例实例 + private static RecentlyDeletedManager sInstance; + // 日志标签 + private static final String TAG = "RecentlyDeletedManager"; + + /** + * 私有构造方法,防止外部实例化 + * @param context 上下文对象 + */ + private RecentlyDeletedManager(Context context) { + mContext = context.getApplicationContext(); + mContentResolver = mContext.getContentResolver(); + } + + /** + * 获取单例实例 + * @param context 上下文对象 + * @return 最近删除管理器实例 + */ + public static synchronized RecentlyDeletedManager getInstance(Context context) { + if (sInstance == null) { + sInstance = new RecentlyDeletedManager(context); + } + return sInstance; + } + + /** + * 获取最近删除的项列表 + * @return 最近删除项的游标,按删除时间倒序排列 + */ + public Cursor getRecentlyDeletedItems() { + // 查询条件:已删除(DELETED_DATE > 0)且位于回收站文件夹 + String selection = NoteColumns.DELETED_DATE + " > 0 AND " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER; + // 按删除时间倒序排序 + String sortOrder = NoteColumns.DELETED_DATE + " DESC"; + + try { + return mContentResolver.query( + Notes.CONTENT_NOTE_URI, + null, // 查询所有列 + selection, + null, + sortOrder + ); + } catch (Exception e) { + Log.e(TAG, "Failed to get recently deleted items", e); + return null; + } + } + + /** + * 恢复指定项 + * @param itemIds 要恢复的项ID数组 + * @return 成功恢复的项数量 + */ + public int restoreItems(long[] itemIds) { + if (itemIds == null || itemIds.length == 0) { + return 0; + } + + int restoredCount = 0; + + for (long itemId : itemIds) { + try { + // 获取原父文件夹ID + String[] projection = {NoteColumns.ORIGIN_PARENT_ID}; + String selection = NoteColumns.ID + "=" + itemId; + + Cursor cursor = mContentResolver.query( + Notes.CONTENT_NOTE_URI, + projection, + selection, + null, + null + ); + + if (cursor != null && cursor.moveToFirst()) { + long originParentId = cursor.getLong(0); + cursor.close(); + + // 如果原父文件夹不存在或已被删除,使用根文件夹 + long targetParentId = originParentId != Notes.ID_TRASH_FOLER ? originParentId : Notes.ID_ROOT_FOLDER; + + // 使用现有的batchMoveToFolder方法来恢复项目 + HashSet ids = new HashSet(); + ids.add(itemId); + if (DataUtils.batchMoveToFolder(mContentResolver, ids, targetParentId)) { + restoredCount++; + } + } else if (cursor != null) { + cursor.close(); + } + } catch (Exception e) { + Log.e(TAG, "Failed to restore item: " + itemId, e); + } + } + + return restoredCount; + } + + /** + * 永久删除指定项 + * @param itemIds 要永久删除的项ID数组 + * @return 成功永久删除的项数量 + */ + public int permanentlyDeleteItems(long[] itemIds) { + if (itemIds == null || itemIds.length == 0) { + return 0; + } + + int deletedCount = 0; + + for (long itemId : itemIds) { + try { + int rowsAffected = mContentResolver.delete( + Notes.CONTENT_NOTE_URI, + NoteColumns.ID + "=" + itemId, + null + ); + + if (rowsAffected > 0) { + deletedCount++; + } + } catch (Exception e) { + Log.e(TAG, "Failed to permanently delete item: " + itemId, e); + } + } + + return deletedCount; + } + + /** + * 清空回收站 + * @return 成功清空的项数量 + */ + public int emptyTrash() { + try { + // 删除所有已删除且位于回收站的项 + String selection = NoteColumns.DELETED_DATE + " > 0 AND " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER; + + return mContentResolver.delete( + Notes.CONTENT_NOTE_URI, + selection, + null + ); + } catch (Exception e) { + Log.e(TAG, "Failed to empty trash", e); + return 0; + } + } + + /** + * 清理超过保留天数的项 + * @param retentionDays 保留天数 + * @return 成功清理的项数量 + */ + public int cleanupOldItems(int retentionDays) { + if (retentionDays < 0) { + retentionDays = DEFAULT_RETENTION_DAYS; + } + + try { + // 计算清理阈值:当前时间减去保留天数(毫秒) + long cleanupThreshold = System.currentTimeMillis() - (retentionDays * 24 * 60 * 60 * 1000); + + // 删除条件:已删除且删除时间小于清理阈值 + String selection = NoteColumns.DELETED_DATE + " > 0 AND " + NoteColumns.DELETED_DATE + " < " + cleanupThreshold; + + return mContentResolver.delete( + Notes.CONTENT_NOTE_URI, + selection, + null + ); + } catch (Exception e) { + Log.e(TAG, "Failed to cleanup old items", e); + return 0; + } + } + + /** + * 启动自动清理任务 + * 注意:此方法在当前实现中仅作为占位符,实际自动清理逻辑由TrashCleanupWorker实现 + */ + public void startAutoCleanup() { + // 自动清理任务由TrashCleanupWorker处理,此处预留接口 + Log.d(TAG, "Auto cleanup task is managed by TrashCleanupWorker"); + } +} \ No newline at end of file diff --git a/src/main/java/net/micode/notes/model/TemplateManager.java b/src/main/java/net/micode/notes/model/TemplateManager.java deleted file mode 100644 index be93fc8..0000000 --- a/src/main/java/net/micode/notes/model/TemplateManager.java +++ /dev/null @@ -1,271 +0,0 @@ -package net.micode.notes.model; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.TextUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -/** - * 模板管理类,用于管理笔记模板的存储、加载、添加、删除等操作 - */ -public class TemplateManager { - private static final String PREF_TEMPLATES = "note_templates"; - private static final String PREF_TEMPLATE_ID_COUNTER = "template_id_counter"; - private static TemplateManager sInstance; - private Context mContext; - private List mTemplates; - - private TemplateManager(Context context) { - mContext = context.getApplicationContext(); - loadTemplates(); - } - - public static synchronized TemplateManager getInstance(Context context) { - if (sInstance == null) { - sInstance = new TemplateManager(context); - } - return sInstance; - } - - /** - * 加载所有模板,包括系统模板和自定义模板 - */ - private void loadTemplates() { - mTemplates = new ArrayList<>(); - - // 先添加系统模板 - addSystemTemplates(); - - // 然后加载自定义模板 - loadCustomTemplates(); - } - - /** - * 添加系统模板 - */ - private void addSystemTemplates() { - // 会议记录模板 - NoteTemplate meetingTemplate = new NoteTemplate(); - meetingTemplate.setId(1); - meetingTemplate.setName("会议记录"); - meetingTemplate.setContent("会议记录

" + - "会议主题
" + - "会议时间
" + - "会议地点
" + - "参会人员
" + - "主持人

" + - "会议议程
" + - "1.
" + - "2.
" + - "3.

" + - "会议内容

" + - "决议事项
" + - "1.
" + - "2.
" + - "3.

" + - "行动项
" + - "任务负责人截止日期状态

" + - "

" + - "下次会议
" + - "时间
" + - "主题
"); - meetingTemplate.setType(NoteTemplate.TYPE_SYSTEM); - mTemplates.add(meetingTemplate); - - // 待办事项模板 - NoteTemplate todoTemplate = new NoteTemplate(); - todoTemplate.setId(2); - todoTemplate.setName("待办事项"); - todoTemplate.setContent("待办事项

" + - "日期

" + - "今日待办
" + - "☐
" + - "☐
" + - "☐
" + - "☐
" + - "☐

" + - "重要事项
" + - "⭐
" + - "⭐

" + - "已完成
" + - "✓
" + - "✓
" + - "✓
"); - todoTemplate.setType(NoteTemplate.TYPE_SYSTEM); - mTemplates.add(todoTemplate); - - // 购物清单模板 - NoteTemplate shoppingTemplate = new NoteTemplate(); - shoppingTemplate.setId(3); - shoppingTemplate.setName("购物清单"); - shoppingTemplate.setContent("购物清单

" + - "日期
" + - "商店
" + - "预算

" + - "清单
" + - "物品数量单价备注状态
" + - " ☐
" + - " ☐
" + - " ☐
" + - " ☐
" + - " ☐

" + - "总计
" + - "实际花费
" + - "节省/超支
"); - shoppingTemplate.setType(NoteTemplate.TYPE_SYSTEM); - mTemplates.add(shoppingTemplate); - } - - /** - * 加载自定义模板 - */ - private void loadCustomTemplates() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - String templatesJson = prefs.getString(PREF_TEMPLATES, "[]"); - - try { - JSONArray jsonArray = new JSONArray(templatesJson); - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject json = jsonArray.getJSONObject(i); - NoteTemplate template = NoteTemplate.fromJson(json); - mTemplates.add(template); - } - } catch (JSONException e) { - e.printStackTrace(); - } - } - - /** - * 保存自定义模板到SharedPreferences - */ - private void saveCustomTemplates() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - SharedPreferences.Editor editor = prefs.edit(); - - JSONArray jsonArray = new JSONArray(); - for (NoteTemplate template : mTemplates) { - if (NoteTemplate.TYPE_CUSTOM.equals(template.getType())) { - try { - jsonArray.put(template.toJson()); - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - - editor.putString(PREF_TEMPLATES, jsonArray.toString()); - editor.apply(); - } - - /** - * 获取所有模板 - */ - public List getAllTemplates() { - return new ArrayList<>(mTemplates); - } - - /** - * 获取系统模板 - */ - public List getSystemTemplates() { - List systemTemplates = new ArrayList<>(); - for (NoteTemplate template : mTemplates) { - if (NoteTemplate.TYPE_SYSTEM.equals(template.getType())) { - systemTemplates.add(template); - } - } - return systemTemplates; - } - - /** - * 获取自定义模板 - */ - public List getCustomTemplates() { - List customTemplates = new ArrayList<>(); - for (NoteTemplate template : mTemplates) { - if (NoteTemplate.TYPE_CUSTOM.equals(template.getType())) { - customTemplates.add(template); - } - } - return customTemplates; - } - - /** - * 根据ID获取模板 - */ - public NoteTemplate getTemplateById(long id) { - for (NoteTemplate template : mTemplates) { - if (template.getId() == id) { - return template; - } - } - return null; - } - - /** - * 添加自定义模板 - */ - public void addCustomTemplate(NoteTemplate template) { - // 生成唯一ID - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - long id = prefs.getLong(PREF_TEMPLATE_ID_COUNTER, 1000); - - template.setId(id); - template.setType(NoteTemplate.TYPE_CUSTOM); - template.setCreateTime(System.currentTimeMillis()); - template.setUpdateTime(System.currentTimeMillis()); - - mTemplates.add(template); - - // 更新ID计数器 - prefs.edit().putLong(PREF_TEMPLATE_ID_COUNTER, id + 1).apply(); - - // 保存自定义模板 - saveCustomTemplates(); - } - - /** - * 删除自定义模板 - */ - public boolean deleteCustomTemplate(long id) { - NoteTemplate templateToRemove = null; - for (NoteTemplate template : mTemplates) { - if (template.getId() == id && NoteTemplate.TYPE_CUSTOM.equals(template.getType())) { - templateToRemove = template; - break; - } - } - - if (templateToRemove != null) { - mTemplates.remove(templateToRemove); - saveCustomTemplates(); - return true; - } - return false; - } - - /** - * 更新自定义模板 - */ - public boolean updateCustomTemplate(NoteTemplate updatedTemplate) { - for (int i = 0; i < mTemplates.size(); i++) { - NoteTemplate template = mTemplates.get(i); - if (template.getId() == updatedTemplate.getId() && - NoteTemplate.TYPE_CUSTOM.equals(template.getType())) { - - updatedTemplate.setUpdateTime(System.currentTimeMillis()); - mTemplates.set(i, updatedTemplate); - saveCustomTemplates(); - return true; - } - } - return false; - } -} diff --git a/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/main/java/net/micode/notes/ui/NoteEditActivity.java index 2777247..184fe3b 100644 --- a/src/main/java/net/micode/notes/ui/NoteEditActivity.java +++ b/src/main/java/net/micode/notes/ui/NoteEditActivity.java @@ -141,8 +141,6 @@ public class NoteEditActivity extends Activity implements OnClickListener, /** 日志标签 */ private static final String TAG = "NoteEditActivity"; - /** 请求选择模板的请求码 */ - private static final int REQUEST_SELECT_TEMPLATE = 100; /** 头部视图持有者 */ private HeadViewHolder mNoteHeaderHolder; @@ -766,43 +764,12 @@ public class NoteEditActivity extends Activity implements OnClickListener, case R.id.menu_unlock: showPasswordDialogForUnlock(); break; - case R.id.menu_template: - // 启动模板选择Activity - Intent intent = new Intent(this, TemplateSelectActivity.class); - getWorkingText(); - intent.putExtra(TemplateSelectActivity.EXTRA_CURRENT_NOTE_CONTENT, mWorkingNote.getContent()); - startActivityForResult(intent, REQUEST_SELECT_TEMPLATE); - break; default: break; } return true; } - /** - * 处理从其他Activity返回的结果 - */ - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == REQUEST_SELECT_TEMPLATE && resultCode == RESULT_OK && data != null) { - // 获取选择的模板内容 - String templateContent = data.getStringExtra(TemplateSelectActivity.EXTRA_TEMPLATE_CONTENT); - if (templateContent != null) { - // 应用模板内容到当前笔记 - mWorkingNote.setWorkingText(templateContent); - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - switchToListMode(templateContent); - } else { - // 解析HTML格式的富文本内容,确保粗体和回车能正确显示 - CharSequence htmlContent = Html.fromHtml(templateContent); - mNoteEditor.setText(getHighlightQueryResult(htmlContent, mUserQuery)); - mNoteEditor.setSelection(mNoteEditor.getText().length()); - } - } - } - } - /** * 设置笔记的提醒时间 *

diff --git a/src/main/java/net/micode/notes/ui/TemplateSelectActivity.java b/src/main/java/net/micode/notes/ui/TemplateSelectActivity.java deleted file mode 100644 index 46999d5..0000000 --- a/src/main/java/net/micode/notes/ui/TemplateSelectActivity.java +++ /dev/null @@ -1,207 +0,0 @@ -package net.micode.notes.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import net.micode.notes.R; -import net.micode.notes.model.NoteTemplate; -import net.micode.notes.model.TemplateManager; - -import java.util.List; - -/** - * 模板选择Activity,用于展示和选择笔记模板 - */ -public class TemplateSelectActivity extends Activity { - public static final String EXTRA_TEMPLATE_CONTENT = "template_content"; - public static final String EXTRA_CURRENT_NOTE_CONTENT = "current_note_content"; - - private RecyclerView mRecyclerView; - private TemplateAdapter mAdapter; - private List mTemplates; - private TemplateManager mTemplateManager; - private String mCurrentNoteContent; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.template_select); - - // 获取当前笔记内容 - mCurrentNoteContent = getIntent().getStringExtra(EXTRA_CURRENT_NOTE_CONTENT); - - // 初始化模板管理器 - mTemplateManager = TemplateManager.getInstance(this); - mTemplates = mTemplateManager.getAllTemplates(); - - // 初始化RecyclerView - mRecyclerView = findViewById(R.id.rv_templates); - mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); - mAdapter = new TemplateAdapter(mTemplates); - mRecyclerView.setAdapter(mAdapter); - - // 初始化按钮点击事件 - findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - findViewById(R.id.btn_save_as_template).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - saveAsTemplate(); - } - }); - } - - /** - * 保存当前笔记作为自定义模板 - */ - private void saveAsTemplate() { - if (TextUtils.isEmpty(mCurrentNoteContent)) { - Toast.makeText(this, R.string.error_note_empty, Toast.LENGTH_SHORT).show(); - return; - } - - // 弹出对话框输入模板名称 - final EditText editText = new EditText(this); - editText.setHint(R.string.enter_template_name); - - new AlertDialog.Builder(this) - .setTitle(R.string.save_as_template) - .setView(editText) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String templateName = editText.getText().toString().trim(); - if (TextUtils.isEmpty(templateName)) { - Toast.makeText(TemplateSelectActivity.this, R.string.error_template_name_empty, Toast.LENGTH_SHORT).show(); - return; - } - - // 创建并保存自定义模板 - NoteTemplate template = new NoteTemplate(); - template.setName(templateName); - template.setContent(mCurrentNoteContent); - template.setType(NoteTemplate.TYPE_CUSTOM); - - mTemplateManager.addCustomTemplate(template); - - // 更新模板列表 - mTemplates = mTemplateManager.getAllTemplates(); - mAdapter = new TemplateAdapter(mTemplates); - mRecyclerView.setAdapter(mAdapter); - - Toast.makeText(TemplateSelectActivity.this, R.string.message_template_saved, Toast.LENGTH_SHORT).show(); - } - }) - .setNegativeButton(android.R.string.cancel, null) - .show(); - } - - /** - * 模板适配器,用于在RecyclerView中展示模板列表 - */ - private class TemplateAdapter extends RecyclerView.Adapter { - private List mTemplates; - - public TemplateAdapter(List templates) { - mTemplates = templates; - } - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.template_item, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(ViewHolder holder, int position) { - final NoteTemplate template = mTemplates.get(position); - - holder.tvTemplateName.setText(template.getName()); - - // 设置模板类型标识 - if (NoteTemplate.TYPE_SYSTEM.equals(template.getType())) { - holder.tvTemplateType.setText(R.string.template_type_system); - holder.ivDelete.setVisibility(View.GONE); - } else { - holder.tvTemplateType.setText(R.string.template_type_custom); - holder.ivDelete.setVisibility(View.VISIBLE); - } - - // 设置点击事件 - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // 返回选择的模板内容 - Intent intent = new Intent(); - intent.putExtra(EXTRA_TEMPLATE_CONTENT, template.getContent()); - setResult(RESULT_OK, intent); - finish(); - } - }); - - // 设置删除按钮点击事件 - holder.ivDelete.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new AlertDialog.Builder(TemplateSelectActivity.this) - .setTitle(R.string.alert_title_delete) - .setMessage(R.string.alert_message_delete_template) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // 删除自定义模板 - mTemplateManager.deleteCustomTemplate(template.getId()); - - // 更新模板列表 - mTemplates.clear(); - mTemplates.addAll(mTemplateManager.getAllTemplates()); - notifyDataSetChanged(); - - Toast.makeText(TemplateSelectActivity.this, R.string.message_template_deleted, Toast.LENGTH_SHORT).show(); - } - }) - .setNegativeButton(android.R.string.cancel, null) - .show(); - } - }); - } - - @Override - public int getItemCount() { - return mTemplates.size(); - } - - public class ViewHolder extends RecyclerView.ViewHolder { - public TextView tvTemplateName; - public TextView tvTemplateType; - public ImageView ivDelete; - - public ViewHolder(View itemView) { - super(itemView); - tvTemplateName = itemView.findViewById(R.id.tv_template_name); - tvTemplateType = itemView.findViewById(R.id.tv_template_type); - ivDelete = itemView.findViewById(R.id.iv_delete); - } - } - } -} diff --git a/src/main/java/net/micode/notes/worker/TrashCleanupWorker.java b/src/main/java/net/micode/notes/worker/TrashCleanupWorker.java index 7af3d13..5efd14f 100644 --- a/src/main/java/net/micode/notes/worker/TrashCleanupWorker.java +++ b/src/main/java/net/micode/notes/worker/TrashCleanupWorker.java @@ -32,6 +32,8 @@ public class TrashCleanupWorker { private static final String TAG = "TrashCleanupWorker"; // 上次清理时间的偏好设置键 private static final String PREF_LAST_CLEANUP_TIME = "last_trash_cleanup_time"; + // 回收站保留天数的偏好设置键 + private static final String PREF_TRASH_RETENTION_DAYS = "pref_key_trash_retention_days"; /** * 执行清理任务 @@ -50,10 +52,15 @@ public class TrashCleanupWorker { return; } - // 获取保留天数设置,从用户偏好中读取,默认30天 - String retentionDaysStr = prefs.getString("pref_trash_retention_days", - String.valueOf(RecentlyDeletedManager.DEFAULT_RETENTION_DAYS)); - int retentionDays = Integer.parseInt(retentionDaysStr); + // 获取用户设置的保留天数 + int retentionDays = RecentlyDeletedManager.DEFAULT_RETENTION_DAYS; + try { + String retentionDaysStr = prefs.getString(PREF_TRASH_RETENTION_DAYS, String.valueOf(RecentlyDeletedManager.DEFAULT_RETENTION_DAYS)); + retentionDays = Integer.parseInt(retentionDaysStr); + } catch (NumberFormatException e) { + Log.e(TAG, "Invalid retention days setting, using default value", e); + retentionDays = RecentlyDeletedManager.DEFAULT_RETENTION_DAYS; + } // 执行清理 RecentlyDeletedManager manager = RecentlyDeletedManager.getInstance(context); diff --git a/src/main/res/drawable/template_item_bg.xml b/src/main/res/drawable/template_item_bg.xml deleted file mode 100644 index 15117c7..0000000 --- a/src/main/res/drawable/template_item_bg.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/src/main/res/drawable/template_type_bg.xml b/src/main/res/drawable/template_type_bg.xml deleted file mode 100644 index 94af0a3..0000000 --- a/src/main/res/drawable/template_type_bg.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - diff --git a/src/main/res/layout/template_item.xml b/src/main/res/layout/template_item.xml deleted file mode 100644 index 0834bb4..0000000 --- a/src/main/res/layout/template_item.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - diff --git a/src/main/res/layout/template_select.xml b/src/main/res/layout/template_select.xml deleted file mode 100644 index e444f96..0000000 --- a/src/main/res/layout/template_select.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - -