解决合并冲突问题

pull/25/head
陶俊宇 1 month ago
parent 672abc00e6
commit 4f078b40cd

@ -48,7 +48,7 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
</intent-filter >>
<intent-filter >
<action android:name="android.intent.action.INSERT_OR_EDIT" />
@ -67,13 +67,6 @@
android:resource="@xml/searchable" />
</activity>
<activity
android:name=".ui.TemplateSelectActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/NoteTheme"
android:exported="false">
</activity>
<provider
android:name="net.micode.notes.data.NotesProvider"

@ -264,6 +264,13 @@ public class Notes {
* <P> 0便1 </P>
*/
public static final String LOCK_TYPE = "lock_type";
/**
* 便
* <P> : INTEGER (long) </P>
* <P> 0 </P>
*/
public static final String DELETED_DATE = "deleted_date";
}
public interface DataColumns {

@ -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");
}
}

@ -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

@ -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;
}
}

@ -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<Long> ids = new HashSet<Long>();
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");
}
}

@ -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<NoteTemplate> 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("<strong>会议记录</strong><br><br>" +
"<strong>会议主题</strong><br>" +
"<strong>会议时间</strong><br>" +
"<strong>会议地点</strong><br>" +
"<strong>参会人员</strong><br>" +
"<strong>主持人</strong><br><br>" +
"<strong>会议议程</strong><br>" +
"1. <br>" +
"2. <br>" +
"3. <br><br>" +
"<strong>会议内容</strong><br><br>" +
"<strong>决议事项</strong><br>" +
"1. <br>" +
"2. <br>" +
"3. <br><br>" +
"<strong>行动项</strong><br>" +
"<strong>任务</strong><strong>负责人</strong><strong>截止日期</strong><strong>状态</strong><br><br>" +
"<br><br>" +
"<strong>下次会议</strong><br>" +
"<strong>时间</strong><br>" +
"<strong>主题</strong><br>");
meetingTemplate.setType(NoteTemplate.TYPE_SYSTEM);
mTemplates.add(meetingTemplate);
// 待办事项模板
NoteTemplate todoTemplate = new NoteTemplate();
todoTemplate.setId(2);
todoTemplate.setName("待办事项");
todoTemplate.setContent("<strong>待办事项</strong><br><br>" +
"<strong>日期</strong><br><br>" +
"<strong>今日待办</strong><br>" +
"☐ <br>" +
"☐ <br>" +
"☐ <br>" +
"☐ <br>" +
"☐ <br><br>" +
"<strong>重要事项</strong><br>" +
"⭐ <br>" +
"⭐ <br><br>" +
"<strong>已完成</strong><br>" +
"✓ <br>" +
"✓ <br>" +
"✓ <br>");
todoTemplate.setType(NoteTemplate.TYPE_SYSTEM);
mTemplates.add(todoTemplate);
// 购物清单模板
NoteTemplate shoppingTemplate = new NoteTemplate();
shoppingTemplate.setId(3);
shoppingTemplate.setName("购物清单");
shoppingTemplate.setContent("<strong>购物清单</strong><br><br>" +
"<strong>日期</strong><br>" +
"<strong>商店</strong><br>" +
"<strong>预算</strong><br><br>" +
"<strong>清单</strong><br>" +
"<strong>物品</strong><strong>数量</strong><strong>单价</strong><strong>备注</strong><strong>状态</strong><br>" +
" ☐ <br>" +
" ☐ <br>" +
" ☐ <br>" +
" ☐ <br>" +
" ☐ <br><br>" +
"<strong>总计</strong><br>" +
"<strong>实际花费</strong><br>" +
"<strong>节省/超支</strong><br>");
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<NoteTemplate> getAllTemplates() {
return new ArrayList<>(mTemplates);
}
/**
*
*/
public List<NoteTemplate> getSystemTemplates() {
List<NoteTemplate> systemTemplates = new ArrayList<>();
for (NoteTemplate template : mTemplates) {
if (NoteTemplate.TYPE_SYSTEM.equals(template.getType())) {
systemTemplates.add(template);
}
}
return systemTemplates;
}
/**
*
*/
public List<NoteTemplate> getCustomTemplates() {
List<NoteTemplate> 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;
}
}

@ -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());
}
}
}
}
/**
*
* <p>

@ -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<NoteTemplate> 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<TemplateAdapter.ViewHolder> {
private List<NoteTemplate> mTemplates;
public TemplateAdapter(List<NoteTemplate> 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);
}
}
}
}

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

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="#E0E0E0" />
<stroke
android:width="1dp"
android:color="#BDBDBD" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="#FFFFFF" />
<stroke
android:width="1dp"
android:color="#BDBDBD" />
</shape>
</item>
</selector>

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="12dp" />
<solid android:color="#F0F0F0" />
<stroke
android:width="1dp"
android:color="#E0E0E0" />
</shape>

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp"
android:background="@drawable/template_item_bg"
android:layout_marginBottom="8dp"
android:gravity="center_vertical">
<!-- 模板名称 -->
<TextView
android:id="@+id/tv_template_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="16sp"
android:textColor="@android:color/black"
android:fontFamily="sans-serif-medium" />
<!-- 模板类型标识 -->
<TextView
android:id="@+id/tv_template_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:textSize="12sp"
android:textColor="@android:color/secondary_text_light"
android:background="@drawable/template_type_bg"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:text="@string/template_type_system" />
<!-- 仅自定义模板显示删除按钮 -->
<ImageView
android:id="@+id/iv_delete"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="8dp"
android:src="@android:drawable/ic_menu_delete"
android:tint="@android:color/darker_gray"
android:visibility="gone" />
</LinearLayout>

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 标题栏 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="?android:attr/colorPrimary"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/menu_template"
android:textSize="20sp"
android:textColor="@android:color/white"
android:fontFamily="sans-serif-medium" />
<Button
android:id="@+id/btn_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/cancel"
android:textColor="@android:color/white"
android:background="@null" />
</LinearLayout>
<!-- 模板列表 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_templates"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="16dp" />
<!-- 添加自定义模板按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<Button
android:id="@+id/btn_save_as_template"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/save_as_template"
android:background="?android:attr/colorPrimary"
android:textColor="@android:color/white"
android:padding="12dp"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>

@ -57,8 +57,4 @@
<item
android:id="@+id/menu_unlock"
android:title="@string/menu_unlock" />
<item
android:id="@+id/menu_template"
android:title="@string/menu_template" />
</menu>

@ -22,6 +22,12 @@
android:title="@string/menu_move"
android:icon="@drawable/menu_move"
android:showAsAction="always|withText" />
<item
android:id="@+id/restore"
android:title="Restore"
android:icon="@drawable/menu_move"
android:showAsAction="always|withText" />
<item
android:id="@+id/delete"

@ -28,4 +28,25 @@
<item>Messaging</item>
<item>Email</item>
</string-array>
<!-- Trash retention days -->
<string-array name="trash_retention_days_entries">
<item>1 day</item>
<item>3 days</item>
<item>7 days</item>
<item>14 days</item>
<item>30 days (default)</item>
<item>60 days</item>
<item>90 days</item>
</string-array>
<string-array name="trash_retention_days_values">
<item>1</item>
<item>3</item>
<item>7</item>
<item>14</item>
<item>30</item>
<item>60</item>
<item>90</item>
</string-array>
</resources>

@ -52,21 +52,11 @@
<string name="menu_unpin">Unpin</string>
<string name="menu_lock">Lock</string>
<string name="menu_unlock">Unlock</string>
<string name="menu_template">Note Template</string>
<string name="save_as_template">Save as Template</string>
<string name="template_type_system">System Template</string>
<string name="template_type_custom">Custom Template</string>
<string name="dialog_enter_password">Enter Password</string>
<string name="hint_enter_password">Please enter password</string>
<string name="error_wrong_password">Incorrect password</string>
<string name="message_note_locked">Note locked successfully</string>
<string name="message_note_unlocked">Note unlocked successfully</string>
<string name="enter_template_name">Enter Template Name</string>
<string name="error_note_empty">Note is empty</string>
<string name="error_template_name_empty">Template name cannot be empty</string>
<string name="message_template_saved">Template saved successfully</string>
<string name="message_template_deleted">Template deleted successfully</string>
<string name="alert_message_delete_template">Are you sure you want to delete this template?</string>
<string name="menu_select_title">%d selected</string>
<string name="menu_select_none">Nothing selected, the operation is invalid</string>
<string name="menu_select_all">Select all</string>
@ -93,6 +83,7 @@
<string name="alert_title_delete">Delete selected notes</string>
<string name="alert_message_delete_notes">Confirm to delete the selected %d notes?</string>
<string name="alert_message_delete_note">Confirm to delete this note?</string>
<string name="alert_message_delete_notes_permanently">Confirm to permanently delete the selected %d notes?</string>
<string name="format_move_notes_to_folder">Have moved selected %1$d notes to %2$s folder</string>
<!-- Error information -->
<string name="error_sdcard_unmounted">SD card busy, not available now</string>
@ -134,10 +125,14 @@
<string name="preferences_toast_cannot_change_account">Cannot change the account because sync is in progress</string>
<string name="preferences_toast_success_set_accout">%1$s has been set as the sync account</string>
<string name="preferences_bg_random_appear_title">New note background color random</string>
<string name="preferences_trash_retention_days_title">Trash retention days</string>
<string name="preferences_trash_retention_days_summary">Number of days to keep deleted items before automatic cleanup</string>
<string name="preferences_trash_retention_days_dialog_title">Select retention days</string>
<string name="button_delete">Delete</string>
<string name="call_record_folder_name">Call notes</string>
<string name="hint_foler_name">Input name</string>
<string name="deleted_time_format">Deleted %s</string>
<string name="search_label">Searching Notes</string>
<string name="search_hint">Search notes</string>

@ -27,4 +27,15 @@
android:title="@string/preferences_bg_random_appear_title"
android:defaultValue="false" />
</PreferenceCategory>
<PreferenceCategory>
<ListPreference
android:key="pref_key_trash_retention_days"
android:title="@string/preferences_trash_retention_days_title"
android:summary="@string/preferences_trash_retention_days_summary"
android:dialogTitle="@string/preferences_trash_retention_days_dialog_title"
android:entries="@array/trash_retention_days_entries"
android:entryValues="@array/trash_retention_days_values"
android:defaultValue="30" />
</PreferenceCategory>
</PreferenceScreen>

@ -21,7 +21,7 @@
android:hint="@string/search_hint"
android:searchMode="queryRewriteFromText"
android:searchSuggestAuthority="notes"
android:searchSuggestAuthority="micode_notes"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:searchSettingsDescription="@string/search_setting_description"
android:includeInGlobalSearch="true" />

Loading…
Cancel
Save