mx #2

Closed
poyt3a5hz wants to merge 0 commits from xiaomibianqian-maxaingru into Watchdog-lyl

@ -1,73 +1,78 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
/*//如果查询结果不为空且有数据
* 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//如果查询结果不为空且有数据//如果查询结果不为空且有数据
*
* 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//如果查询结果不为空且有数据
*
* 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.data;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
import android.telephony.PhoneNumberUtils;
import android.util.Log;
import java.util.HashMap;
public class Contact {
private static HashMap<String, String> sContactCache;
private static final String TAG = "Contact";
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id "
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
public static String getContact(Context context, String phoneNumber) {
if(sContactCache == null) {
sContactCache = new HashMap<String, String>();
}
if(sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber);
}
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
selection,
new String[] { phoneNumber },
null);
* 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.data; // 定义包名
//如果查询结果不为空且有数据
import android.content.Context; // 导入Context类
import android.database.Cursor; // 导入Cursor类
import android.provider.ContactsContract.CommonDataKinds.Phone; // 导入Phone类
import android.provider.ContactsContract.Data; // 导入Data类
import android.telephony.PhoneNumberUtils; // 导入PhoneNumberUtils类
import android.util.Log; // 导入Log类
// 如果查询结果不为空且有数据
import java.util.HashMap; // 导入HashMap类
// 如果查询结果不为空且有数据
public class Contact {//如果查询结果不为空且有数据
private static HashMap<String, String> sContactCache; // 定义一个静态HashMap用于缓存联系人信息
private static final String TAG = "Contact"; // 定义日志标签// 如果查询结果不为空且有数据
if (cursor != null && cursor.moveToFirst()) {
try {
String name = cursor.getString(0);
sContactCache.put(phoneNumber, name);
return name;
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, " Cursor get string error " + e.toString());
return null;
} finally {
cursor.close();
}
} else {
Log.d(TAG, "No contact matched with number:" + phoneNumber);
return null;
}
}
}
// 定义查询条件字符串,用于匹配电话号码// 如果查询结果不为空且有数据
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER// 如果查询结果不为空且有数据
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"// 如果查询结果不为空且有数据
+ " AND " + Data.RAW_CONTACT_ID + " IN "// 如果查询结果不为空且有数据
+ "(SELECT raw_contact_id "// 如果查询结果不为空且有数据
+ " FROM phone_lookup"// 如果查询结果不为空且有数据
+ " WHERE min_match = '+')";// 如果查询结果不为空且有数据
//如果查询结果不为空且有数据
// 获取联系人信息的方法// 如果查询结果不为空且有数据
public static String getContact(Context context, String phoneNumber) {// 如果查询结果不为空且有数据
if(sContactCache == null) { // 如果缓存为空,则初始化
sContactCache = new HashMap<String, String>();// 如果查询结果不为空且有数据
}// 如果查询结果不为空且有数据
// 如果查询结果不为空且有数据
if(sContactCache.containsKey(phoneNumber)) { // 如果缓存中已存在该电话号码,直接返回缓存的联系人姓名
return sContactCache.get(phoneNumber);// 如果查询结果不为空且有数据
}// 如果查询结果不为空且有数据
// 如果查询结果不为空且有数据
// 替换查询条// 如果查询结果不为空且有数据件中的占位符
String selection = CALLER_ID_SELECTION.replace("+",// 如果查询结果不为空且有数据
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));// 如果查询结果不为空且有数据
// 查询联系人信息
Cursor cursor = context.getContentResolver().query(// 如果查询结果不为空且有数据
Data.CONTENT_URI,// 如果查询结果不为空且有数据
new String [] { Phone.DISPLAY_NAME },// 如果查询结果不为空且有数据
selection,// 如果查询结果不为空且有数据
new String[] { phoneNumber },// 如果查询结果不为空且有数据
null);// 如果查询结果不为空且有数据
//如果查询结果不为空且有数据
if (cursor != null && cursor.moveToFirst()) { // 如果查询结果不为空且有数据
try {//如果查询结果不为空且有数据
String name = cursor.getString(0); // 获取联系人姓名
sContactCache.put(phoneNumber, name); // 将联系人信息缓存
return name; // 返回联系人姓名
} catch (IndexOutOfBoundsException e) { // 捕获异常
Log.e(TAG, " Cursor get string error " + e.toString()); // 打印错误日志
return null; // 返回空
} finally {// 返回空
cursor.close(); // 关闭游标
}// 返回空
} else {// 返回空
Log.d(TAG, "No contact matched with number:" + phoneNumber); // 打印未匹配到联系人日志
return null; // 返回空
}// 返回空
}// 返回空
}// 返回空
//如果查询结果不为空且有数据

@ -1,40 +1,26 @@
/*
* 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.data; // 定义该类所在的包名
package net.micode.notes.data;
import android.net.Uri; // 导入Android的Uri类
import android.net.Uri;
// 定义一个公共类 Notes用于管理笔记应用中的常量和数据结构
public class Notes {
// 定义权限名,用于内容提供者的访问
public static final String AUTHORITY = "micode_notes";
// 定义日志标签名,便于调试
public static final String TAG = "Notes";
public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2;
/**
* Following IDs are system folders' identifiers
* {@link Notes#ID_ROOT_FOLDER } is default folder
* {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder
* {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records
*/
public static final int ID_ROOT_FOLDER = 0;
public static final int ID_TEMPARAY_FOLDER = -1;
public static final int ID_CALL_RECORD_FOLDER = -2;
public static final int ID_TRASH_FOLER = -3;
// 定义笔记类型:普通笔记、文件夹、系统类型
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 ID_ROOT_FOLDER = 0; // 根文件夹的ID
public static final int ID_TEMPARAY_FOLDER = -1; // 临时文件夹的ID
public static final int ID_CALL_RECORD_FOLDER = -2; // 通话记录文件夹的ID
public static final int ID_TRASH_FOLER = -3; // 垃圾箱文件夹的ID
// 定义各种Intent额外数据的key
public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date";
public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id";
public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id";
@ -42,238 +28,74 @@ public class Notes {
public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id";
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date";
public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0;
public static final int TYPE_WIDGET_4X = 1;
// 定义Widget类型
public static final int TYPE_WIDGET_INVALIDE = -1; // 无效Widget类型
public static final int TYPE_WIDGET_2X = 0; // 2x的Widget类型
public static final int TYPE_WIDGET_4X = 1; // 4x的Widget类型
// 定义数据常量类
public static class DataConstants {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
// 定义文本笔记类型和通话笔记类型
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; // 文本笔记类型
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; // 通话笔记类型
}
/**
* Uri to query all notes and folders
*/
// 定义访问所有笔记和文件夹的Uri
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note");
/**
* Uri to query data
*/
// 定义访问数据的Uri
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");
// 定义笔记的列名接口
public interface NoteColumns {
/**
* The unique ID for a row
* <P> Type: INTEGER (long) </P>
*/
public static final String ID = "_id";
/**
* The parent's id for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String PARENT_ID = "parent_id";
/**
* Created data for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String CREATED_DATE = "created_date";
/**
* Latest modified date
* <P> Type: INTEGER (long) </P>
*/
public static final String MODIFIED_DATE = "modified_date";
/**
* Alert date
* <P> Type: INTEGER (long) </P>
*/
public static final String ALERTED_DATE = "alert_date";
/**
* Folder's name or text content of note
* <P> Type: TEXT </P>
*/
public static final String SNIPPET = "snippet";
/**
* Note's widget id
* <P> Type: INTEGER (long) </P>
*/
public static final String WIDGET_ID = "widget_id";
/**
* Note's widget type
* <P> Type: INTEGER (long) </P>
*/
public static final String WIDGET_TYPE = "widget_type";
/**
* Note's background color's id
* <P> Type: INTEGER (long) </P>
*/
public static final String BG_COLOR_ID = "bg_color_id";
/**
* For text note, it doesn't has attachment, for multi-media
* note, it has at least one attachment
* <P> Type: INTEGER </P>
*/
public static final String HAS_ATTACHMENT = "has_attachment";
/**
* Folder's count of notes
* <P> Type: INTEGER (long) </P>
*/
public static final String NOTES_COUNT = "notes_count";
/**
* The file type: folder or note
* <P> Type: INTEGER </P>
*/
public static final String TYPE = "type";
/**
* The last sync id
* <P> Type: INTEGER (long) </P>
*/
public static final String SYNC_ID = "sync_id";
/**
* Sign to indicate local modified or not
* <P> Type: INTEGER </P>
*/
public static final String LOCAL_MODIFIED = "local_modified";
/**
* Original parent id before moving into temporary folder
* <P> Type : INTEGER </P>
*/
public static final String ORIGIN_PARENT_ID = "origin_parent_id";
/**
* The gtask id
* <P> Type : TEXT </P>
*/
public static final String GTASK_ID = "gtask_id";
/**
* The version code
* <P> Type : INTEGER (long) </P>
*/
public static final String VERSION = "version";
public static final String ID = "_id"; // 每行的唯一ID
public static final String PARENT_ID = "parent_id"; // 父ID文件夹的ID或上级ID
public static final String CREATED_DATE = "created_date"; // 创建日期
public static final String MODIFIED_DATE = "modified_date"; // 最后修改日期
public static final String ALERTED_DATE = "alert_date"; // 提醒日期
public static final String SNIPPET = "snippet"; // 文件夹名称或笔记文本内容
public static final String WIDGET_ID = "widget_id"; // Widget的ID
public static final String WIDGET_TYPE = "widget_type"; // Widget的类型
public static final String BG_COLOR_ID = "bg_color_id"; // 背景颜色ID
public static final String HAS_ATTACHMENT = "has_attachment"; // 是否有附件
public static final String NOTES_COUNT = "notes_count"; // 文件夹内笔记数量
public static final String TYPE = "type"; // 文件类型(笔记或文件夹)
public static final String SYNC_ID = "sync_id"; // 同步ID
public static final String LOCAL_MODIFIED = "local_modified"; // 是否本地修改
public static final String ORIGIN_PARENT_ID = "origin_parent_id"; // 移动前的父ID
public static final String GTASK_ID = "gtask_id"; // 任务ID
public static final String VERSION = "version"; // 版本号
}
// 定义数据列的接口
public interface DataColumns {
/**
* The unique ID for a row
* <P> Type: INTEGER (long) </P>
*/
public static final String ID = "_id";
/**
* The MIME type of the item represented by this row.
* <P> Type: Text </P>
*/
public static final String MIME_TYPE = "mime_type";
/**
* The reference id to note that this data belongs to
* <P> Type: INTEGER (long) </P>
*/
public static final String NOTE_ID = "note_id";
/**
* Created data for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String CREATED_DATE = "created_date";
/**
* Latest modified date
* <P> Type: INTEGER (long) </P>
*/
public static final String MODIFIED_DATE = "modified_date";
/**
* Data's content
* <P> Type: TEXT </P>
*/
public static final String CONTENT = "content";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA1 = "data1";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA2 = "data2";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA3 = "data3";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA4 = "data4";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA5 = "data5";
public static final String ID = "_id"; // 数据的唯一ID
public static final String MIME_TYPE = "mime_type"; // 数据的MIME类型
public static final String NOTE_ID = "note_id"; // 数据所属的笔记ID
public static final String CREATED_DATE = "created_date"; // 数据创建日期
public static final String MODIFIED_DATE = "modified_date"; // 数据最后修改日期
public static final String CONTENT = "content"; // 数据内容
public static final String DATA1 = "data1"; // 通用数据列1
public static final String DATA2 = "data2"; // 通用数据列2
public static final String DATA3 = "data3"; // 通用数据列3
public static final String DATA4 = "data4"; // 通用数据列4
public static final String DATA5 = "data5"; // 通用数据列5
}
// 定义文本笔记类
public static final class TextNote implements DataColumns {
/**
* Mode to indicate the text in check list mode or not
* <P> Type: Integer 1:check list mode 0: normal mode </P>
*/
public static final String MODE = DATA1;
public static final int MODE_CHECK_LIST = 1;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");
public static final String MODE = DATA1; // 模式字段:是否为检查列表模式
public static final int MODE_CHECK_LIST = 1; // 检查列表模式
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; // 内容类型:多个文本笔记
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; // 内容类型:单个文本笔记
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); // 文本笔记的访问Uri
}
// 定义通话笔记类
public static final class CallNote implements DataColumns {
/**
* Call date for this record
* <P> Type: INTEGER (long) </P>
*/
public static final String CALL_DATE = DATA1;
/**
* Phone number for this record
* <P> Type: TEXT </P>
*/
public static final String PHONE_NUMBER = DATA3;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
public static final String CALL_DATE = DATA1; // 通话日期字段
public static final String PHONE_NUMBER = DATA3; // 电话号码字段
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; // 内容类型:多个通话笔记
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; // 内容类型:单个通话笔记
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); // 通话笔记的访问Uri
}
}

@ -1,362 +1,287 @@
/*
* 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.data; // 包声明
package net.micode.notes.data;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import android.content.ContentValues; // 导入ContentValues类
import android.content.Context; // 导入Context类
import android.database.sqlite.SQLiteDatabase; // 导入SQLiteDatabase类
import android.database.sqlite.SQLiteOpenHelper; // 导入SQLiteOpenHelper类
import android.util.Log; // 导入Log类
import net.micode.notes.data.Notes.DataColumns; // 导入DataColumns类
import net.micode.notes.data.Notes.DataConstants; // 导入DataConstants类
import net.micode.notes.data.Notes.NoteColumns; // 导入NoteColumns类
// Notes数据库帮助类
public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 4;
private static final String DB_NAME = "note.db"; // 定义数据库名称
private static final int DB_VERSION = 4; // 定义数据库版本号
// 表名接口
public interface TABLE {
public static final String NOTE = "note";
public static final String DATA = "data";
public static final String NOTE = "note"; // 笔记表名
public static final String DATA = "data"; // 数据表名
}
private static final String TAG = "NotesDatabaseHelper";
private static final String TAG = "NotesDatabaseHelper"; // 用于日志输出的TAG
private static NotesDatabaseHelper mInstance;
private static NotesDatabaseHelper mInstance; // 定义数据库帮助类的实例
// 创建笔记表的SQL语句
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA1 + " INTEGER," +
DataColumns.DATA2 + " INTEGER," +
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")";
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
/**
* Increase folder's note count when move note to the folder
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* Decrease folder's note count when move note from folder
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_update " +
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" END";
/**
* Increase folder's note count when insert new note to the folder
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_insert " +
" AFTER INSERT ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* Decrease folder's note count when delete note from the folder
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END";
/**
* Update note's content when insert data with type {@link DataConstants#NOTE}
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " +
" AFTER INSERT ON " + TABLE.DATA +
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has changed
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER update_note_content_on_update " +
" AFTER UPDATE ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
"CREATE TRIGGER update_note_content_on_delete " +
" AFTER delete ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";
/**
* Delete datas belong to note which has been deleted
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.DATA +
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* Delete notes belong to folder which has been deleted
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.NOTE +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* Move notes belong to folder which has been moved to trash folder
*/
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
"CREATE TRIGGER folder_move_notes_on_trash " +
" AFTER UPDATE ON " + TABLE.NOTE +
" WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
"CREATE TABLE " + TABLE.NOTE + "(" + // 创建笔记表
NoteColumns.ID + " INTEGER PRIMARY KEY," + // 笔记ID主键
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 父级笔记ID默认为0
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + // 提醒日期默认为0
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + // 背景色ID默认为0
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期,默认为当前时间戳
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + // 是否有附件默认为0
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期,默认为当前时间戳
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + // 笔记数量默认为0
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + // 笔记摘要,默认为空字符串
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + // 笔记类型默认为0
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + // 小部件ID默认为0
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + // 小部件类型,默认为-1
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + // 同步ID默认为0
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + // 本地修改标志默认为0
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 原父级ID默认为0
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + // GTASK ID默认为空字符串
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + // 笔记版本号默认为0
")"; // 结束创建表的SQL语句
// 创建触发器SQL
// 创建数据表的SQL语句
private static final String CREATE_DATA_TABLE_SQL =// 创建触发器SQL
"CREATE TABLE " + TABLE.DATA + "(" + // 创建数据表
DataColumns.ID + " INTEGER PRIMARY KEY," + // 数据ID主键
DataColumns.MIME_TYPE + " TEXT NOT NULL," + // MIME类型
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + // 笔记ID默认为0
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期,默认为当前时间戳
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期,默认为当前时间戳
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + // 内容,默认为空字符串
DataColumns.DATA1 + " INTEGER," + // 数据字段1
DataColumns.DATA2 + " INTEGER," + // 数据字段2
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + // 数据字段3默认为空字符串
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + // 数据字段4默认为空字符串
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + // 数据字段5默认为空字符串
")"; // 结束创建数据表的SQL语句// 创建触发器SQL
// 创建触发器SQL
// 创建数据表的NOTE_ID索引// 创建触发器SQL
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =// 创建触发器SQL
"CREATE INDEX IF NOT EXISTS note_id_index ON " +// 创建触发器SQL
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; // 创建数据表的NOTE_ID索引
// 创建触发器SQL
// 创建触发器更新笔记的父级ID时增加父文件夹的笔记数// 创建触发器SQL
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER increase_folder_count_on_update " +// 创建触发器SQL
" AFTER UPDATE OF " + eColumns.PARENT_ID + " ON " + TABLE.NOTE +// 创建触发器SQL
" BEGIN " +// 创建触发器SQL
" UPDATE " + TABLE.NOTE +// 创建触发器SQL// 创建触发器SQL// 创建触发器SQL
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +// 创建触发器SQL
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +// 创建触发器SQL// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器SQL
// 创建触发器更新笔记的父级ID时减少父文件夹的笔记数
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER decrease_folder_count_on_update " +// 创建触发器SQL
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +// 创建触发器SQL
" BEGIN " +// 创建触发器SQL// 创建触发器SQL
" UPDATE " + TABLE.NOTE +// 创建触发器SQL
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +// 创建触发器SQL
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +// 创建触发器SQL
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:插入笔记时增加父文件夹的笔记数
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER increase_folder_count_on_insert " +// 创建触发器SQL
" AFTER INSERT ON " + TABLE.NOTE +// 创建触发器SQL
" BEGIN " +// 创建触发器SQL
" UPDATE " + TABLE.NOTE +// 创建触发器SQL
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +// 创建触发器SQL
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:删除笔记时减少父文件夹的笔记数
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER decrease_folder_count_on_delete " +// 创建触发器SQL
" AFTER DELETE ON " + TABLE.NOTE +// 创建触发器SQL
" BEGIN " +// 创建触发器SQL
" UPDATE " + TABLE.NOTE +// 创建触发器SQL
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +// 创建触发器SQL
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +// 创建触发器SQL
" AND " + NoteColumns.NOTES_COUNT + ">0;" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:插入数据时更新笔记的摘要
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER update_note_content_on_insert " +// 创建触发器SQL
" AFTER INSERT ON " + TABLE.DATA +// 创建触发器SQL
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +// 创建触发器SQL
" BEGIN" +// 创建触发器SQL
" UPDATE " + TABLE.NOTE +// 创建触发器SQL
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +// 创建触发器SQL
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:更新数据时更新笔记的摘要
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER update_note_content_on_update " +// 创建触发器SQL// 创建触发器SQL
" AFTER UPDATE ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +// 创建触发器SQL
" BEGIN" +// 创建触发器SQL
" UPDATE " + TABLE.NOTE +// 创建触发器SQL
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +// 创建触发器SQL
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:删除数据时更新笔记的摘要
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER update_note_content_on_delete " +// 创建触发器SQL
" AFTER delete ON " + TABLE.DATA +// 创建触发器SQL
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +// 创建触发器SQL
" BEGIN" +
" UPDATE " + TABLE.NOTE +// 创建触发器SQL
" SET " + NoteColumns.SNIPPET + "=''" +// 创建触发器SQL
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:删除笔记时删除相关的数据
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER delete_data_on_delete " +// 创建触发器SQL
" AFTER DELETE ON " + TABLE.NOTE +// 创建触发器SQL
" BEGIN" +// 创建触发器SQL
" DELETE FROM " + TABLE.DATA +// 创建触发器SQL
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:删除文件夹时删除该文件夹中的所有笔记
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER folder_delete_notes_on_delete " +// 创建触发器SQL
" AFTER DELETE ON " + TABLE.NOTE +// 创建触发器SQL
" BEGIN" +// 创建触发器SQL
" DELETE FROM " + TABLE.NOTE +// 创建触发器SQL
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 创建触发器:移动文件夹到回收站时移动所有笔记到回收站
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =// 创建触发器SQL
"CREATE TRIGGER folder_move_notes_on_trash " +// 创建触发器SQL
" AFTER UPDATE ON " + TABLE.NOTE +// 创建触发器SQL
" WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +// 创建触发器SQL
" BEGIN" +// 创建触发器SQL
" UPDATE " + TABLE.NOTE +// 创建触发器SQL
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +// 创建触发器SQL
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +// 创建触发器SQL
" END"; // 创建触发器SQL
// 构造函数,初始化数据库帮助类
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
super(context, DB_NAME, null, DB_VERSION); // 调用父类的构造函数,指定数据库名称和版本
}
// 创建笔记表
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}
private void reCreateNoteTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete");
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(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER);
db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
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);
}
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
/**
* call record foler for call notes
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* root folder which is default folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* temporary folder which is used for moving note
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* create trash folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
db.execSQL(CREATE_NOTE_TABLE_SQL); // 执行创建笔记表的SQL语句
reCreateNoteTableTriggers(db); // 创建触发器
}
// 创建数据表
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
Log.d(TAG, "data table has been created");
}
private void reCreateDataTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
return mInstance;
db.execSQL(CREATE_DATA_TABLE_SQL); // 执行创建数据表的SQL语句
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); // 创建数据表的索引
Log.d(TAG, "data table has been created"); // 打印日志
}
// 执行数据库创建操作
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
createNoteTable(db); // 创建笔记表
createDataTable(db); // 创建数据表
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.d(TAG, "onUpgrade: " + oldVersion + " --> " + newVersion); // 打印日志
// 根据版本号升级数据库
if (oldVersion == 1) {
db.execSQL(CREATE_DATA_TABLE_SQL); // 创建数据表
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); // 创建索引
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); // 创建触发器
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); // 创建触发器
}
if (oldVersion <= 3) {
createNoteTable(db); // 创建笔记表
reCreateNoteTableTriggers(db); // 创建触发器
}
}
// 执行数据库升级操作
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
boolean skipV2 = false;
boolean reCreateTriggers = false; // 是否需要重新创建触发器的标志
boolean skipV2 = false; // 是否跳过V2升级的标志
// 如果当前数据库版本是1进行从V1升级到V2的操作
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
upgradeToV2(db); // 执行V1到V2的升级
skipV2 = true; // 跳过V2到V3的升级
oldVersion++; // 更新数据库版本为2
}
// 如果当前数据库版本是2且没有跳过V2升级
if (oldVersion == 2 && !skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
upgradeToV3(db); // 执行V2到V3的升级
reCreateTriggers = true; // 标记需要重新创建触发器
oldVersion++; // 更新数据库版本为3
}
// 如果当前数据库版本是3执行V3到V4的升级
if (oldVersion == 3) {
upgradeToV4(db);
oldVersion++;
}
upgradeToV4(db); // 执行V3到V4的升级
oldVersion++; // 更新数据库版本为4
}// 添加VERSION列默认为0
// 如果需要重新创建触发器,执行重新创建触发器的操作
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
reCreateNoteTableTriggers(db); // 重新创建笔记表的触发器
reCreateDataTableTriggers(db); // 重新创建数据表的触发器
}
// 如果升级后的版本不等于目标版本,抛出异常
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
}
}
throw new IllegalStateException("Upgrade notes database to version " + newVersion// 添加VERSION列默认为0
+ " fails"); // 升级失败抛出异常
}// 添加VERSION列默认为0
}// 添加VERSION列默认为0
// 添加VERSION列默认为0
// 从V1升级到V2
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
createNoteTable(db);
createDataTable(db);
}
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); // 删除笔记表(如果存在)
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); // 删除数据表(如果存在)
createNoteTable(db); // 重新创建笔记表
createDataTable(db); // 重新创建数据表
}// 添加VERSION列默认为0
// 添加VERSION列默认为0
// 从V2升级到V3
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
// add a column for gtask id
// 删除不再使用的触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); // 删除插入时更新时间触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); // 删除删除时更新时间触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); // 删除更新时更新时间触发器
// 在笔记表中添加一个新的列用于存储gtask ID
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
+ " TEXT NOT NULL DEFAULT ''");
// add a trash system folder
ContentValues values = new ContentValues();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
+ " TEXT NOT NULL DEFAULT ''"); // 添加GTASK_ID列默认为空字符串
// 在笔记表中添加一个垃圾系统文件夹
ContentValues values = new ContentValues(); // 创建一个ContentValues对象
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); // 设置垃圾文件夹ID
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统文件夹
db.insert(TABLE.NOTE, null, values); // 插入新的垃圾文件夹记录
}// 添加VERSION列默认为0
// 添加VERSION列默认为0
// 从V3升级到V4
private void upgradeToV4(SQLiteDatabase db) {
// 在笔记表中添加一个新的列,用于存储版本号
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
}
+ " INTEGER NOT NULL DEFAULT 0"); // 添加VERSION列默认为0
}// 添加VERSION列默认为0
// 添加VERSION列默认为0
// 添加VERSION列默认为0
}// 添加VERSION列默认为0
// 添加VERSION列默认为0

@ -1,305 +1,229 @@
/*
* 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.
* See LICENSE file for full license details.
*/
package net.micode.notes.data;
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.R;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
public class NotesProvider extends ContentProvider {
private static final UriMatcher mMatcher;
private NotesDatabaseHelper mHelper;
private static final String TAG = "NotesProvider";
private static final int URI_NOTE = 1;
private static final int URI_NOTE_ITEM = 2;
private static final int URI_DATA = 3;
private static final int URI_DATA_ITEM = 4;
private static final int URI_SEARCH = 5;
private static final int URI_SEARCH_SUGGEST = 6;
package net.micode.notes.data;//导入
import android.app.SearchManager;//导入
import android.content.ContentProvider;//导入
import android.content.ContentUris;//导入
import android.content.ContentValues;//导入
import android.content.Intent;//导入
import android.content.UriMatcher;//导入
import android.database.Cursor;//导入
import android.database.sqlite.SQLiteDatabase;//导入
import android.net.Uri;//导入
import android.text.TextUtils;//导入
import android.util.Log;//导入
//导入
import net.micode.notes.R;//导入
import net.micode.notes.data.Notes.DataColumns;//导入
import net.micode.notes.data.Notes.NoteColumns;//导入
import net.micode.notes.data.NotesDatabaseHelper.TABLE;//导入
public class NotesProvider extends ContentProvider {//导入
// 日志标签,用于日志输出
private static final String TAG = "NotesProvider";//导入
// Uri匹配器负责匹配传入的Uri
private static final UriMatcher mMatcher;// 插入方法
// 数据库帮助类对象
private NotesDatabaseHelper mHelper;// 插入方法
// 常量定义匹配不同Uri
private static final int URI_NOTE = 1; // 匹配整个笔记表// 常量定义匹配不同Uri
private static final int URI_NOTE_ITEM = 2; // 匹配单个笔记项// 常量定义匹配不同Uri
private static final int URI_DATA = 3; // 匹配数据表// 常量定义匹配不同Uri
private static final int URI_DATA_ITEM = 4; // 匹配单个数据项// 常量定义匹配不同Uri
private static final int URI_SEARCH = 5; // 匹配搜索功能// 常量定义匹配不同Uri
private static final int URI_SEARCH_SUGGEST = 6; // 匹配搜索建议// 常量定义匹配不同Uri
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);// 常量定义匹配不同Uri
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); // 匹配笔记表Uri
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); // 匹配单个笔记
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); // 匹配数据表Uri
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); // 匹配单个数据项
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); // 匹配搜索功能
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); // 匹配搜索建议
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); // 带参数的搜索建议
}
/**
* x'0A' represents the '\n' character in sqlite. For title and content in the search result,
* we will trim '\n' and white space in order to show more information.
*/
// 查询笔记表的列,去除换行符并用于搜索建议结果显示
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + ","
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","// 常量定义匹配不同Uri
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + ","// 常量定义匹配不同Uri
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","// 常量定义匹配不同Uri
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","// 常量定义匹配不同Uri
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;// 常量定义匹配不同Uri
// SQL查询模糊搜索笔记内容
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
+ " FROM " + TABLE.NOTE // SQL查询模糊搜索笔记内容
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?" // SQL查询模糊搜索笔记内容
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER // SQL查询模糊搜索笔记内容
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; // SQL查询模糊搜索笔记内容
// 初始化ContentProvider时调用
@Override
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
public boolean onCreate() { // SQL查询模糊搜索笔记内容
mHelper = NotesDatabaseHelper.getInstance(getContext()); // 获取数据库帮助类实例
return true; // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
/**
* Uri
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
switch (mMatcher.match(uri)) {
case URI_NOTE:
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
break;
case URI_NOTE_ITEM:
id = uri.getPathSegments().get(1);
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
case URI_DATA:
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
sortOrder);
break;
case URI_DATA_ITEM:
id = uri.getPathSegments().get(1);
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
case URI_SEARCH:
case URI_SEARCH_SUGGEST:
if (sortOrder != null || projection != null) {
throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
}
String searchString = null;
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
if (uri.getPathSegments().size() > 1) {
searchString = uri.getPathSegments().get(1);
}
} else {
searchString = uri.getQueryParameter("pattern");
}
if (TextUtils.isEmpty(searchString)) {
return null;
}
try {
searchString = String.format("%%%s%%", searchString);
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
new String[] { searchString });
} catch (IllegalStateException ex) {
Log.e(TAG, "got exception: " + ex.toString());
}
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {// 插入方法
Cursor c = null;// 插入方法
SQLiteDatabase db = mHelper.getReadableDatabase(); // 获取可读数据库
String id = null;// 插入方法
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0;
switch (mMatcher.match(uri)) {
case URI_NOTE:
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
case URI_DATA:
if (values.containsKey(DataColumns.NOTE_ID)) {
noteId = values.getAsLong(DataColumns.NOTE_ID);
} else {
Log.d(TAG, "Wrong data format without note id:" + values.toString());
}
insertedId = dataId = db.insert(TABLE.DATA, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// Notify the data uri
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
return ContentUris.withAppendedId(uri, insertedId);
}
// 查询笔记表
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, sortOrder);// 插入方法
break;// 插入方法
// SQL查询模糊搜索笔记内容
case URI_NOTE_ITEM:// 插入方法
// 查询特定的笔记
id = uri.getPathSegments().get(1);// 插入方法
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder);
break; // SQL查询模糊搜索笔记内容
// SQL查询模糊搜索笔记内容
case URI_DATA: // SQL查询模糊搜索笔记内容
// 查询数据表
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, sortOrder);
break; // SQL查询模糊搜索笔记内容
case URI_DATA_ITEM: // SQL查询模糊搜索笔记内容
// 查询特定的数据项
id = uri.getPathSegments().get(1); // SQL查询模糊搜索笔记内容
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder);
break; // SQL查询模糊搜索笔记内容
case URI_SEARCH: // SQL查询模糊搜索笔记内容
case URI_SEARCH_SUGGEST: // SQL查询模糊搜索笔记内容
// 执行搜索查询
if (sortOrder != null || projection != null) { // SQL查询模糊搜索笔记内容
throw new IllegalArgumentException("Invalid query parameters for search"); // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
String searchString = null; // SQL查询模糊搜索笔记内容
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST && uri.getPathSegments().size() > 1) { // SQL查询模糊搜索笔记内容
searchString = uri.getPathSegments().get(1); // SQL查询模糊搜索笔记内容
} else { // SQL查询模糊搜索笔记内容
searchString = uri.getQueryParameter("pattern"); // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
if (TextUtils.isEmpty(searchString)) { // SQL查询模糊搜索笔记内容
return null; // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
try { // SQL查询模糊搜索笔记内容
searchString = String.format("%%%s%%", searchString); // SQL查询模糊搜索笔记内容
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, new String[] { searchString }); // SQL查询模糊搜索笔记内容
} catch (IllegalStateException ex) { // SQL查询模糊搜索笔记内容
Log.e(TAG, "Exception during search query: " + ex.toString()); // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
break; // SQL查询模糊搜索笔记内容
default: // SQL查询模糊搜索笔记内容
throw new IllegalArgumentException("Unknown URI: " + uri); // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
// SQL查询模糊搜索笔记内容
if (c != null) { // SQL查询模糊搜索笔记内容
c.setNotificationUri(getContext().getContentResolver(), uri); // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
return c; // SQL查询模糊搜索笔记内容
} // SQL查询模糊搜索笔记内容
// 插入方法
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false;
switch (mMatcher.match(uri)) {
case URI_NOTE:
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
id = uri.getPathSegments().get(1);
/**
* ID that smaller than 0 is system folder which is not allowed to
* trash
*/
long noteId = Long.valueOf(id);
if (noteId <= 0) {
break;
}
count = db.delete(TABLE.NOTE,
NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break;
case URI_DATA:
count = db.delete(TABLE.DATA, selection, selectionArgs);
deleteData = true;
break;
case URI_DATA_ITEM:
id = uri.getPathSegments().get(1);
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
public Uri insert(Uri uri, ContentValues values) {// 插入方法
SQLiteDatabase db = mHelper.getWritableDatabase();// 插入方法
long insertedId = 0;// 插入方法
switch (mMatcher.match(uri)) {// 插入方法
case URI_NOTE:// 插入方法
insertedId = db.insert(TABLE.NOTE, null, values); // 插入到笔记表
break;// 插入方法
case URI_DATA:// 插入方法
insertedId = db.insert(TABLE.DATA, null, values); // 插入到数据表
break;// 插入方法
default:// 插入方法
throw new IllegalArgumentException("Unknown URI: " + uri);// 插入方法
}// 插入方法
getContext().getContentResolver().notifyChange(uri, null); // 通知数据变更
return ContentUris.withAppendedId(uri, insertedId);// 插入方法
} // SQL查询模糊搜索笔记内容
// 删除方法
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false;
switch (mMatcher.match(uri)) {
case URI_NOTE:
increaseNoteVersion(-1, selection, selectionArgs);
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
id = uri.getPathSegments().get(1);
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
break;
case URI_DATA:
count = db.update(TABLE.DATA, values, selection, selectionArgs);
updateData = true;
break;
case URI_DATA_ITEM:
id = uri.getPathSegments().get(1);
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (count > 0) {
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
public int delete(Uri uri, String selection, String[] selectionArgs) { // SQL查询模糊搜索笔记内容
SQLiteDatabase db = mHelper.getWritableDatabase(); // SQL查询模糊搜索笔记内容
int count = 0; // SQL查询模糊搜索笔记内容
switch (mMatcher.match(uri)) { // SQL查询模糊搜索笔记内容
case URI_NOTE: // SQL查询模糊搜索笔记内容
count = db.delete(TABLE.NOTE, selection, selectionArgs); // SQL查询模糊搜索笔记内容
break; // SQL查询模糊搜索笔记内容
// SQL查询模糊搜索笔记内容
case URI_NOTE_ITEM: // SQL查询模糊搜索笔记内容
count = db.delete(TABLE.NOTE, NoteColumns.ID // SQL查询模糊搜索笔记内容+ "=" + id + parseSelection(selection), selectionArgs);
String id = uri.getPathSegments().get(1);
// count = db.delete(TABLE.NOTE, NoteColumns.ID // SQL查询模糊搜索笔记内容+ "=" + id + parseSelection(selection), selectionArgs);
count = db.delete(TABLE.NOTE, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);// SQL查询模糊搜索笔记内容
break;// SQL查询模糊搜索笔记内容
default:// SQL查询模糊搜索笔记内容
throw new IllegalArgumentException("Unknown URI: " + uri);// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容
if (count > 0) {// SQL查询模糊搜索笔记内容
getContext().getContentResolver().notifyChange(uri, null); // 数据变更通知
}// SQL查询模糊搜索笔记内容
return count;// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容
// 更新方法
@Override// SQL查询模糊搜索笔记内容
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {// SQL查询模糊搜索笔记内容
SQLiteDatabase db = mHelper.getWritableDatabase();// SQL查询模糊搜索笔记内容
int count = 0;// SQL查询模糊搜索笔记内容
// SQL查询模糊搜索笔记内容
switch (mMatcher.match(uri)) {// SQL查询模糊搜索笔记内容
case URI_NOTE:// SQL查询模糊搜索笔记内容
count = db.update(TABLE.NOTE, values, selection, selectionArgs);// SQL查询模糊搜索笔记内容
break;// SQL查询模糊搜索笔记内容
default:// SQL查询模糊搜索笔记内容
throw new IllegalArgumentException("Unknown URI: " + uri);// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容
if (count > 0) {// SQL查询模糊搜索笔记内容
getContext().getContentResolver().notifyChange(uri, null);// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容
return count;// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容
// 辅助方法解析selection条件
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
sql.append(" SET ");
sql.append(NoteColumns.VERSION);
sql.append("=" + NoteColumns.VERSION + "+1 ");
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
}
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
}
if (!TextUtils.isEmpty(selection)) {
String selectString = id > 0 ? parseSelection(selection) : selection;
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
}
sql.append(selectString);
}
mHelper.getWritableDatabase().execSQL(sql.toString());
}
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容
// SQL查询模糊搜索笔记内容
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}
public String getType(Uri uri) {// SQL查询模糊搜索笔记内容
return null; // 不使用MIME类型// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容
}// SQL查询模糊搜索笔记内容

@ -1,82 +1,83 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
* 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
* 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
* 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.
*/
* 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.gtask.data;
import android.database.Cursor;
import android.util.Log;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
public class MetaData extends Task {
private final static String TAG = MetaData.class.getSimpleName();
private String mRelatedGid = null;
public void setMeta(String gid, JSONObject metaInfo) {
try {
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
Log.e(TAG, "failed to put related gid");
}
setNotes(metaInfo.toString());
setName(GTaskStringUtils.META_NOTE_NAME);
}
public String getRelatedGid() {
return mRelatedGid;
}
@Override
public boolean isWorthSaving() {
return getNotes() != null;
}
@Override
public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js);
if (getNotes() != null) {
try {
JSONObject metaInfo = new JSONObject(getNotes().trim());
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) {
Log.w(TAG, "failed to get related gid");
mRelatedGid = null;
}
}
}
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
}
@Override
public JSONObject getLocalJSONFromContent() {
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
}
@Override
public int getSyncAction(Cursor c) {
throw new IllegalAccessError("MetaData:getSyncAction should not be called");
}
}
package net.micode.notes.gtask.data; // 定义包名
// 定义包名
import android.database.Cursor; // 导入Cursor类
import android.util.Log; // 导入Log类
// 定义包名
import net.micode.notes.tool.GTaskStringUtils; // 导入GTaskStringUtils类
// 定义包名
import org.json.JSONException; // 导入JSONException类
import org.json.JSONObject; // 导入JSONObject类
// 定义包名
public class MetaData extends Task { // 定义MetaData类继承自Task类
private final static String TAG = MetaData.class.getSimpleName(); // 定义日志标签
// 定义包名
private String mRelatedGid = null; // 定义一个字符串变量用于存储相关的GID
// 定义包名
// 设置元数据的方法
public void setMeta(String gid, JSONObject metaInfo) {// 定义包名
try {// 定义包名
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); // 将GID放入metaInfo中// 定义包名
} catch (JSONException e) {// 定义包名
Log.e(TAG, "failed to put related gid"); // 捕获异常并记录错误日志// 定义包名
}// 定义包名
setNotes(metaInfo.toString()); // 将metaInfo转换为字符串并设置为笔记内容// 定义包名
setName(GTaskStringUtils.META_NOTE_NAME); // 设置笔记名称// 定义包名
}// 定义包名
// 定义包名
// 获取相关GID的方法
public String getRelatedGid() {// 定义包名
return mRelatedGid; // 返回相关GID// 定义包名
}// 定义包名
// 定义包名
@Override// 定义包名
public boolean isWorthSaving() {// 定义包名
return getNotes() != null; // 判断笔记内容是否不为空// 定义包名
}// 定义包名
// 定义包名
@Override// 定义包名
public void setContentByRemoteJSON(JSONObject js) {// 定义包名
super.setContentByRemoteJSON(js); // 调用父类方法设置内容// 定义包名
if (getNotes() != null) { // 如果笔记内容不为空// 定义包名
try {// 定义包名
JSONObject metaInfo = new JSONObject(getNotes().trim()); // 将笔记内容转换为JSONObject// 定义包名
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); // 获取相关GID// 定义包名
} catch (JSONException e) {// 定义包名
Log.w(TAG, "failed to get related gid"); // 捕获异常并记录警告日志// 定义包名
mRelatedGid = null; // 将相关GID设置为空// 定义包名
}// 定义包名
}// 定义包名
}// 定义包名
// 定义包名
@Override// 定义包名
public void setContentByLocalJSON(JSONObject js) {// 定义包名
// 这个方法不应该被调用
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");// 定义包名
}// 定义包名
// 定义包名
@Override// 定义包名
public JSONObject getLocalJSONFromContent() {// 定义包名
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");// 定义包名
}// 定义包名
// 定义包名
@Override// 定义包名
public int getSyncAction(Cursor c) {// 定义包名
throw new IllegalAccessError("MetaData:getSyncAction should not be called");// 定义包名
}// 定义包名
// 定义包名
}// 定义包名

@ -1,101 +1,101 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
* 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
* 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
* 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.
* 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.gtask.data;
package net.micode.notes.gtask.data; // 定义包名
import android.database.Cursor;
import android.database.Cursor; // 导入Cursor类
import org.json.JSONObject;
import org.json.JSONObject; // 导入JSONObject类
public abstract class Node {
public static final int SYNC_ACTION_NONE = 0;
public abstract class Node { // 定义抽象类Node
public static final int SYNC_ACTION_NONE = 0; // 定义常量,表示无同步操作
public static final int SYNC_ACTION_ADD_REMOTE = 1;
public static final int SYNC_ACTION_ADD_REMOTE = 1; // 定义常量,表示添加到远程
public static final int SYNC_ACTION_ADD_LOCAL = 2;
public static final int SYNC_ACTION_ADD_LOCAL = 2; // 定义常量,表示添加到本地
public static final int SYNC_ACTION_DEL_REMOTE = 3;
public static final int SYNC_ACTION_DEL_REMOTE = 3; // 定义常量,表示从远程删除
public static final int SYNC_ACTION_DEL_LOCAL = 4;
public static final int SYNC_ACTION_DEL_LOCAL = 4; // 定义常量,表示从本地删除
public static final int SYNC_ACTION_UPDATE_REMOTE = 5;
public static final int SYNC_ACTION_UPDATE_REMOTE = 5; // 定义常量,表示更新到远程
public static final int SYNC_ACTION_UPDATE_LOCAL = 6;
public static final int SYNC_ACTION_UPDATE_LOCAL = 6; // 定义常量,表示更新到本地
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; // 定义常量,表示更新冲突
public static final int SYNC_ACTION_ERROR = 8;
public static final int SYNC_ACTION_ERROR = 8; // 定义常量,表示同步错误
private String mGid;
private String mGid; // 定义私有变量mGid存储GID
private String mName;
private String mName; // 定义私有变量mName存储名称
private long mLastModified;
private long mLastModified; // 定义私有变量mLastModified存储最后修改时间
private boolean mDeleted;
private boolean mDeleted; // 定义私有变量mDeleted存储删除状态
public Node() {
mGid = null;
mName = "";
mLastModified = 0;
mDeleted = false;
public Node() { // 构造函数,初始化变量
mGid = null; // 初始化mGid为null
mName = ""; // 初始化mName为空字符串
mLastModified = 0; // 初始化mLastModified为0
mDeleted = false; // 初始化mDeleted为false
}
public abstract JSONObject getCreateAction(int actionId);
public abstract JSONObject getCreateAction(int actionId); // 抽象方法获取创建操作的JSON对象
public abstract JSONObject getUpdateAction(int actionId);
public abstract JSONObject getUpdateAction(int actionId); // 抽象方法获取更新操作的JSON对象
public abstract void setContentByRemoteJSON(JSONObject js);
public abstract void setContentByRemoteJSON(JSONObject js); // 抽象方法通过远程JSON设置内容
public abstract void setContentByLocalJSON(JSONObject js);
public abstract void setContentByLocalJSON(JSONObject js); // 抽象方法通过本地JSON设置内容
public abstract JSONObject getLocalJSONFromContent();
public abstract JSONObject getLocalJSONFromContent(); // 抽象方法从内容获取本地JSON对象
public abstract int getSyncAction(Cursor c);
public abstract int getSyncAction(Cursor c); // 抽象方法,获取同步操作
public void setGid(String gid) {
public void setGid(String gid) { // 设置GID的方法
this.mGid = gid;
}
public void setName(String name) {
public void setName(String name) { // 获取删除状态的方法
this.mName = name;
}
public void setLastModified(long lastModified) {
this.mLastModified = lastModified;
}
public void setDeleted(boolean deleted) {
}/
/
public void setLastModified(long lastModified) { // 设置最后修改时间的方法
this.mLastModified = lastModified;/
}/
/
public void setDeleted(boolean deleted) { /
this.mDeleted = deleted;
}
public String getGid() {
return this.mGid;
}
public String getName() {
return this.mName;
}
public long getLastModified() {
return this.mLastModified;
}
public boolean getDeleted() {
return this.mDeleted;
}
}
}/
/
public String getGid() { // 获取GID的方法
return this.mGid;/
}/
/
public String getName() { // 获取名称的方法
return this.mName;/
}/
/
public long getLastModified() { // 获取最后修改时间的方法
return this.mLastModified;/
}/ /
/
public boolean getDeleted() { // 获取删除状态的方法
return this.mDeleted;/
}/
/
}/

@ -1,189 +1,186 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
* 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
* 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
* 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.
* 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.gtask.data;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
import net.micode.notes.gtask.exception.ActionFailureException;
import org.json.JSONException;
import org.json.JSONObject;
package net.micode.notes.gtask.data;//
import android.content.ContentResolver;//
import android.content.ContentUris;//
import android.content.ContentValues;//
import android.content.Context;//
import android.database.Cursor;//
import android.net.Uri;//
import android.util.Log;//
import net.micode.notes.data.Notes;//
import net.micode.notes.data.Notes.DataColumns;//
import net.micode.notes.data.Notes.DataConstants;//
import net.micode.notes.data.Notes.NoteColumns;//
import net.micode.notes.data.NotesDatabaseHelper.TABLE;//
import net.micode.notes.gtask.exception.ActionFailureException;//
//
import org.json.JSONException;//
import org.json.JSONObject;//
//
public class SqlData {
private static final String TAG = SqlData.class.getSimpleName();
private static final int INVALID_ID = -99999;
private static final String TAG = SqlData.class.getSimpleName(); // 定义日志标签
//
private static final int INVALID_ID = -99999; // 无效ID常量
//
// 定义查询数据库时所需要的字段
public static final String[] PROJECTION_DATA = new String[] {
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA3
};
public static final int DATA_ID_COLUMN = 0;
public static final int DATA_MIME_TYPE_COLUMN = 1;
public static final int DATA_CONTENT_COLUMN = 2;
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
private ContentResolver mContentResolver;
private boolean mIsCreate;
private long mDataId;
private String mDataMimeType;
private String mDataContent;
private long mDataContentData1;
private String mDataContentData3;
private ContentValues mDiffDataValues;
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,//
DataColumns.DATA3//
};//
//
// 数据库列的索引
public static final int DATA_ID_COLUMN = 0;//
public static final int DATA_MIME_TYPE_COLUMN = 1;//
public static final int DATA_CONTENT_COLUMN = 2;//
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;//
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;//
//
private ContentResolver mContentResolver; // 用于访问ContentProvider的ContentResolver
private boolean mIsCreate; // 标记当前对象是否是新创建的
private long mDataId; // 数据ID
private String mDataMimeType; // 数据类型
private String mDataContent; // 数据内容
private long mDataContentData1; // 数据内容的附加信息1
private String mDataContentData3; // 数据内容的附加信息3
private ContentValues mDiffDataValues; // 用于存储更改的数据内容
// 构造函数初始化SqlData对象
public SqlData(Context context) {
mContentResolver = context.getContentResolver();
mIsCreate = true;
mDataId = INVALID_ID;
mDataMimeType = DataConstants.NOTE;
mDataContent = "";
mDataContentData1 = 0;
mDataContentData3 = "";
mDiffDataValues = new ContentValues();
}
mContentResolver = context.getContentResolver(); // 获取ContentResolver
mIsCreate = true; // 标记为新创建
mDataId = INVALID_ID; // 初始化为无效ID
mDataMimeType = DataConstants.NOTE; // 默认数据类型为NOTE
mDataContent = ""; // 默认内容为空
mDataContentData1 = 0; // 默认附加信息1为0
mDataContentData3 = ""; // 默认附加信息3为空
mDiffDataValues = new ContentValues(); // 初始化更改数据的ContentValues
}//
//
// 构造函数通过Cur/sor加载数据
public SqlData(Context context, Cursor c) {
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDiffDataValues = new ContentValues();
}
private void loadFromCursor(Cursor c) {
mDataId = c.getLong(DATA_ID_COLUMN);
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
mDataContent = c.getString(DATA_CONTENT_COLUMN);
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
}
mContentResolver = context.getContentResolver(); // 获取ContentResolver
mIsCreate = false; // 标记为已存在数据
loadFromCursor(c); // 从Cursor中加载数据
mDiffDataValues = new ContentValues(); // 初始化更改数据的ContentValues
}//
//
// 从Cursor加载数据
private void loadFromCursor(Cursor c) {//
mDataId = c.getLong(DATA_ID_COLUMN); // 获取数据ID
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); // 获取数据类型
mDataContent = c.getString(DATA_CONTENT_COLUMN); // 获取数据内容
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); // 获取附加信息1
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); // 获取附加信息3
}//
//
// 设置数据内容
public void setContent(JSONObject js) throws JSONException {
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;
if (mIsCreate || mDataId != dataId) {
mDiffDataValues.put(DataColumns.ID, dataId);
}
mDataId = dataId;
String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)
: DataConstants.NOTE;
if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {
mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType);
}
mDataMimeType = dataMimeType;
String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";
if (mIsCreate || !mDataContent.equals(dataContent)) {
mDiffDataValues.put(DataColumns.CONTENT, dataContent);
}
mDataContent = dataContent;
long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;
if (mIsCreate || mDataContentData1 != dataContentData1) {
mDiffDataValues.put(DataColumns.DATA1, dataContentData1);
}
mDataContentData1 = dataContentData1;
String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";
if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {
mDiffDataValues.put(DataColumns.DATA3, dataContentData3);
}
mDataContentData3 = dataContentData3;
}
public JSONObject getContent() throws JSONException {
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
JSONObject js = new JSONObject();
js.put(DataColumns.ID, mDataId);
js.put(DataColumns.MIME_TYPE, mDataMimeType);
js.put(DataColumns.CONTENT, mDataContent);
js.put(DataColumns.DATA1, mDataContentData1);
js.put(DataColumns.DATA3, mDataContentData3);
return js;
}
public void commit(long noteId, boolean validateVersion, long version) {
if (mIsCreate) {
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID);
}
mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try {
mDataId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
} else {
if (mDiffDataValues.size() > 0) {
int result = 0;
if (!validateVersion) {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);
} else {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues,
" ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.VERSION + "=?)", new String[] {
String.valueOf(noteId), String.valueOf(version)
});
}
if (result == 0) {
Log.w(TAG, "there is no update. maybe user updates note when syncing");
}
}
}
mDiffDataValues.clear();
mIsCreate = false;
}
public long getId() {
return mDataId;
}
}
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; // 获取ID如果没有则设置为无效ID
if (mIsCreate || mDataId != dataId) { // 如果是新创建的或者ID不相同
mDiffDataValues.put(DataColumns.ID, dataId); // 将ID放入更改数据中
}//
mDataId = dataId; // 更新数据ID
//
String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)//
: DataConstants.NOTE; // 获取数据类型默认是NOTE
if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { // 如果是新创建的或者类型不相同
mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); // 将数据类型放入更改数据中
}//
mDataMimeType = dataMimeType; // 更新数据类型
//
String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; // 获取内容
if (mIsCreate || !mDataContent.equals(dataContent)) { // 如果是新创建的或者内容不相同
mDiffDataValues.put(DataColumns.CONTENT, dataContent); // 将内容放入更改数据中
}//
mDataContent = dataContent; // 更新内容 // 清空更改的数据
// 清空更改的数据
long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; // 获取附加信息1
if (mIsCreate || mDataContentData1 != dataContentData1) { // 如果是新创建的或者附加信息1不同
mDiffDataValues.put(DataColumns.DATA1, dataContentData1); // 将附加信息1放入更改数据中
} // 清空更改的数据
mDataContentData1 = dataContentData1; // 更新附加信息1
// 清空更改的数据
String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; // 获取附加信息3
if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { // 如果是新创建的或者附加信息3不同
mDiffDataValues.put(DataColumns.DATA3, dataContentData3); // 将附加信息3放入更改数据中
} // 清空更改的数据
mDataContentData3 = dataContentData3; // 更新附加信息3
} // 清空更改的数据
// 清空更改的数据
// 获取数据内容
public JSONObject getContent() throws JSONException {//
if (mIsCreate) { // 如果是新创建的
Log.e(TAG, "it seems that we haven't created this in database yet"); // 打印错误日志
return null; // 返回null
}// 返回null
JSONObject js = new JSONObject(); // 创建一个新的JSONObject
js.put(DataColumns.ID, mDataId); // 将ID放入JSONObject中
js.put(DataColumns.MIME_TYPE, mDataMimeType); // 将数据类型放入JSONObject中
js.put(DataColumns.CONTENT, mDataContent); // 将内容放入JSONObject中
js.put(DataColumns.DATA1, mDataContentData1); // 将附加信息1放入JSONObject中
js.put(DataColumns.DATA3, mDataContentData3); // 将附加信息3放入JSONObject中
return js; // 返回JSONObject
} // 清空更改的数据
// 清空更改的数据
// 提交更改
public void commit(long noteId, boolean validateVersion, long version) {//
if (mIsCreate) { // 如果是新创建的
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { // 如果ID无效并且有ID更改
mDiffDataValues.remove(DataColumns.ID); // 移除ID字段
} // 清空更改的数据
// 清空更改的数据
mDiffDataValues.put(DataColumns.NOTE_ID, noteId); // 将笔记ID放入更改数据中
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); // 插入数据到ContentProvider
try { // 清空更改的数据
mDataId = Long.valueOf(uri.getPathSegments().get(1)); // 获取插入数据的ID
} catch (NumberFormatException e) { // 清空更改的数据
Log.e(TAG, "Get note id error :" + e.toString()); // 打印日志
throw new ActionFailureException("create note failed"); // 抛出异常
} // 清空更改的数据
} else { // 如果不是新创建的
if (mDiffDataValues.size() > 0) { // 如果有更改的数据
int result = 0; // 清空更改的数据
if (!validateVersion) { // 如果不需要版本验证 // 清空更改的数据
result = mContentResolver.update(ContentUris.withAppendedId( // 清空更改的数据
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); // 更新数据
} else { // 如果需要版本验证
result = mContentResolver.update(ContentUris.withAppendedId( // 清空更改的数据
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, // 清空更改的数据
" ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE // 清空更改的数据
+ " WHERE " + NoteColumns.VERSION + "=?)", new String[] { // 清空更改的数据
String.valueOf(noteId), String.valueOf(version) // 清空更改的数据
}); // 清空更改的数据
} // 清空更改的数据
if (result == 0) { // 如果没有更新数据
Log.w(TAG, "there is no update. maybe user updates note when syncing"); // 打印警告日志
} // 清空更改的数据
} // 清空更改的数据
} // 清空更改的数据
// 清空更改的数据
// 清空更改的数据
mDiffDataValues.clear(); // 清空更改的数据
mIsCreate = false; // 标记为非新创建
} // 清空更改的数据
// 清空更改的数据
// 获取数据ID
public long getId() { // 清空更改的数据
return mDataId; // 返回数据ID
} // 清空更改的数据
} // 清空更改的数据

@ -200,6 +200,13 @@ public class SqlNote {
mVersion = c.getLong(VERSION_COLUMN);
}
private void loadDataContent() {
Cursor c = null;
mDataList.clear();

@ -33,319 +33,357 @@ import org.json.JSONObject;
public class Task extends Node {
private static final String TAG = Task.class.getSimpleName();
private static final String TAG = Task.class.getSimpleName(); // Tag for logging
private boolean mCompleted;
private boolean mCompleted; // Flag indicating task completion status
private String mNotes;
private String mNotes; // Stores notes related to the task
private JSONObject mMetaInfo;
private JSONObject mMetaInfo; // Metadata for task
private Task mPriorSibling;
private Task mPriorSibling; // Reference to the previous task in the same list
private TaskList mParent;
private TaskList mParent; // Reference to the parent task list
// Constructor
public Task() {
super();
mCompleted = false;
mNotes = null;
mPriorSibling = null;
mParent = null;
mMetaInfo = null;
mCompleted = false; // Initialize task as not completed
mNotes = null; // Initialize notes as null
mPriorSibling = null; // Initialize prior sibling as null
mParent = null; // Initialize parent as null
mMetaInfo = null; // Initialize metadata as null
}
// Creates a JSON object representing a task creation action
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
JSONObject js = new JSONObject(); // Create a new JSONObject to hold the action details
try {
// action_type
// Set action type to "create"
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// action_id
// Set the action ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// index
// Set the task index within its parent task list
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
// entity_delta
// Set the entity delta which holds the task details
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // Set the task name
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // Set the creator as null (default)
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_TASK);
GTaskStringUtils.GTASK_JSON_TYPE_TASK); // Set entity type to task
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); // Add notes if present
}
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // Add entity to the action
// parent_id
// Set parent ID (the ID of the parent task list)
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
// dest_parent_type
// Set the destination parent type
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// list_id
// Set the list ID (the ID of the parent task list)
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
// prior_sibling_id
// Set prior sibling ID if there's a prior sibling
if (mPriorSibling != null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-create jsonobject");
} catch (JSONException e) { // Catch JSON exception if any occur
Log.e(TAG, e.toString()); // Log the error
e.printStackTrace(); // Print the stack trace
throw new ActionFailureException("fail to generate task-create jsonobject"); // Throw custom exception
}
return js;
return js; // Return the JSON object representing the create action
}
// Creates a JSON object representing a task update action
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
JSONObject js = new JSONObject(); // Create a new JSONObject for the update action
try {
// action_type
// Set action type to "update"
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// action_id
// Set action ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// id
// Set task ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// entity_delta
// Set the entity delta with task details
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // Set the task name
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); // Add notes if available
}
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // Set deletion status
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // Add entity to the update action
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-update jsonobject");
} catch (JSONException e) { // Catch JSON exception if any occur
Log.e(TAG, e.toString()); // Log the error
e.printStackTrace(); // Print the stack trace
throw new ActionFailureException("fail to generate task-update jsonobject"); // Throw custom exception
}
return js;
return js; // Return the JSON object representing the update action
}
// Sets the task content based on a remote JSON object
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
// id
// Set task ID if available
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// last_modified
// Set last modified timestamp if available
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// name
// Set task name if available
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
// notes
// Set notes if available
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));
}
// deleted
// Set deletion status if available
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));
}
// completed
// Set completion status if available
if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get task content from jsonobject");
} catch (JSONException e) { // Catch JSON exception if any occur
Log.e(TAG, e.toString()); // Log the error
e.printStackTrace(); // Print the stack trace
throw new ActionFailureException("fail to get task content from jsonobject"); // Throw custom exception
}
}
}
// Sets the task content based on a local JSON object
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
Log.w(TAG, "setContentByLocalJSON: nothing is available"); // Log a warning if data is not available
}
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); // Get the note object
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); // Get data array
// Check if the note type is valid
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
Log.e(TAG, "invalid type");
return;
Log.e(TAG, "invalid type"); // Log an error if the type is invalid
return; // Exit the method
}
// Iterate through data array and set the task name
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
setName(data.getString(DataColumns.CONTENT));
setName(data.getString(DataColumns.CONTENT)); // Set the task name
break;
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
} catch (JSONException e) { // Catch JSON exception if any occur
Log.e(TAG, e.toString()); // Log the error
e.printStackTrace(); // Print the stack trace
}
}
// Returns a local JSON representation of the task content
public JSONObject getLocalJSONFromContent() {
String name = getName();
String name = getName(); // Get the task name
try {
if (mMetaInfo == null) {
// new task created from web
if (name == null) {
if (mMetaInfo == null) { // If metadata is null, create a new task
// New task created from the web
if (name == null) { // If the task name is null, log a warning
Log.w(TAG, "the note seems to be an empty one");
return null;
return null; // Return null if the task name is empty
}
// Create a new JSON object for the task
JSONObject js = new JSONObject();
JSONObject note = new JSONObject();
JSONArray dataArray = new JSONArray();
JSONObject data = new JSONObject();
data.put(DataColumns.CONTENT, name);
dataArray.put(data);
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
return js;
data.put(DataColumns.CONTENT, name); // Set the task name in the data
dataArray.put(data); // Add data to the array
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); // Add data array to the JSON object
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); // Set note type to "note"
js.put(GTaskStringUtils.META_HEAD_NOTE, note); // Add note object to the JSON object
return js; // Return the newly created JSON object
} else {
// synced task
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
data.put(DataColumns.CONTENT, getName());
break;
}
}
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
return mMetaInfo;
// Synced task, retrieve data from metadata
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); // Get the note object
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); // Get data array
// Iterate through data array and update task name
for (int i = 0; i < dataArray.length(); i++) {// Return null if an error occurs
JSONObject data = dataArray.getJSONObject(i);// Return null if an error occurs
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {// Return null if an error occurs
data.put(DataColumns.CONTENT, getName()); // Set the task name in data
break;// Return null if an error occurs
}// Return null if an error occurs
}// Return null if an error occurs
// Return null if an error occurs
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); // Set note type to "note"
return mMetaInfo; // Return the metadata as the JSON object
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return null;
}
}
public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) {
try {
mMetaInfo = new JSONObject(metaData.getNotes());
} catch (JSONException e) {
Log.w(TAG, e.toString());
mMetaInfo = null;
}
}
}
public int getSyncAction(Cursor c) {
} catch (JSONException e) { // Catch JSON exception if any occur
Log.e(TAG, e.toString()); // Log the error
e.printStackTrace(); // Print the stack trace
return null; // Return null if an error occurs
}// Return null if an error occurs
}// Return null if an error occurs
}// Return null if an error occurs
// Return null if an error occurs
// Return null if an error occurs
// Return null if an error occurs
// Return null if an error occurs
// Return null if an error occurs
// Return null if an error occurs
// Method to set meta information using a MetaData object
public void setMetaInfo(MetaData metaData) {
// Check if the metaData is not null and contains notes
if (metaData != null && metaData.getNotes() != null) {
try {
JSONObject noteInfo = null;
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
if (noteInfo == null) {
Log.w(TAG, "it seems that note meta has been deleted");
return SYNC_ACTION_UPDATE_REMOTE;
}
if (!noteInfo.has(NoteColumns.ID)) {
Log.w(TAG, "remote note id seems to be deleted");
return SYNC_ACTION_UPDATE_LOCAL;
}
// validate the note id now
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
Log.w(TAG, "note id doesn't match");
return SYNC_ACTION_UPDATE_LOCAL;
}
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// there is no local update
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// no update both side
return SYNC_ACTION_NONE;
} else {
// apply remote to local
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
// validate gtask id
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "gtask id doesn't match");
return SYNC_ACTION_ERROR;
}
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// local modification only
return SYNC_ACTION_UPDATE_REMOTE;
} else {
return SYNC_ACTION_UPDATE_CONFLICT;
}
}
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return SYNC_ACTION_ERROR;
}
public boolean isWorthSaving() {
return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
|| (getNotes() != null && getNotes().trim().length() > 0);
}
public void setCompleted(boolean completed) {
this.mCompleted = completed;
}
public void setNotes(String notes) {
this.mNotes = notes;
}
public void setPriorSibling(Task priorSibling) {
this.mPriorSibling = priorSibling;
}
public void setParent(TaskList parent) {
this.mParent = parent;
}
public boolean getCompleted() {
return this.mCompleted;
}
public String getNotes() {
return this.mNotes;
}
public Task getPriorSibling() {
return this.mPriorSibling;
}
public TaskList getParent() {
return this.mParent;
}
// Convert the notes data into a JSONObject and assign it to mMetaInfo
mMetaInfo = new JSONObject(metaData.getNotes());
} catch (JSONException e) {
// Log a warning if the conversion fails
Log.w(TAG, e.toString());
// Reset mMetaInfo to null in case of an error
mMetaInfo = null; // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
// Method to determine the sync action based on the data in the cursor
public int getSyncAction(Cursor c) { // Reset mMetaInfo to null in case of an error
try { // Reset mMetaInfo to null in case of an error
JSONObject noteInfo = null; // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
// Check if mMetaInfo is not null and contains the note info
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { // Reset mMetaInfo to null in case of an error
// Retrieve the note info from mMetaInfo
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
// If no note info is found, return SYNC_ACTION_UPDATE_REMOTE
if (noteInfo == null) { // Reset mMetaInfo to null in case of an error
Log.w(TAG, "it seems that note meta has been deleted"); // Reset mMetaInfo to null in case of an error
return SYNC_ACTION_UPDATE_REMOTE; // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
// If no note ID is found in the note info, return SYNC_ACTION_UPDATE_LOCAL
if (!noteInfo.has(NoteColumns.ID)) {
Log.w(TAG, "remote note id seems to be deleted");
return SYNC_ACTION_UPDATE_LOCAL;
} // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
// Validate the note ID with the value in the cursor
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { // Reset mMetaInfo to null in case of an error
Log.w(TAG, "note id doesn't match"); // Reset mMetaInfo to null in case of an error
return SYNC_ACTION_UPDATE_LOCAL; // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
// Check if there are any local updates
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// If no local updates, check if the sync ID matches the last modified timestamp
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// No updates on either side // Reset mMetaInfo to null in case of an error
return SYNC_ACTION_NONE; // Reset mMetaInfo to null in case of an error
} else { // Reset mMetaInfo to null in case of an error
// Apply remote updates to local // Reset mMetaInfo to null in case of an error
return SYNC_ACTION_UPDATE_LOCAL; // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
} else { // Reset mMetaInfo to null in case of an error
// If there are local modifications, // Reset mMetaInfo to null in case of an errorvalidate the gtask ID
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { // Reset mMetaInfo to null in case of an error
Log.e(TAG, "gtask id doesn't match"); // Reset mMetaInfo to null in case of an error
return SYNC_ACTION_ERROR; // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
// Check if the sync ID matches the last modified timestamp for local modification
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { // Reset mMetaInfo to null in case of an error
// Local modification only
return SYNC_ACTION_UPDATE_REMOTE; // Reset mMetaInfo to null in case of an error
// Conflict between local and remote modification
return SYNC_ACTION_UPDATE_CONFLICT; // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
} catch (Exception e) { // Reset mMetaInfo to null in case of an error
// Log the exception and return SYNC_ACTION_ERROR
Log.e(TAG, e.toString()); // Reset mMetaInfo to null in case of an error
e.printStackTrace(); // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
return SYNC_ACTION_ERROR; // Reset mMetaInfo to null in case of an error
} // Reset mMetaInfo to null in case of an error
// Getter method to retrieve the parent task list
// Method to check if the task is worth saving based on meta info or task content
public boolean isWorthSaving() { // Reset mMetaInfo to null in case of an error
// If there is meta info or non-empty name or notes, return true
return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)// Getter method to retrieve the parent task list
|| (getNotes() != null && getNotes().trim().length() > 0);// Getter method to retrieve the parent task list
} // Reset mMetaInfo to null in case of an error
// Reset mMetaInfo to null in case of an error
// Setter method to mark the task as completed
public void setCompleted(boolean completed) { // Reset mMetaInfo to null in case of an error
this.mCompleted = completed;// Getter method to retrieve the parent task list
}// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
// Setter method to set the notes of the task
public void setNotes(String notes) {// Getter method to retrieve the parent task list
this.mNotes = notes;// Getter method to retrieve the parent task list
}// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
// Setter method to set the prior sibling task
public void setPriorSibling(Task priorSibling) {// Getter method to retrieve the parent task list
this.mPriorSibling = priorSibling;// Getter method to retrieve the parent task list
}// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
// Setter method to set the parent task list
public void setParent(TaskList parent) {// Getter method to retrieve the parent task list
this.mParent = parent;// Getter method to retrieve the parent task list
}// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
// Getter method to retrieve the completed status of the task
public boolean getCompleted() {// Getter method to retrieve the parent task list
return this.mCompleted;// Getter method to retrieve the parent task list
}// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
// Getter method to retrieve the notes of the task
public String getNotes() {// Getter method to retrieve the parent task list
return this.mNotes;// Getter method to retrieve the parent task list
}// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
// Getter method to retrieve the prior sibling task
public Task getPriorSibling() {// Getter method to retrieve the parent task list
return this.mPriorSibling;// Getter method to retrieve the parent task list
}// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
// Getter method to retrieve the parent task list
public TaskList getParent() {// Getter method to retrieve the parent task list
return this.mParent;// Getter method to retrieve the parent task list
}

@ -1,28 +1,25 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明指定版本为1.0编码格式为utf-8 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
版权相关信息,说明该代码所属的开源社区及版权时间范围等
Licensed under the Apache License, Version 2.0 (the "License");
说明该代码遵循Apache License 2.0协议授权
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.
提示查看协议了解权限和限制相关具体内容 -->
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<!-- 定义一个线性布局LinearLayout宽度占满父容器高度也占满父容器布局方向为垂直方向同时引入了安卓的命名空间 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/account_dialog_title"
@ -35,8 +32,6 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<!-- 定义一个TextView控件设置了其id为account_dialog_title应用了安卓中中等文本外观的样式文本单行显示超出部分省略号显示在结尾文本居中对齐设置了上下外边距宽度占满父容器高度根据内容自适应wrap_content -->
<TextView
android:id="@+id/account_dialog_subtitle"
android:layout_width="fill_parent"
@ -45,5 +40,4 @@
android:layout_marginBottom="1dip"
android:gravity="center"/>
<!-- 定义另一个TextView控件设置了id为account_dialog_subtitle宽度占满父容器高度根据内容自适应设置了上下外边距文本居中对齐 -->
</LinearLayout>

@ -1,21 +1,20 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该XML文件遵循的版本是1.0使用的编码格式为utf-8 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
这里是版权相关的说明信息,指出代码所属的开源社区以及对应的版权时间范围
Licensed under the Apache License, Version 2.0 (the "License");
说明此代码遵循Apache License 2.0这个开源协议进行授权许可
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
告知可以通过这个网址去获取Apache 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.
提示查看该协议来了解具体关于权限以及限制方面的内容 -->
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@ -23,21 +22,11 @@
android:minHeight="50dip"
android:gravity="center_vertical"
android:orientation="vertical">
<!-- 引入安卓的命名空间,用于后续使用安卓系统定义的各种布局属性等 -->
<!-- 线性布局的宽度设置为与父容器宽度匹配,也就是占满父容器宽度 -->
<!-- 线性布局的高度根据其内部子元素的布局情况自适应,也就是包裹内容的高度 -->
<!-- 定义线性布局的最小高度为50dip确保其不会小于这个高度值 -->
<!-- 设置线性布局内部元素在垂直方向上居中对齐 -->
<!-- 定义线性布局内子元素的排列方向为垂直方向 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/preferences_add_account" />
<!-- TextView控件的宽度根据其文本内容自适应也就是包裹内容的宽度 -->
<!-- TextView控件的高度同样根据其文本内容自适应包裹内容的高度 -->
<!-- 设置该TextView在其所在的父容器这里是线性布局中居中对齐 -->
<!-- 应用安卓系统中定义的中等文本外观样式来显示文本 -->
<!-- 设置TextView显示的文本内容这里引用了名为"preferences_add_account"的字符串资源通常在strings.xml文件中定义 -->
</LinearLayout>

@ -1,77 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式为 utf-8这是 XML 文件开头必备的标识信息 -->
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关的声明信息,指出这段代码所属的开源社区为 The MiCode Open Source Community版权时间范围是 2010 - 2011 年
Licensed under the Apache License, Version 2.0 (the "License");
说明该代码遵循 Apache License 2.0 这个开源协议来进行授权许可,意味着使用该代码需要遵循此协议的相关规定
you may not use this file except in compliance with the License.
强调若要使用此 XML 文件所定义的相关内容,必须严格按照上述提到的 Apache License 2.0 协议来操作
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问这个网址http://www.apache.org/licenses/LICENSE-2.0)去获取 Apache 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.
提示查看该协议内容,以了解具体关于权限授予以及限制方面的详细信息 -->
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<NumberPicker
android:id="@+id/date"
android:layout_width="120dip"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
/>
android:layout_height="wrap_content">
<NumberPicker
android:id="@+id/hour"
android:layout_width="50dip"
<NumberPicker
android:id="@+id/date"
android:layout_width="120dip"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
/>
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<NumberPicker
android:id="@+id/hour"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<NumberPicker
android:id="@+id/minute"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<NumberPicker
android:id="@+id/minute"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<NumberPicker
android:id="@+id/amPm"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
</LinearLayout>
<!-- 设置此 NumberPicker 控件的宽度为 50 设备独立像素dip以确定其在水平方向上的尺寸 -->
<!-- 设置该控件距离其左边相邻元素在这里就是前面定义的“date” NumberPicker 控件)的间距为 5 设备独立像素dip用于控制控件之间的水平间隔距离 -->
<!-- 在触摸模式下(例如在触屏设备上操作时)也允许该控件获取焦点,方便用户通过触摸操作来与该控件进行交互,比如点击后进行数值调整等 -->
<!-- 为这个 NumberPicker 控件定义一个唯一的标识符id在安卓开发中通过这个 id 可以在代码里方便地对该控件进行引用、操作和事件处理等 -->
<!-- 设置 NumberPicker 控件的高度根据其内部内容自适应,也就是其高度会根据该控件显示的数值等内容自动调整,刚好包裹住这些内容 -->
<!-- 设置 NumberPicker 控件的宽度为 120 设备独立像素dip这确定了该控件在屏幕上水平方向所占据的空间大小 -->
<!-- 引入安卓的命名空间xmlns通过这个命名空间后续可以使用安卓系统预定义的各种布局属性和控件等相关元素这是在安卓 XML 布局文件中定义布局的基础 -->
<!-- 设置线性布局LinearLayout内子元素的排列方向为水平方向意味着子元素会从左到右依次水平排列 -->
<!-- 使该线性布局在其父容器中水平方向上居中对齐,这样整个布局会在水平维度上处于父容器的中间位置 -->
<!-- 线性布局的宽度设置为根据其内部包含的子元素大小自适应,也就是刚好能够包裹住所有子元素所需要的宽度 -->
<!-- 允许该控件获取焦点,意味着在用户操作时(例如通过键盘导航等方式),可以将操作焦点定位到这个控件上,使其能够接收用户输入等操作 -->
<!-- 允许该控件获取焦点,意味着在用户操作时(例如通过键盘导航等方式),可以将操作焦点定位到这个控件上,使其能够接收用户输入等操作 -->
<!-- 线性布局的高度同样根据其内部包含的子元素大小自适应,即包裹住子元素后所需要的高度 -->
<NumberPicker
android:id="@+id/amPm"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
</LinearLayout>

@ -1,30 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明用于指定该XML文件所遵循的版本是1.0并且编码格式为utf-8这是XML文件开头必备的基础信息让解析器知晓如何正确解析文件内容 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
这部分是版权声明相关的注释内容说明该代码归属于The MiCode Open Source Community这个开源社区其版权时间范围涵盖了2010年至2011年期间
Licensed under the Apache License, Version 2.0 (the "License");
表明此代码是按照Apache License 2.0这个开源协议来进行授权许可的,意味着任何使用该代码的行为都需要遵循此协议所规定的各项条款
you may not use this file except in compliance with the License.
着重强调了只有在符合上述Apache License 2.0协议要求的情况下才可以使用当前这个XML文件所定义的相关内容否则属于违规使用
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
提供了获取Apache License 2.0协议具体内容的途径即可以通过访问这个网址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.
提示用户如果想要了解关于该协议所规定的权限管理以及各种限制方面的详细内容,需要去查看对应的协议文本 -->
-->
<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/et_foler_name"
android:layout_width="fill_parent"
android:hint="@string/hint_foler_name"
android:layout_height="fill_parent" /><!-- 设定了该EditText控件的高度属性为fill_parent意味着它在垂直方向上也会填满所在父容器的全部高度空间这样该控件在整个布局中的尺寸就会尽可能地大占据父容器的绝大部分空间 -->
<!-- 用于设置该EditText控件的提示文本内容这里通过引用名为hint_foler_name的字符串资源一般在项目的strings.xml文件中定义具体的字符串值来显示提示信息当该控件中没有用户输入的文本时就会显示这个提示文本以此来提示用户应该输入什么样的内容从名称来看大概率是提示用户输入文件夹名称相关的内容 -->
<!-- 设置了该EditText控件的宽度属性将其设置为fill_parent表示这个控件在水平方向上会填满它所在的父容器的全部宽度空间使其能够在布局中占据足够的横向空间 -->
<!-- 为这个EditText控件定义了一个唯一的标识符id在安卓开发过程中其他代码部分比如在Java或者Kotlin代码中可以通过这个id来准确地引用到该控件进而对其进行各种操作例如获取用户输入的文本、设置控件的显示状态等这里将其命名为et_foler_name从命名推测可能是用于和文件夹名称相关的输入操作 -->
<!-- 引入了安卓的命名空间xmlns这是在安卓开发中XML布局文件里必不可少的部分通过这个命名空间后续就能够使用安卓系统所定义的众多属性来对该EditText控件进行各种配置 -->
android:layout_height="fill_parent" />

@ -1,16 +1,24 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,所采用的编码格式为 utf-8这是 XML 文件开头的标准标识,用于告知解析器如何正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 设置线性布局LinearLayout的宽度与父容器宽度相匹配也就是占满父容器的整个宽度 -->
<!-- 设置线性布局的高度与父容器高度相匹配,即占满父容器的整个高度 -->
<!-- 定义线性布局的最小高度为 50 设备独立像素dip确保该布局在任何情况下高度都不会低于这个值可用于保证一定的显示效果 -->
<!-- 引入安卓的命名空间,后续通过此命名空间来使用安卓系统定义的各种布局属性及控件相关属性,是安卓 XML 布局文件必备的部分 -->
android:minHeight="50dip"
android:layout_height="match_parent"
android:minHeight="50dip" >
<TextView
android:id="@+id/tv_folder_name"
@ -18,31 +26,4 @@
android:layout_height="match_parent"
android:gravity="center"
android:textAppearance="@style/TextAppearancePrimaryItem" />
</LinearLayout><!-- 为该 TextView 控件定义一个唯一标识符id方便在代码中对其进行引用、操作从命名推测可能是用于显示文件夹名称相关内容 -->
<!-- 设置 TextView 控件的宽度与父容器(这里是外层的 LinearLayout宽度相匹配使其能占满水平方向的空间 -->
<!-- 设置 TextView 控件的高度与父容器高度相匹配,占满垂直方向的空间 -->
<!-- 设置文本在该 TextView 控件内的对齐方式为居中对齐,使文本在水平和垂直方向都处于中间位置 -->
<!-- 应用名为 TextAppearancePrimaryItem 的样式来设置文本的外观,该样式通常在样式资源文件中定义,可控制文本的字体、字号、颜色等外观属性 -->
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处为版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围是 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示该代码遵循 Apache License 2.0 开源协议进行授权许可,意味着使用该代码需要遵循此协议规定。
you may not use this file except in compliance with the License.
强调若要使用这个文件,必须按照上述 Apache License 2.0 协议来操作。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问此网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议以了解关于权限及限制方面的详细内容。 -->
</LinearLayout>

@ -55,7 +55,7 @@
android:layout_marginLeft="2dip"
android:layout_marginRight="8dip"
android:textAppearance="@style/TextAppearanceSecondaryItem" />
<ImageButton
android:id="@+id/menu_more"
android:layout_width="wrap_content"
@ -65,7 +65,7 @@
android:background="@drawable/ic_menu_more_dark" />
<ImageView
android:id="@+id/btn_set_bg_color"
android:id="@+id/btn_set_bg_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
@ -407,310 +407,4 @@
android:src="@drawable/selected" />
</FrameLayout>
</LinearLayout>
</FrameLayout><!-- XML声明表明该XML文件遵循的版本是1.0使用的编码格式是utf-8这是XML文件开头的标准标识用于告知解析器如何正确解析该文件 -->
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种布局属性以及控件相关的属性了 -->
<!-- 设置FrameLayout帧布局的宽度占满父容器意味着它在水平方向上会填满所在父容器的全部可用空间 -->
<!-- 设置FrameLayout的高度占满父容器也就是在垂直方向上会填满所在父容器的全部可用空间 -->
<!-- 设置FrameLayout的背景这里引用了名为"list_background"的可绘制资源(通常可以是图片、颜色等能作为背景的资源)来作为该布局的背景 -->
<!-- 设置LinearLayout线性布局的宽度占满父容器此处父容器为外层的FrameLayout使其在水平方向上填满整个父布局空间 -->
<!-- 设置LinearLayout的高度占满父容器让它在垂直方向上也填满整个父布局空间 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素会按照从上到下的顺序依次排列 -->
<!-- 为这个内层的LinearLayout定义一个唯一标识符id方便在后续的代码中比如Java或Kotlin代码对该布局进行引用、操作等从命名来看可能与笔记的标题部分相关 -->
<!-- 设置这个LinearLayout的宽度占满父容器这里的父容器是外层的LinearLayout使其在水平方向上占据全部空间 -->
<!-- 设置该LinearLayout的高度根据其内部子元素的大小自适应也就是刚好能包裹住内部子元素所需的高度 -->
<!-- 为这个TextView控件定义一个唯一标识符id从名字推测可能是用于显示笔记的修改日期相关信息 -->
<!-- 初始设置该TextView的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向的空间 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应即刚好能包裹住文本的高度 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间通常意味着它会占据相对较多的水平空间与同层级其他设置了权重的控件一起分配父容器的宽度 -->
<!-- 设置文本在该TextView控件内的对齐方式水平方向居左对齐、垂直方向居中对齐 -->
<!-- 设置该TextView控件距离其右边相邻元素的间距为8设备独立像素dip -->
<!-- 应用名为TextAppearanceSecondaryItem的样式来设置文本的外观像字体、字号、颜色等属性通常在对应的样式资源文件中定义好了 -->
<!-- 为这个ImageView控件定义一个唯一标识符id从名字推测可能是用于显示与提醒相关的图标 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应也就是刚好能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应刚好能包裹住图片的高度 -->
<!-- 设置图片在该ImageView控件内的对齐方式为垂直居中对齐 -->
<!-- 设置该ImageView的背景引用名为title_alert的可绘制资源通常是图片资源作为背景 -->
<!-- 为这个TextView控件定义一个唯一标识符id从名字推测可能是用于显示提醒相关的日期信息 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应能包裹住文本的宽度 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应能包裹住文本的高度 -->
<!-- 设置文本在该TextView控件内的对齐方式为垂直居中对齐 -->
<!-- 设置该TextView控件距离其左边相邻元素的间距为2设备独立像素dip -->
<!-- 设置该TextView控件距离其右边相邻元素的间距为8设备独立像素dip -->
<!-- 应用名为TextAppearanceSecondaryItem的样式来设置文本的外观 -->
<!-- 为这个ImageButton控件定义一个唯一标识符id从名字推测可能是用于点击后打开更多菜单之类的操作 -->
<!-- 设置该ImageButton的宽度根据其内部要显示的图片内容自适应能包裹住图片的宽度 -->
<!-- 设置该ImageButton的高度根据其内部要显示的图片内容自适应能包裹住图片的高度 -->
<!-- 设置图片在该ImageButton控件内的对齐方式为居中对齐 -->
<!-- 设置点击该ImageButton时触发的方法名为OnOpenMenu需要在对应的代码逻辑中实现这个方法来处理点击事件 -->
<!-- 设置该ImageButton的背景引用名为ic_menu_more_dark的可绘制资源通常是图片资源作为背景 -->
<!-- 为这个ImageView控件定义一个唯一标识符id从名字推测可能与设置背景颜色相关的操作有关 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应能包裹住图片的高度 -->
<!-- 设置该ImageView的内边距为10设备独立像素dp也就是在图片的四周留出一定的空白空间 -->
<!-- 设置图片在该ImageView控件内的对齐方式为居中对齐 -->
<!-- 设置该ImageView的背景引用名为bg_btn_set_color的可绘制资源通常是图片资源作为背景 -->
<!-- 结束前面开始的 FrameLayout 布局定义,与开头的 <FrameLayout> 标签对应,构成一个完整的帧布局结构 -->
<!-- 为该 LinearLayout 定义一个唯一标识符id方便在代码中对其进行引用、操作从命名推测可能与笔记编辑相关的布局 -->
<!-- 设置该 LinearLayout 的宽度占满父容器(这里的父容器应该是外层与之对应的布局元素),使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 LinearLayout 的高度占满父容器,在垂直方向上填满整个父容器空间 -->
<!-- 设置线性布局内子元素的排列方向为垂直方向,意味着子元素将从上到下依次排列 -->
<!-- 设置该 ImageView 的宽度占满父容器(这里的父容器是当前的 LinearLayout水平方向填满整个空间 -->
<!-- 设置该 ImageView 的高度为 7 设备独立像素dip -->
<!-- 设置 ImageView 的背景,引用名为 bg_color_btn_mask 的可绘制资源(通常是图片资源)作为背景 -->
<!-- 设置 ScrollView滚动视图的宽度占满父容器这里的父容器是当前的 LinearLayout使其在水平方向上填满整个空间 -->
<!-- 初始设置高度为 0 设备独立像素dip后续会结合 layout_weight 属性来分配垂直方向的空间 -->
<!-- 设置权重为 1在垂直方向上按比例分配剩余空间用于占据较大的可滚动区域 -->
<!-- 设置不显示滚动条 -->
<!-- 设置禁止过度滚动效果 -->
<!-- 设置在父容器中的对齐方式为左上角对齐 -->
<!-- 设置渐变边缘的长度为 0 设备独立像素dip即不显示渐变边缘效果 -->
<!-- 设置该 LinearLayout 的宽度占满父容器(这里的父容器是外层的 ScrollView在水平方向上填满整个空间 -->
<!-- 设置该 LinearLayout 的高度占满父容器,在垂直方向上填满整个空间 -->
<!-- 设置线性布局内子元素的排列方向为垂直方向 -->
<!-- 为该 NoteEditText 控件定义一个唯一标识符id从命名推测是用于编辑笔记内容的主要输入框 -->
<!-- 设置宽度占满父容器(这里的父容器是当前的 LinearLayout水平方向填满空间 -->
<!-- 设置高度根据文本内容自适应,包裹住文本内容 -->
<!-- 设置文本在该控件内的对齐方式为左上角对齐 -->
<!-- 设置背景为空,即不显示默认的背景样式 -->
<!-- 设置自动识别链接,会识别所有类型的链接(如网址、邮箱等) -->
<!-- 设置虽然识别了链接,但链接不可点击 -->
<!-- 设置最小行数为 12 行,确保输入框有一定的初始高度 -->
<!-- 应用名为 TextAppearancePrimaryItem 的样式来设置文本外观,例如字体、字号、颜色等属性 -->
<!-- 设置行间距倍数为 1.2,增加文本行之间的间距 -->
<!-- 为该 LinearLayout 定义一个唯一标识符id从命名推测可能与笔记编辑相关的列表部分当前设置为不可见 -->
<!-- 设置宽度占满父容器(这里的父容器是当前的 LinearLayout水平方向填满空间 -->
<!-- 设置高度根据其内部子元素自适应,包裹住子元素 -->
<!-- 设置线性布局内子元素的排列方向为垂直方向 -->
<!-- 设置该布局初始状态为不可见 -->
<!-- 结束前面开始的LinearLayout布局定义与对应的<LinearLayout>开头标签相匹配,完成该线性布局的结构 -->
<!-- 设置ImageView的高度为7设备独立像素dip使其具有固定的垂直高度 -->
<!-- 设置ImageView的背景引用名为bg_color_btn_mask的可绘制资源通常是图片、颜色等用于作为背景的资源来作为该ImageView的背景 -->
<!-- 设置ImageView的宽度占满父容器也就是在水平方向上填满其所在父布局的全部可用空间 -->
<!-- 设置ImageView的高度为43设备独立像素dip确定其垂直方向上的尺寸大小 -->
<!-- 设置ImageView的宽度根据其内部要显示的内容通常是图片自适应即刚好能包裹住图片的宽度 -->
<!-- 同样是设置该ImageView的背景使用名为bg_color_btn_mask的可绘制资源作为背景 -->
<!-- 设置该ImageView在其父容器中的对齐方式为右上角对齐使其显示在父容器的右上角位置 -->
<!-- 为该LinearLayout定义一个唯一标识符id方便在代码中对其进行引用、操作从命名来看可能是用于选择笔记背景颜色的相关布局 -->
<!-- 设置该LinearLayout的宽度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的宽度 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置该LinearLayout的背景引用名为note_edit_color_selector_panel的可绘制资源作为背景 -->
<!-- 设置该LinearLayout距离其父容器顶部的间距为30设备独立像素dip用于调整其垂直方向上的位置 -->
<!-- 设置该LinearLayout距离其父容器右侧的间距为8设备独立像素dip用于调整其水平方向上的位置 -->
<!-- 设置该LinearLayout在其父容器中的对齐方式为右上角对齐使其显示在父容器的右上角位置 -->
<!-- 设置该LinearLayout初始状态为不可见可能在满足某些条件后才会显示出来 -->
<!-- 初始设置FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来分配水平方向上的空间 -->
<!-- 设置FrameLayout的高度与父容器高度匹配使其在垂直方向上填满整个父容器空间 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间用于多个同层级FrameLayout按比例划分宽度 -->
<!-- 为该ImageView控件定义一个唯一标识符id从命名推测是用于显示黄色背景相关的图片或样式 -->
<!-- 设置该ImageView的宽度与父容器这里是外层的FrameLayout宽度匹配在水平方向上填满整个父容器空间 -->
<!-- 设置该ImageView的高度与父容器高度匹配在垂直方向上填满整个父容器空间 -->
<!-- 为该ImageView控件定义一个唯一标识符id推测是用于表示黄色背景是否被选中的相关显示元素初始设置为不可见 -->
<!-- 设置该ImageView的宽度根据其内部要显示的内容自适应包裹住内容的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的内容自适应包裹住内容的高度 -->
<!-- 设置该ImageView在其父容器这里是外层的FrameLayout中的对齐方式为右下角对齐 -->
<!-- 设置该ImageView距离其父容器右侧的间距为5设备独立像素dip -->
<!-- 设置该ImageView不可获取焦点意味着用户不能通过焦点操作来与之交互 -->
<!-- 设置该ImageView初始状态为不可见可能在相关逻辑控制下变为可见以表示选中状态等 -->
<!-- 设置该ImageView要显示的图片资源引用名为selected的可绘制资源通常是图片资源 -->
<!-- 结束前面对应的 FrameLayout 标签所开始的布局定义,与开头的 <FrameLayout> 相呼应,完成一个 FrameLayout 布局结构的声明 -->
<!-- 初始设置该 FrameLayout 的宽度为 0 设备独立像素dip后续会结合 layout_weight 属性在水平方向上按比例分配空间 -->
<!-- 设置该 FrameLayout 的高度与父容器高度相匹配,使其在垂直方向上填满整个父容器空间 -->
<!-- 设置权重为 1意味着在水平方向上它会按照比例去分配剩余的空间通常用于和同层级的其他设置了权重的布局共同划分父容器的宽度 -->
<!-- 为这个 ImageView 控件定义一个唯一标识符id从命名来看可能是用于显示蓝色背景相关的图片资源用于界面展示相关用途 -->
<!-- 设置该 ImageView 的宽度与父容器(这里就是外层的 FrameLayout宽度相匹配使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 ImageView 的高度与父容器高度相匹配,使其在垂直方向上填满整个父容器空间 -->
<!-- 为这个 ImageView 控件定义一个唯一标识符id推测是用于表示蓝色背景是否被选中的一个指示性图片比如选中后显示特定样式初始设置为不可见 -->
<!-- 设置该 ImageView 的宽度根据其内部要显示的图片内容自适应,也就是刚好能包裹住图片的宽度 -->
<!-- 设置该 ImageView 的高度根据其内部要显示的图片内容自适应,刚好能包裹住图片的高度 -->
<!-- 设置该 ImageView 在其父容器(外层的 FrameLayout内的对齐方式为右下角对齐确定其显示位置 -->
<!-- 设置该 ImageView 不可获取焦点,意味着用户不能通过焦点操作(比如通过方向键、触摸焦点等方式)与它进行交互 -->
<!-- 设置该 ImageView 初始状态为不可见,可能在后续满足某些条件(比如用户选择了蓝色背景选项等)时,通过代码将其设置为可见来表示相应的选中状态 -->
<!-- 设置该 ImageView 距离其父容器(外层的 FrameLayout右侧的间距为 3 设备独立像素dip用于微调其在水平方向上的位置 -->
<!-- 设置该 ImageView 要显示的图片资源引用名为“selected”的可绘制资源通常是图片资源这个图片应该是用于体现选中状态的特定样式 -->
<!-- 初始设置该FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间通常用于多个同层级FrameLayout按权重划分父容器宽度 -->
<!-- 设置该FrameLayout的高度与父容器高度相匹配使其在垂直方向上填满整个父容器空间 -->
<!-- 设置权重为1意味着在水平方向上它会按照比例去分配剩余空间和同层级其他设置了权重的布局一起确定各自 <!- 为该ImageView控件定义一个唯一标识符id从命名推测是用于展示白色背景相关的图片或视觉元素在界面布局中起到对应的显示作用 -->
<!-- 设置该ImageView的宽度与父容器这里就是外层的FrameLayout宽度相匹配使其在水平方向上填满整个父容器空间 -->
<!-- 设置该ImageView的高度与父容器高度相匹配使其在垂直方向上填满整个父容器空间 -->
<!-- 为该ImageView控件定义一个唯一标识符id推测是用于表示黄色背景是否被选中的相关显示元素初始设置为不可见 -->
<!-- 设置该ImageView的宽度根据其内部要显示的内容自适应包裹住内容的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的内容自适应包裹住内容的高度 -->
<!-- 设置该ImageView在其父容器这里是外层的FrameLayout中的对齐方式为右下角对齐 -->
<!-- 设置该ImageView距离其父容器右侧的间距为5设备独立像素dip -->
<!-- 设置该ImageView不可获取焦点意味着用户不能通过焦点操作来与之交互 -->
<!-- 设置该ImageView初始状态为不可见可能在相关逻辑控制下变为可见以表示选中状态等 -->
<!-- 设置该ImageView要显示的图片资源引用名为selected的可绘制资源通常是图片资源 -->
<!-- 结束前面对应的 FrameLayout 标签所开始的布局定义,与开头的 <FrameLayout> 相呼应,完成一个 FrameLayout 布局结构的声明 -->
<!-- 初始设置该 FrameLayout 的宽度为 0 设备独立像素dip后续会结合 layout_weight 属性在水平方向上按比例分配空间 -->
<!-- 设置该 FrameLayout 的高度与父容器高度相匹配,使其在垂直方向上填满整个父容器空间 -->
<!-- 设置权重为 1意味着在水平方向上它会按照比例去分配剩余的空间通常用于和同层级的其他设置了权重的布局共同划分父容器的宽度 -->
<!-- 为这个 ImageView 控件定义一个唯一标识符id从命名来看可能是用于显示蓝色背景相关的图片资源用于界面展示相关用途 -->
<!-- 设置该 ImageView 的宽度与父容器(这里就是外层的 FrameLayout宽度相匹配使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 ImageView 的高度与父容器高度相匹配,使其在垂直方向上填满整个父容器空间 -->
<!-- 为这个 ImageView 控件定义一个唯一标识符id推测是用于表示蓝色背景是否被选中的一个指示性图片比如选中后显示特定样式初始设置为不可见 -->
<!-- 设置该 ImageView 的宽度根据其内部要显示的图片内容自适应,也就是刚好能包裹住图片的宽度 -->
<!-- 设置该 ImageView 的高度根据其内部要显示的图片内容自适应,刚好能包裹住图片的高度 -->
<!-- 设置该 ImageView 在其父容器(外层的 FrameLayout内的对齐方式为右下角对齐确定其显示位置 -->
<!-- 设置该 ImageView 不可获取焦点,意味着用户不能通过焦点操作(比如通过方向键、触摸焦点等方式)与它进行交互 -->
<!-- 设置该 ImageView 初始状态为不可见,可能在后续满足某些条件(比如用户选择了蓝色背景选项等)时,通过代码将其设置为可见来表示相应的选中状态 -->
<!-- 设置该 ImageView 距离其父容器(外层的 FrameLayout右侧的间距为 3 设备独立像素dip用于微调其在水平方向上的位置 -->
<!-- 设置该 ImageView 要显示的图片资源引用名为“selected”的可绘制资源通常是图片资源这个图片应该是用于体现选中状态的特定样式 -->
<!-- 初始设置该FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间通常用于多个同层级FrameLayout按权重划分父容器宽度 -->
<!-- 设置该FrameLayout的高度与父容器高度相匹配使其在垂直方向上填满整个父容器空间 -->
<!-- 设置权重为1意味着在水平方向上它会按照比例去分配剩余空间和同层级其他设置了权重的布局一起确定各自所占宽度比例 -->
<!-- 为该ImageView控件定义一个唯一标识符id从命名推测是用于展示白色背景相关的图片或视觉元素在界面布局中起到对应的显示作用 -->
<!-- 设置该ImageView的宽度与父容器这里就是外层的FrameLayout宽度相匹配使其在水平方向上填满整个父容器空间 -->
<!-- 设置该ImageView的高度与父容器高度相匹配使其在垂直方向上填满整个父容器空间 -->
<!-- 为该ImageView控件定义一个唯一标识符id推测是用于表示白色背景是否被选中的一个指示性元素初始状态通常是不可见的后续根据选择逻辑来控制显示与否 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应也就是刚好能包裹住图片的宽度 -->
<!-- 设置该ImageView在其父容器外层的FrameLayout内的对齐方式为右下角对齐确定其在布局中的显示位置 -->
<!-- 设置该ImageView不可获取焦点意味着用户不能通过焦点相关操作如使用方向键、触摸焦点等方式与它进行交互 -->
<!-- 设置该ImageView初始状态为不可见等待满足特定条件比如用户选择了白色背景选项等情况再通过代码将其设置为可见来体现相应的选中状态 -->
<!-- 设置该ImageView距离其父容器外层的FrameLayout右侧的间距为2设备独立像素dip用于微调其在水平方向上的位置 -->
<!-- 设置该ImageView要显示的图片资源引用名为“selected”的可绘制资源通常是图片资源该图片一般用于表示选中的特定样式 -->
<!-- 为该ImageView控件定义一个唯一标识符id从命名来看是用于展示绿色背景相关的图片或视觉元素用于界面的相关显示需求 -->
<!-- 设置该ImageView的宽度与父容器这里的外层FrameLayout宽度相匹配在水平方向上填满整个父容器空间 -->
<!-- 设置该ImageView的高度与父容器高度相匹配在垂直方向上填满整个父容器空间 -->
<!-- 为该ImageView控件定义一个唯一标识符id推测是用于表示绿色背景是否被选中的指示性元素初始状态通常是不可见的 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应能包裹住图片宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应能包裹住图片高度 -->
<!-- 设置该ImageView在其父容器外层FrameLayout内的对齐方式为右下角对齐确定其显示位置 -->
<!-- 设置该ImageView不可获取焦点用户不能通过焦点操作与之交互 -->
<!-- 设置该ImageView初始状态为不可见待满足特定条件后可通过代码控制显示来体现选中状态 -->
<!-- 设置该ImageView要显示的图片资源引用名为“selected”的可绘制资源用于表示选中的样式 -->
<!-- 为该ImageView控件定义一个唯一标识符id从命名推测是用于展示红色背景相关的图片或视觉元素在界面布局中有对应的显示作用 -->
<!-- 设置该ImageView的宽度与父容器外层FrameLayout宽度相匹配在水平方向上填满整个父容器空间 -->
<!-- 设置该ImageView的高度与父容器高度相匹配在垂直方向上填满整个父容器空间 -->
<!-- 为该ImageView控件定义一个唯一标识符id推测是用于表示红色背景是否被选中的指示性元素初始状态一般是不可见的 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应能包裹住图片宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应能包裹住图片高度 -->
<!-- 设置该ImageView在其父容器外层FrameLayout内的对齐方式为右下角对齐确定其显示位置 -->
<!-- 设置该ImageView不可获取焦点用户无法通过焦点操作与之交互 -->
<!-- 设置该ImageView初始状态为不可见后续根据特定条件可通过代码控制显示来体现选中状态 -->
<!-- 设置该ImageView要显示的图片资源引用名为“selected”的可绘制资源用于表示选中的样式 -->
<!-- 结束前面的LinearLayout布局定义与对应的开始标签相匹配完成该线性布局结构的声明 -->
<!-- 为该LinearLayout定义一个唯一标识符id方便在代码中对其进行引用、操作从命名推测可能是用于字体大小选择相关的布局 -->
<!-- 设置该LinearLayout的宽度占满父容器使其在水平方向上填满整个父容器空间 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的高度 -->
<!-- 设置该LinearLayout的背景引用名为font_size_selector_bg的可绘制资源通常是图片、颜色等用于作为背景的资源作为背景 -->
<!-- 设置该LinearLayout在其父容器中的对齐方式为底部对齐使其显示在父容器的底部位置 -->
<!-- 设置该LinearLayout初始状态为不可见可能在满足某些条件比如用户点击相关按钮等操作后才会显示出来 -->
<!-- 为该FrameLayout定义一个唯一标识符id从命名推测可能与字体大小为小的相关设置布局有关 -->
<!-- 初始设置该FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间 -->
<!-- 设置该FrameLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间通常用于和同层级其他设置了权重的布局共同划分父容器的宽度 -->
<!-- 设置该LinearLayout的宽度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的宽度 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素将从上到下依次排列 -->
<!-- 设置该LinearLayout在其父容器这里是外层的FrameLayout内的对齐方式为居中对齐 -->
<!-- 设置该LinearLayout内部子元素的对齐方式为居中对齐使子元素在该布局内处于中心位置 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应也就是刚好能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应刚好能包裹住图片的高度 -->
<!-- 设置该ImageView要显示的图片资源引用名为font_small的可绘制资源通常是图片资源从命名推测是表示小字体相关的图标 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为5设备独立像素dip用于调整其垂直方向上的位置 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应能包裹住文本的宽度 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应能包裹住文本的高度 -->
<!-- 设置该TextView要显示的文本内容引用名为menu_font_small的字符串资源从命名推测是用于表示小字体相关的文字描述 -->
<!-- 应用名为TextAppearanceUnderMenuIcon的样式来设置文本的外观例如字体、字号、颜色等属性该样式通常在样式资源文件中定义 -->
<!-- 为该ImageView定义一个唯一标识符id从命名推测可能是用于表示小字体选项是否被选中的相关显示元素初始状态通常是不可见的 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应能包裹住图片的 height -->
<!-- 设置该ImageView在其父容器外层的FrameLayout内的对齐方式为右下角对齐确定其在布局中的显示位置 -->
<!-- 设置该ImageView距离其父容器右侧的间距为6设备独立像素dip用于微调其在水平方向上的位置 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为 -7设备独立像素dip这里的负数值可能用于特殊的布局调整效果 -->
<!-- 设置该ImageView不可获取焦点意味着用户不能通过焦点相关操作如使用方向键、触摸焦点等方式与它进行交互 -->
<!-- 设置该ImageView初始状态为不可见等待满足特定条件比如用户选择了小字体选项等情况再通过代码将其设置为可见来体现相应的选中状态 -->
<!-- 设置该ImageView要显示的图片资源引用名为“selected”的可绘制资源通常是图片资源该图片一般用于表示选中的特定样式 -->
<!-- 结束前面的FrameLayout布局定义与对应的开始标签相匹配完成该帧布局结构的声明 -->
<!-- 为该FrameLayout定义一个唯一标识符id从命名推测可能与字体大小为正常常规的相关设置布局有关方便后续在代码中引用操作 -->
<!-- 初始设置该FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间 -->
<!-- 设置该FrameLayout的高度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的高度 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间通常用于和同层级其他设置了权重的布局共同划分父容器这里是外层的LinearLayout的宽度 -->
<!-- 设置该LinearLayout的宽度根据其内部子元素自适应即刚好能包裹住内部子元素所需要的宽度 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素将从上到下依次排列 -->
<!-- 设置该LinearLayout在其父容器这里是外层的FrameLayout内的对齐方式为居中对齐 -->
<!-- 设置该LinearLayout内部子元素的对齐方式为居中对齐使子元素在该布局内处于中心位置 -->
<!-- 设置该LinearLayout的宽度根据其内部子元素自适应即刚好能包裹住内部子元素所需要的宽度 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素将从上到下依次排列 -->
<!-- 设置该LinearLayout在其父容器这里是外层的FrameLayout内的对齐方式为居中对齐 -->
<!-- 设置该LinearLayout内部子元素的对齐方式为居中对齐使子元素在该布局内处于中心位置 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应也就是刚好能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应刚好能包裹住图片的高度 -->
<!-- 设置该ImageView要显示的图片资源引用名为font_normal的可绘制资源通常是图片资源从命名推测是表示正常常规字体相关的图标 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为5设备独立像素dip用于调整其垂直方向上的位置 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应能包裹住文本的宽度 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应能包裹住文本的高度 -->
<!-- 设置该TextView要显示的文本内容引用名为menu_font_normal的字符串资源从命名推测是用于表示正常常规字体相关的文字描述 -->
<!-- 应用名为TextAppearanceUnderMenuIcon的样式来设置文本的外观例如字体、字号、颜色等属性该样式通常在样式资源文件中定义 -->
<!-- 为该ImageView定义一个唯一标识符id从命名推测可能是用于表示正常常规字体选项是否被选中的相关显示元素初始状态通常是不可见的 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应能包裹住图片的高度 -->
<!-- 设置该ImageView在其父容器外层的FrameLayout内的对齐方式为右下角对齐确定其在布局中的显示位置 -->
<!-- 设置该ImageView不可获取焦点意味着用户不能通过焦点相关操作如使用方向键、触摸焦点等方式与它进行交互 -->
<!-- 设置该ImageView初始状态为不可见等待满足特定条件比如用户选择了正常字体选项等情况再通过代码将其设置为可见来体现相应的选中状态 -->
<!-- 设置该ImageView距离其父容器右侧的间距为6设备独立像素dip用于微调其在水平方向上的位置 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为 -7设备独立像素dip这里的负数值可能用于特殊的布局调整效果 -->
<!-- 设置该ImageView要显示的图片资源引用名为“selected”的可绘制资源通常是图片资源该图片一般用于表示选中的特定样式 -->
<!-- 为该FrameLayout定义一个唯一标识符id从命名推测可能与字体大小为大的相关设置布局有关便于后续代码中对其进行引用等操作 -->
<!-- 初始设置该FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间 -->
<!-- 初始设置该FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间用于和同层级其他设置了权重的布局共同划分父容器的宽度 -->
<!-- 设置该LinearLayout的宽度根据其内部子元素自适应能包裹住内部子元素所需的宽度 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应能包裹住内部子元素的高度 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,子元素按从上到下顺序排列 -->
<!-- 设置该LinearLayout在其父容器外层的FrameLayout内的对齐方式为居中对齐 -->
<!-- 设置该LinearLayout内部子元素的对齐方式为居中对齐让子元素处于该布局中心位置 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应包裹住图片宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应包裹住图片高度 -->
<!-- 设置该ImageView要显示的图片资源引用名为font_large的可绘制资源通常是图片资源推测是表示大字体相关的图标 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为5设备独立像素dip调整垂直位置 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应包裹住文本宽度 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应包裹住文本高度 -->
<!-- 设置该TextView要显示的文本内容引用名为menu_font_large的字符串资源用于表示大字体相关文字描述 -->
<!-- 应用样式设置文本外观,样式在对应资源文件中定义 -->
<!-- 结束前面的LinearLayout布局定义与对应的开始标签相匹配完成该线性布局结构的声明 -->
<!-- 为该ImageView定义一个唯一标识符id从命名推测是用于表示大字体选项是否被选中的相关显示元素方便在代码中对其进行操作和引用 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应也就是刚好能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应刚好能包裹住图片的高度 -->
<!-- 设置该ImageView在其父容器这里的父容器应该是外层与之对应的布局元素可能是上一层的FrameLayout内的对齐方式为右下角对齐确定其显示位置 -->
<!-- 设置该ImageView不可获取焦点意味着用户不能通过焦点相关操作比如使用方向键、触摸焦点等方式与它进行交互 -->
<!-- 设置该ImageView初始状态为不可见等待满足特定条件比如用户选择了大字体选项等情况再通过代码将其设置为可见来体现相应的选中状态 -->
<!-- 设置该ImageView距离其父容器右侧的间距为6设备独立像素dip用于微调其在水平方向上的位置 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为 -7设备独立像素dip这里的负数值可能用于特殊的布局调整效果使其在垂直方向上能达到特定的布局位置 -->
<!-- 设置该ImageView要显示的图片资源引用名为“selected”的可绘制资源通常是图片资源该图片一般用于表示选中的特定样式 -->
<!-- 结束前面的FrameLayout布局定义与对应的开始标签相匹配完成该帧布局结构的声明 -->
<!-- 为该FrameLayout定义一个唯一标识符id从命名推测可能与字体大小为超大的相关设置布局有关便于后续在代码中对其进行引用和操作 -->
<!-- 初始设置该FrameLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间 -->
<!-- 设置该FrameLayout的高度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的高度 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间通常用于和同层级其他设置了权重的布局共同划分父容器这里应该是外层的LinearLayout的宽度 -->
<!-- 设置该LinearLayout的宽度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的宽度 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素将从上到下依次排列 -->
<!-- 设置该LinearLayout在其父容器这里是外层的FrameLayout内的对齐方式为居中对齐 -->
<!-- 设置该LinearLayout内部子元素的对齐方式为居中对齐使子元素在该布局内处于中心位置 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应也就是刚好能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应刚好能包裹住图片的高度 -->
<!-- 设置该ImageView要显示的图片资源引用名为font_super的可绘制资源通常是图片资源从命名推测是表示超大字体相关的图标 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为5设备独立像素dip用于调整其垂直方向上的位置 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应能包裹住文本的宽度 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应能包裹住文本的高度 -->
<!-- 设置该TextView要显示的文本内容引用名为menu_font_super的字符串资源从命名推测是用于表示超大字体相关的文字描述 -->
<!-- 应用名为TextAppearanceUnderMenuIcon的样式来设置文本的外观例如字体、字号、颜色等属性该样式通常在样式资源文件中定义 -->
<!-- 为该ImageView定义一个唯一标识符id从命名推测可能是用于表示超大字体选项是否被选中的相关显示元素初始状态通常是不可见的 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应能包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应能包裹住图片的高度 -->
<!-- 设置该ImageView在其父容器外层的FrameLayout内的对齐方式为右下角对齐确定其在布局中的显示位置 -->
<!-- 设置该ImageView不可获取焦点意味着用户不能通过焦点相关操作与它进行交互 -->
<!-- 设置该ImageView初始状态为不可见等待满足特定条件比如用户选择了超大字体选项等情况再通过代码将其设置为可见来体现相应的选中状态 -->
<!-- 设置该ImageView距离其父容器右侧的间距为6设备独立像素dip用于微调其在水平方向上的位置 -->
<!-- 设置该ImageView距离其底部相邻元素的间距为 -7设备独立像素dip用于特殊的布局调整效果 -->
<!-- 设置该ImageView要显示的图片资源引用名为“selected”的可绘制资源通常是图片资源用于表示选中的特定样式 -->
<!-- 结束最外层的FrameLayout布局定义与整个XML文件开头的<FrameLayout>标签相对应,完成整个布局结构的声明 -->
<!-- 结束前面的LinearLayout布局定义与对应的开始标签相匹配完成该线性布局结构的声明 -->
</FrameLayout>

@ -1,14 +1,24 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该XML文件遵循的版本是1.0使用的编码格式为utf-8这是XML文件开头的标准标识用于告知解析器如何正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种布局属性以及控件相关的属性了 -->
<!-- 设置LinearLayout线性布局的宽度占满父容器使其在水平方向上填满整个父容器空间 -->
<!-- 设置LinearLayout的高度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的高度 -->
<CheckBox
android:id="@+id/cb_edit_item"
@ -17,13 +27,6 @@
android:checked="false"
android:focusable="false"
android:layout_gravity="top|left" />
<!-- 为该CheckBox控件定义一个唯一标识符id方便在后续代码中对其进行引用、操作等 -->
<!-- 设置CheckBox的宽度根据其自身内容如勾选框图标等自适应也就是刚好能包裹住其内容的宽度 -->
<!-- 设置CheckBox的高度为28设备独立像素dip确定其垂直方向上的固定尺寸 -->
<!-- 设置该CheckBox初始状态为未勾选 -->
<!-- 设置该CheckBox不可获取焦点意味着用户不能通过焦点操作比如使用方向键等方式使其获得焦点 -->
<!-- 设置该CheckBox在其父容器这里是外层的LinearLayout内的对齐方式为左上角对齐确定其在布局中的位置 -->
<net.micode.notes.ui.NoteEditText
android:id="@+id/et_edit_text"
@ -32,31 +35,5 @@
android:lineSpacingMultiplier="1.2"
android:layout_gravity="center_vertical"
android:textAppearance="@style/TextAppearancePrimaryItem"
android:background="@null"
/>
<!-- 为该NoteEditText控件定义一个唯一标识符id从命名推测可能是用于编辑文本内容的输入框 -->
<!-- 设置该NoteEditText的宽度占满父容器这里的父容器是外层的LinearLayout使其在水平方向上填满整个可用空间 -->
<!-- 设置该NoteEditText的高度根据其内部文本内容自适应也就是刚好能包裹住文本的高度 -->
<!-- 设置文本行间距倍数为1.2,用于增加文本行之间的间距,使文本显示更清晰美观 -->
<!-- 设置该NoteEditText在其父容器内的对齐方式为垂直居中对齐确保其在垂直方向上处于合适位置 -->
<!-- 应用名为TextAppearancePrimaryItem的样式来设置文本的外观例如字体、字号、颜色等属性该样式通常在样式资源文件中定义 -->
<!-- 设置背景为空,即不显示默认的背景样式,可能是为了让输入框更好地融入整体界面或者根据需要自定义背景效果 -->
</LinearLayout><!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明说明代码所属的开源社区是The MiCode Open Source Community版权时间范围为2010 - 2011年
Licensed under the Apache License, Version 2.0 (the "License");
表示该代码遵循Apache License 2.0开源协议进行授权许可,意味着使用该代码需要遵循此协议规定
you may not use this file except in compliance with the License.
强调若要使用这个文件必须按照上述Apache License 2.0协议来操作
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问此网址http://www.apache.org/licenses/LICENSE-2.0获取Apache 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.
提示查看协议以了解关于权限及限制方面的详细内容 -->
android:background="@null" />
</LinearLayout>

@ -1,53 +1,37 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该XML文件遵循的版本是1.0使用的编码格式为utf-8这是XML文件开头的标准标识用于告知解析器按照此版本和编码来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处为版权相关声明说明该代码隶属于The MiCode Open Source Community这个开源社区版权有效期在2010至2011年之间
Licensed under the Apache License, Version 2.0 (the "License");
表示此代码遵循Apache License 2.0开源协议进行授权许可,意味着使用该代码时必须遵守此协议所规定的各项要求
you may not use this file except in compliance with the License.
着重强调若要使用本文件必须严格按照上述的Apache License 2.0协议来操作
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可通过访问这个网址http://www.apache.org/licenses/LICENSE-2.0来获取Apache 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.
提示查看协议内容,以便了解关于权限以及限制方面的详细规定 -->
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/note_item"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- 引入安卓的命名空间,后续可借助此命名空间使用安卓系统所定义的各类布局属性和控件相关属性 -->
<!-- 为该FrameLayout定义一个唯一标识符id方便在代码中对其进行引用、操作从命名推测可能与笔记相关的某个项目布局 -->
<!-- 设置FrameLayout的宽度占满父容器使其在水平方向上填满所在父容器的全部可用空间 -->
<!-- 设置FrameLayout的高度占满父容器即在垂直方向上填满所在父容器的全部可用空间 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical">
<!-- 设置LinearLayout的宽度占满父容器这里的父容器就是外层的FrameLayout使其在水平方向上填满整个父布局空间 -->
<!-- 设置LinearLayout的高度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的高度 -->
<!-- 设置该LinearLayout在其父容器FrameLayout内的对齐方式为垂直居中对齐确保其在垂直方向上处于合适位置 -->
<!-- 设置该LinearLayout内部子元素的对齐方式为垂直居中对齐使子元素在该线性布局内垂直方向上处于中心位置 -->
<LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<!-- 初始设置该LinearLayout的宽度为0设备独立像素dip后续会结合layout_weight属性来按比例分配水平方向上的空间 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间用于和同层级其他设置了权重的布局共同划分父容器的宽度 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素将从上到下依次排列 -->
<TextView
android:id="@+id/tv_name"
@ -56,20 +40,11 @@
android:layout_weight="1"
android:textAppearance="@style/TextAppearancePrimaryItem"
android:visibility="gone" />
<!-- 为该TextView控件定义一个唯一标识符id从命名推测可能用于显示名称相关信息不过当前设置为不可见 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应能包裹住文本的宽度 -->
<!-- 初始设置该TextView的高度为0设备独立像素dip后续结合layout_weight属性分配垂直方向空间 -->
<!-- 设置权重为1在垂直方向上按比例分配剩余空间通常用于占据较多垂直空间 -->
<!-- 应用名为TextAppearancePrimaryItem的样式来设置文本的外观像字体、字号、颜色等属性在对应的样式资源文件中定义 -->
<!-- 设置该TextView初始状态为不可见可能在满足某些条件后才显示出来 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<!-- 设置该LinearLayout的宽度占满父容器这里的父容器是外层的垂直方向的LinearLayout在水平方向上填满空间 -->
<!-- 设置该LinearLayout的高度根据其内部子元素自适应包裹住内部子元素的高度 -->
<!-- 设置该LinearLayout在其父容器内的对齐方式为垂直居中对齐 -->
<TextView
android:id="@+id/tv_title"
@ -77,22 +52,12 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true" />
<!-- 为该TextView控件定义一个唯一标识符id从命名推测可能用于显示标题相关信息 -->
<!-- 初始设置该TextView的宽度为0设备独立像素dip后续结合layout_weight属性分配水平方向空间 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应能包裹住文本的高度 -->
<!-- 设置权重为1在水平方向上按比例分配剩余空间通常占据较多水平空间 -->
<!-- 设置该TextView只能显示单行文本多余文本可能会截断显示 -->
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearanceSecondaryItem" />
<!-- 为该TextView控件定义一个唯一标识符id从命名推测可能用于显示时间相关信息 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应能包裹住文本的宽度 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应能包裹住文本的高度 -->
<!-- 应用名为TextAppearanceSecondaryItem的样式来设置文本的外观 -->
</LinearLayout>
</LinearLayout>
@ -104,19 +69,10 @@
android:clickable="false"
android:visibility="gone" />
</LinearLayout>
<!-- 为该CheckBox控件定义一个唯一标识符id这里使用了安卓系统内置的命名空间下的id可能是遵循某种规范来定义用于一些标准的勾选操作相关功能 -->
<!-- 设置CheckBox的宽度根据其自身内容如勾选框图标等自适应包裹住其内容的宽度 -->
<!-- 设置CheckBox的高度根据其自身内容自适应包裹住其内容的高度 -->
<!-- 设置该CheckBox不可获取焦点意味着用户不能通过焦点操作如使用方向键等方式使其获得焦点 -->
<!-- 设置该CheckBox不可点击用户无法通过点击操作来改变其勾选状态等 -->
<!-- 设置该CheckBox初始状态为不可见可能在特定条件下才会显示并发挥作用 -->
<ImageView
android:id="@+id/iv_alert_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right" />
</FrameLayout><!-- 为该ImageView控件定义一个唯一标识符id从命名推测可能用于显示提醒相关的图标 -->
<!-- 设置该ImageView的宽度根据其内部要显示的图片内容自适应包裹住图片的宽度 -->
<!-- 设置该ImageView的高度根据其内部要显示的图片内容自适应包裹住图片的 height -->
<!-- 设置该ImageView在其父容器FrameLayout内的对齐方式为右上角对齐确定其在布局中的显示位置 -->
android:layout_gravity="top|right"/>
</FrameLayout>

@ -1,24 +1,30 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/list_background">
<!-- 设置 FrameLayout帧布局的宽度占满父容器意味着它在水平方向上会填满所在父容器的全部可用空间 -->
<!-- 设置 FrameLayout 的高度占满父容器,也就是在垂直方向上会填满所在父容器的全部可用空间 -->
<!-- 设置 FrameLayout 的背景这里引用了名为“list_background”的可绘制资源通常可以是图片、颜色等能作为背景的资源来作为该布局的背景 -->
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种布局属性以及控件相关的属性了 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<!-- 设置 LinearLayout线性布局的宽度占满父容器此处父容器为外层的 FrameLayout使其在水平方向上填满整个父布局空间 -->
<!-- 设置 LinearLayout 的高度占满父容器,让它在垂直方向上也填满整个父布局空间 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素会按照从上到下的顺序依次排列 -->
<TextView
android:id="@+id/tv_title_bar"
@ -30,15 +36,6 @@
android:singleLine="true"
android:textColor="#FFEAD1AE"
android:textSize="@dimen/text_font_size_medium" />
<!-- 为这个 TextView 控件定义一个唯一标识符id从命名推测可能用于显示标题栏相关的文本信息 -->
<!-- 设置该 TextView 的宽度占满父容器(这里的父容器是外层的 LinearLayout使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 TextView 的高度根据其要显示的文本内容自适应,也就是刚好能包裹住文本的高度 -->
<!-- 设置该 TextView 的背景引用名为“title_bar_bg”的可绘制资源通常是图片、颜色等用于作为背景的资源作为背景 -->
<!-- 设置该 TextView 初始状态为不可见,可能在满足某些条件(比如特定页面显示、用户操作后等)后才会显示出来 -->
<!-- 设置文本在该 TextView 控件内的对齐方式为垂直居中对齐,使文本在垂直方向上处于中间位置 -->
<!-- 设置该 TextView 只能显示单行文本,多余的文本内容可能会被截断显示 -->
<!-- 设置该 TextView 显示文本的颜色,这里使用十六进制颜色值 #FFEAD1AE 来指定颜色 -->
<!-- 设置该 TextView 显示文本的字号大小引用名为“text_font_size_medium”的尺寸资源来确定具体字号该资源通常在对应的资源文件中定义 -->
<ListView
android:id="@+id/notes_list"
@ -47,15 +44,9 @@
android:layout_weight="1"
android:cacheColorHint="@null"
android:listSelector="@android:color/transparent"
android:divider="@null" />
android:divider="@null"
android:fadingEdge="@null" />
</LinearLayout>
<!-- 为这个 ListView 控件定义一个唯一标识符id从命名推测是用于展示笔记列表相关内容的列表视图 -->
<!-- 设置该 ListView 的宽度占满父容器(这里的父容器是外层的 LinearLayout使其在水平方向上填满整个父容器空间 -->
<!-- 初始设置该 ListView 的高度为 0 设备独立像素dip后续会结合 layout_weight 属性来按比例分配垂直方向上的空间 -->
<!-- 设置权重为 1在垂直方向上按比例分配剩余空间通常用于使其占据较大的垂直空间以展示列表内容 -->
<!-- 设置缓存颜色提示为 null这样可以避免 ListView 在滚动等操作时出现颜色相关的显示问题(比如闪烁等) -->
<!-- 设置列表项被选中时的背景颜色为透明,让列表项在选中时视觉上更自然,不会出现默认的选中背景色 -->
<!-- 设置列表项之间的分割线为 null即不显示分割线使列表外观更简洁 -->
<Button
android:id="@+id/btn_new_note"
@ -64,13 +55,7 @@
android:layout_height="wrap_content"
android:focusable="false"
android:layout_gravity="bottom" />
<!-- 为这个 Button 控件定义一个唯一标识符id从命名推测可能是用于点击创建新笔记的按钮 -->
<!-- 设置该 Button 的背景引用名为“new_note”的可绘制资源通常是图片资源作为背景比如按钮的外观样式图片等 -->
<!-- 设置该 Button 的宽度与父容器宽度匹配,使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 Button 的高度根据其内部文本或图标等内容自适应,包裹住内容的高度 -->
<!-- 设置该 Button 不可获取焦点,意味着用户不能通过焦点操作(比如使用方向键等方式)使其获得焦点 -->
<!-- 设置该 Button 在其父容器(这里的父容器是外层的 FrameLayout内的对齐方式为底部对齐使其显示在底部位置 -->
<Button
android:id="@+id/btn_set"
android:background="@drawable/ic_menu_more"
@ -81,29 +66,4 @@
android:layout_margin="10dp"
android:onClick="OnOpenMenu"
android:layout_gravity="bottom|right" />
</FrameLayout><!-- 为这个 Button 控件定义一个唯一标识符id从命名推测可能是用于点击打开设置相关菜单之类的按钮 -->
<!-- 设置该 Button 的背景引用名为“ic_menu_more”的可绘制资源通常是图片资源作为背景 -->
<!-- 设置该 Button 的宽度根据其内部文本或图标等内容自适应,包裹住内容的宽度 -->
<!-- 设置该 Button 的高度根据其内部文本或图标等内容自适应,包裹住内容的高度 -->
<!-- 设置该 Button 不可获取焦点,意味着用户不能通过焦点操作与它进行交互 -->
<!-- 设置该 Button 的内边距为 10 设备独立像素dp也就是在按钮内容文本、图标等的四周留出一定的空白空间 -->
<!-- 设置该 Button 的外边距为 10 设备独立像素dp用于调整按钮与周围元素在水平和垂直方向上的间距 -->
<!-- 设置点击该 Button 时触发的方法名为“OnOpenMenu”需要在对应的代码逻辑中实现这个方法来处理点击事件 -->
<!-- 设置该 Button 在其父容器(外层的 FrameLayout内的对齐方式为右下角对齐使其显示在右下角位置 -->
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
这里是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围是 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守此协议的相关规定。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问这个网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限以及限制方面的详细规定。 -->
</FrameLayout>

@ -1,46 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析文件内容 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/navigation_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种布局属性以及控件相关的属性了 -->
<!-- 为该 LinearLayout 定义一个唯一标识符id方便在后续代码中对其进行引用、操作等从命名来看可能是用于导航栏相关的布局 -->
<!-- 设置 LinearLayout线性布局的宽度与父容器宽度相匹配使其在水平方向上填满整个父容器空间 -->
<!-- 设置 LinearLayout 的高度与父容器高度相匹配,使其在垂直方向上填满整个父容器空间 -->
<!-- 设置该线性布局内子元素的排列方向为水平方向,意味着子元素会按照从左到右的顺序依次排列 -->
http://www.apache.org/licenses/LICENSE-2.0
<Button
android:id="@+id/selection_menu"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/navigation_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="?android:attr/listDividerAlertDialog"
android:gravity="left|center_vertical"
android:singleLine="true" />
<!-- 为该 Button 控件定义一个唯一标识符id从命名推测可能是用于选择菜单相关操作的按钮 -->
<!-- 设置按钮的分割线样式,这里引用了安卓系统内置属性(?android:attr/listDividerAlertDialog来指定分割线的样式通常用于在按钮相关显示上呈现分割效果 -->
<!-- 设置该 Button 只能显示单行文本,若文本内容过长可能会被截断显示 -->
<!-- 设置文本在该 Button 控件内的对齐方式,水平方向居左对齐、垂直方向居中对齐,让文本在按钮内处于合适位置 -->
<!-- 设置该 Button 的宽度根据其内部要显示的文本或图标等内容自适应,也就是刚好能包裹住这些内容的宽度 -->
<!-- 设置该 Button 的高度与父容器(这里就是外层的 LinearLayout高度相匹配使其在垂直方向上填满整个父容器空间 -->
<!-- 应用安卓系统内置的样式(?android:attr/borderlessButtonStyle来设置按钮的外观风格通常这种样式会使按钮呈现无边框的效果 -->
android:orientation="horizontal">
</LinearLayout><!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表明这份代码遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守此协议规定的相关要求。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
提示可以通过访问这个网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提醒查看协议内容,以了解关于权限以及限制方面的详细规定。 -->
<Button android:id="@+id/selection_menu"
android:divider="?android:attr/listDividerAlertDialog"
android:singleLine="true"
android:gravity="left|center_vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>

@ -1,6 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照相应版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<View
xmlns:android="http://schemas.android.com/apk/res/android"
@ -8,26 +21,4 @@
android:layout_height="100dip"
android:visibility="invisible"
android:focusable="false"
android:background="@drawable/list_footer_bg" /><!-- 引入安卓的命名空间,后续借助此命名空间就能使用安卓系统所定义的各类布局属性以及控件相关属性 -->
<!-- 设置 View视图的宽度占满父容器使其在水平方向上填满所在父容器的全部可用空间 -->
<!-- 设置 View 的高度为 100 设备独立像素dip确定其在垂直方向上的固定尺寸大小 -->
<!-- 设置该 View 的初始可见性为不可见状态,不过它依然会占据布局空间,只是用户看不到它,与 "gone" 不同的是,它的空间不会被回收 -->
<!-- 设置该 View 不可获取焦点,意味着用户不能通过焦点操作(例如使用方向键、触摸焦点等方式)使其获得焦点 -->
<!-- 设置该 View 的背景,引用名为 "list_footer_bg" 的可绘制资源(通常是图片、颜色等可作为背景的资源)来作为该 View 的背景 -->
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
这里是版权相关声明,说明该代码隶属于 The MiCode Open Source Community 这个开源社区,版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表明这份代码遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守此协议所规定的各项要求。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可通过访问这个网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限以及限制方面的详细规定。 -->
android:background="@drawable/list_footer_bg" />

@ -1,29 +1,25 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处为版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- 设置LinearLayout线性布局的宽度占满父容器使其在水平方向上填满整个父容器空间 -->
<!-- 设置LinearLayout的高度根据其内部子元素自适应也就是刚好能包裹住内部子元素所需的高度 -->
<!-- 设置该线性布局内子元素的排列方向为垂直方向,意味着子元素会按照从上到下的顺序依次排列 -->
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种布局属性以及控件相关的属性了 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/preference_sync_button"
@ -33,24 +29,13 @@
android:layout_marginLeft="30dip"
android:layout_marginRight="30dip"
style="?android:attr/textAppearanceMedium"
android:text="@string/preferences_button_sync_immediately" />
<!-- 为该Button控件定义一个唯一标识符id从命名推测可能是用于执行偏好设置preference中同步相关操作的按钮 -->
<!-- 设置该Button的宽度占满父容器这里的父容器是外层的LinearLayout使其在水平方向上填满整个父容器空间 -->
<!-- 设置该Button的高度根据其内部文本或图标等内容自适应也就是刚好能包裹住这些内容的高度 -->
<!-- 设置该Button距离其顶部相邻元素的间距为15设备独立像素dip用于调整其在垂直方向上的位置 -->
<!-- 设置该Button距离其左边相邻元素的间距为30设备独立像素dip用于调整其在水平方向上的位置 -->
<!-- 设置该Button距离其右边相邻元素的间距为30设备独立像素dip用于调整其在水平方向上的位置 -->
<!-- 应用安卓系统内置属性(?android:attr/textAppearanceMedium来设置按钮上文本的外观样式例如字体、字号、颜色等属性使其呈现出中等外观的样式 -->
<!-- 设置该Button要显示的文本内容引用名为“preferences_button_sync_immediately”的字符串资源该资源通常在对应的字符串资源文件中定义从命名推测是提示立即同步相关的文字描述 -->
android:text="@string/preferences_button_sync_immediately"/>
<TextView
android:id="@+id/prefenerece_sync_status_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</LinearLayout><!-- 为该TextView控件定义一个唯一标识符id从命名推测可能是用于显示偏好设置preference中同步状态相关信息的文本视图 -->
<!-- 设置该TextView的宽度根据其要显示的文本内容自适应也就是刚好能包裹住文本的宽度 -->
<!-- 设置该TextView的高度根据其要显示的文本内容自适应也就是刚好能包裹住文本的高度 -->
<!-- 设置该TextView在其父容器外层的LinearLayout内的对齐方式为居中对齐使其在布局中处于中心位置 -->
<!-- 设置该TextView初始状态为不可见可能在满足某些条件比如同步操作进行中、完成等情况后才会显示出来 -->
android:visibility="gone"/>
</LinearLayout>

@ -1,24 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<!-- 设置文本行间距倍数为 1.2,用于增加文本行之间的间距,使文本显示更清晰美观 -->
<!-- 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种布局属性以及控件相关的属性了 -->
<!-- 设置 FrameLayout帧布局的宽度占满父容器意味着它在水平方向上会填满所在父容器的全部可用空间 -->
<!-- 设置 FrameLayout 的高度占满父容器,也就是在垂直方向上会填满所在父容器的全部可用空间 -->
<ImageView
android:id="@+id/widget_bg_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<!-- 为该 ImageView 控件定义一个唯一标识符id从命名推测可能是用于显示部件widget背景相关图片的视图 -->
<!-- 设置该 ImageView 的宽度占满父容器(这里的父容器是外层的 FrameLayout使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 ImageView 的高度占满父容器,让它在垂直方向上也填满整个父容器空间 -->
<TextView
android:id="@+id/widget_text"
android:layout_width="fill_parent"
@ -30,28 +34,4 @@
android:textColor="#FF663300"
android:maxLines="6"
android:lineSpacingMultiplier="1.2" />
<!-- 为该 TextView 控件定义一个唯一标识符id从命名推测可能是用于在部件widget上显示文本内容的视图 -->
<!-- 设置该 TextView 的宽度占满父容器(这里的父容器是外层的 FrameLayout使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 TextView 的高度占满父容器,让它在垂直方向上也填满整个父容器空间 -->
<!-- 设置该 TextView 顶部的内边距为 30 设备独立像素dip也就是在文本内容上方留出一定的空白空间 -->
<!-- 设置该 TextView 左侧的内边距为 8 设备独立像素dip在文本内容左侧留出空白空间 -->
<!-- 设置该 TextView 显示文本的字号大小为 14 可缩放像素sp可根据用户手机系统设置的字体大小进行相应缩放 -->
<!-- 设置该 TextView 显示文本的颜色,这里使用十六进制颜色值 #FF663300 来指定颜色 -->
<!-- 设置该 TextView 最多能显示的行数为 6 行,超出部分可能会被截断或者通过其他方式处理(比如显示省略号等) -->
<!-- 设置文本行间距倍数为 1.2,用于增加文本行之间的间距,使文本显示更清晰美观 -->
</FrameLayout><!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
这里是版权相关声明,说明该代码隶属于 The MiCode Open Source Community 这个开源社区,版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, 2.0 (the "License");
表明这份代码遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守此协议所规定的各项要求。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可通过访问这个网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限以及限制方面的详细规定。 -->
</FrameLayout>

@ -1,36 +1,29 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种布局属性以及控件相关的属性了 -->
<!-- 设置 FrameLayout帧布局的宽度占满父容器使其在水平方向上填满所在父容器的全部可用空间 -->
<!-- 设置 FrameLayout 的高度占满父容器,让它在垂直方向上也填满所在父容器的全部可用空间 -->
<ImageView
android:id="@+id/widget_bg_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<!-- 为该 ImageView 控件定义一个唯一标识符id从命名推测可能是用于显示部件widget的背景图片的视图 -->
<!-- 设置该 ImageView 的宽度占满父容器(这里的父容器是外层的 FrameLayout使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 ImageView 的高度占满父容器,让它在垂直方向上也填满整个父容器空间 -->
<TextView
android:id="@+id/widget_text"
@ -43,12 +36,4 @@
android:textColor="#FF663300"
android:maxLines="14"
android:lineSpacingMultiplier="1.2" />
</FrameLayout><!-- 为该 TextView 控件定义一个唯一标识符id从命名推测可能是用于在部件widget上显示文本内容的视图 -->
<!-- 设置该 TextView 的宽度占满父容器(这里的父容器是外层的 FrameLayout使其在水平方向上填满整个父容器空间 -->
<!-- 设置该 TextView 的高度占满父容器,让它在垂直方向上也填满整个父容器空间 -->
<!-- 设置该 TextView 顶部的内边距为 33 设备独立像素dip也就是在文本内容上方留出一定的空白空间 -->
<!-- 设置该 TextView 左侧的内边距为 10 设备独立像素dip在文本内容左侧留出空白空间 -->
<!-- 设置该 TextView 右侧的内边距为 10 设备独立像素dip在文本内容右侧留出空白空间 -->
<!-- 设置该 TextView 显示文本的颜色,这里使用十六进制颜色值 #FF663300 来指定颜色 -->
<!-- 设置该 TextView 最多能显示的行数为 14 行,超出的文本内容可能会被截断或者通过其他方式处理(比如显示省略号等) -->
<!-- 设置文本行间距倍数为 1.2,用于增加文本行之间的间距,使文本显示更清晰美观 -->
</FrameLayout>

@ -1,64 +1,48 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种菜单相关的属性 -->
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.
-->
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_delete"
android:title="@string/menu_delete" />
<!-- 为该菜单项定义一个唯一标识符id从命名“menu_delete”来看可能是用于执行删除相关操作的菜单项 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_delete”的字符串资源该资源通常在对应的字符串资源文件中定义用于明确提示用户该项的功能与删除有关 -->
<item
android:id="@+id/menu_font_size"
android:title="@string/menu_font_size" />
<!-- 为该菜单项定义一个唯一标识符id推测是用于操作字体大小相关设置的菜单项 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_font_size”的字符串资源提示用户点击该项可进行字体大小相关的操作 -->
android:title="@string/menu_font_size"/>
<item
android:id="@+id/menu_list_mode"
android:title="@string/menu_list_mode" />
<!-- 为该菜单项定义一个唯一标识符id可能是用于切换列表模式相关功能的菜单项 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_list_mode”的字符串资源告知用户该项与列表模式操作有关 -->
<item
android:id="@+id/menu_share"
android:title="@string/menu_share" />
<!-- 为该菜单项定义一个唯一标识符id显然是用于实现分享功能的菜单项 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_share”的字符串资源让用户明白点击该项可进行分享操作 -->
android:title="@string/menu_share"/>
<item
android:id="@+id/menu_send_to_desktop"
android:title="@string/menu_send_to_desktop" />
<!-- 为该菜单项定义一个唯一标识符id推测是用于将相关内容发送到桌面等操作的菜单项 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_send_to_desktop”的字符串资源提示用户该项功能与发送到桌面有关 -->
android:title="@string/menu_send_to_desktop"/>
<item
android:id="@+id/menu_alert"
android:title="@string/menu_alert" />
<!-- 为该菜单项定义一个唯一标识符id可能是用于设置提醒相关功能的菜单项 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_alert”的字符串资源告知用户点击该项可进行提醒相关操作 -->
<item
android:id="@+id/menu_delete_remind"
android:title="@string/menu_remove_remind" />
<!-- 为该菜单项定义一个唯一标识符id从命名推测是用于删除提醒相关操作的菜单项 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_remove_remind”的字符串资源提示用户该项功能与删除提醒有关 -->
</menu><!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处为版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
</menu>

@ -1,30 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
<menu xmlns:android="http://schemas.android.com/apk/res/android">
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.
-->
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_search"
android:title="@string/menu_search" />
</menu>
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种菜单相关的属性 -->
<!-- 为该菜单项定义一个唯一标识符id从命名“menu_search”可以看出这个菜单项大概率是用于触发搜索相关操作的 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_search”的字符串资源这个字符串资源通常在对应的字符串资源文件中定义以此来明确地向用户提示该菜单项的功能是进行搜索 -->
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->

@ -1,69 +1,52 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种菜单相关属性 -->
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.
-->
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_new_note"
android:title="@string/notelist_menu_new" />
<!-- 为该菜单项定义一个唯一标识符id从命名“menu_new_note”推测这个菜单项大概率是用于创建新笔记相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“notelist_menu_new”的字符串资源该字符串资源通常在对应的字符串资源文件中定义用于向用户提示点击此项可进行创建新笔记的操作 -->
android:title="@string/notelist_menu_new"/>
<item
android:id="@+id/menu_delete"
android:title="@string/menu_delete" />
<!-- 为该菜单项定义一个唯一标识符id“menu_delete”表明这个菜单项很可能是用于执行删除相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_delete”的字符串资源明确提示用户点击该项可执行删除操作 -->
android:title="@string/menu_delete"/>
<item
android:id="@+id/menu_font_size"
android:title="@string/menu_font_size" />
<!-- 为该菜单项定义一个唯一标识符id根据“menu_font_size”命名可推测这个菜单项是用于调整字体大小相关设置的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_font_size”的字符串资源提示用户点击该项可进行字体大小相关操作 -->
android:title="@string/menu_font_size"/>
<item
android:id="@+id/menu_list_mode"
android:title="@string/menu_list_mode" />
<!-- 为该菜单项定义一个唯一标识符id从“menu_list_mode”来看这个菜单项可能是用于切换列表显示模式相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_list_mode”的字符串资源告知用户点击该项可进行列表模式相关操作 -->
<item
android:id="@+id/menu_share"
android:title="@string/menu_share" />
<!-- 为该菜单项定义一个唯一标识符id“menu_share”清晰地表明这个菜单项是用于实现分享功能的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_share”的字符串资源让用户明白点击该项可进行分享操作 -->
android:title="@string/menu_share"/>
<item
android:id="@+id/menu_send_to_desktop"
android:title="@string/menu_send_to_desktop" />
<!-- 为该菜单项定义一个唯一标识符id由“menu_send_to_desktop”推测这个菜单项可能是用于将相关内容发送到桌面等操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_send_to_desktop”的字符串资源提示用户点击该项可进行发送到桌面相关操作 -->
android:title="@string/menu_send_to_desktop"/>
<item
android:id="@+id/menu_alert"
android:title="@string/menu_alert" />
<!-- 为该菜单项定义一个唯一标识符id“menu_alert”表明这个菜单项大概率是用于设置提醒相关功能的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_alert”的字符串资源告知用户点击该项可进行提醒相关操作 -->
<item
android:id="@+id/menu_delete_remind"
android:title="@string/menu_remove_remind" />
</menu><!-- 为该菜单项定义一个唯一标识符id从“menu_delete_remind”可推测这个菜单项是用于删除提醒相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_remove_remind”的字符串资源提示用户点击该项可进行删除提醒相关操作 -->
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
这里是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
</menu>

@ -1,52 +1,39 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种菜单相关的属性 -->
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.
-->
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_new_folder"
android:title="@string/menu_create_folder" />
<!-- 为该菜单项定义一个唯一标识符id从命名“menu_new_folder”可以推测出这个菜单项大概率是用于创建新文件夹相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_create_folder”的字符串资源该字符串资源通常在对应的字符串资源文件中定义以此来明确地向用户提示点击此项可进行创建新文件夹的操作 -->
android:title="@string/menu_create_folder"/>
<item
android:id="@+id/menu_export_text"
android:title="@string/menu_export_text" />
<!-- 为该菜单项定义一个唯一标识符id“menu_export_text”表明这个菜单项很可能是用于执行文本导出相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_export_text”的字符串资源提示用户点击该项可进行文本导出操作 -->
android:title="@string/menu_export_text"/>
<item
android:id="@+id/menu_sync"
android:title="@string/menu_sync" />
<!-- 为该菜单项定义一个唯一标识符id根据“menu_sync”命名可推测这个菜单项是用于进行数据同步相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_sync”的字符串资源告知用户点击该项可进行同步操作 -->
android:title="@string/menu_sync"/>
<item
android:id="@+id/menu_setting"
android:title="@string/menu_setting" />
<!-- 为该菜单项定义一个唯一标识符id“menu_setting”清晰地表明这个菜单项是用于打开设置相关界面或执行设置相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_setting”的字符串资源让用户明白点击该项可进入设置相关功能 -->
<item
android:id="@+id/menu_search"
android:title="@string/menu_search" />
<!-- 为该菜单项定义一个唯一标识符id“menu_search”表明这个菜单项大概率是用于触发搜索相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_search”的字符串资源提示用户点击该项可进行搜索操作 -->
</menu><!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
android:title="@string/menu_search"/>
</menu>

@ -1,26 +1,20 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_select_all"
android:title="@string/menu_select_all" />
</menu><!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种菜单相关的属性 -->
<!-- 为该菜单项定义一个唯一标识符id从命名“action_select_all”可以推测出这个菜单项大概率是用于执行全选相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_select_all”的字符串资源该字符串资源通常在对应的字符串资源文件中定义以此来明确地向用户提示点击此项可进行全选操作 -->
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
<item android:id="@+id/action_select_all" android:title="@string/menu_select_all" />
</menu>

@ -1,42 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种菜单相关的属性 -->
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.
-->
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/move"
android:title="@string/menu_move"
android:icon="@drawable/menu_move"
android:showAsAction="always|withText" />
<!-- 为该菜单项定义一个唯一标识符id从命名“move”可以推测出这个菜单项大概率是用于执行移动相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_move”的字符串资源该字符串资源通常在对应的字符串资源文件中定义以此来明确地向用户提示点击此项可进行移动操作 -->
<!-- 设置该菜单项要显示的图标引用名为“menu_move”的可绘制资源通常是图片资源用于在界面上直观地展示该菜单项对应的功能方便用户识别 -->
<!-- 设置该菜单项在界面上的显示方式“always”表示总是显示在界面上比如在ActionBar等相关位置“withText”表示同时显示图标和文本内容让用户能更清晰地看到菜单项的功能和名称 -->
<item
android:id="@+id/delete"
android:title="@string/menu_delete"
android:icon="@drawable/menu_delete"
android:showAsAction="always|withText" />
<!-- 为该菜单项定义一个唯一标识符id“delete”表明这个菜单项很可能是用于执行删除相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“menu_delete”的字符串资源提示用户点击该项可进行删除操作 -->
<!-- 设置该菜单项要显示的图标引用名为“menu_delete”的可绘制资源通常是图片资源用于辅助用户直观地识别该菜单项的功能 -->
<!-- 同样设置该菜单项在界面上的显示方式,使其总是显示并且同时展示图标和文本内容 -->
</menu><!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
</menu>

@ -1,26 +1,24 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 引入安卓的命名空间,后续通过这个命名空间就能使用安卓系统中定义的各种菜单相关属性 -->
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_new_note"
android:title="@string/notelist_menu_new" />
</menu><!-- 为该菜单项定义一个唯一标识符id从命名“menu_new_note”来看这个菜单项大概率是用于触发创建新笔记相关操作的功能入口 -->
<!-- 设置该菜单项显示的标题文本引用名为“notelist_menu_new”的字符串资源该字符串资源通常在对应的字符串资源文件中定义用于向用户提示点击此项可进行创建新笔记的操作 -->
android:title="@string/notelist_menu_new"/>
</menu>

@ -1,28 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources>
<!-- <resources>标签是安卓资源文件中的根标签,用于定义各种类型的资源,比如字符串、数组、颜色等资源都可以放在这里面定义 -->
<string-array name="menu_share_ways">
<!-- 定义一个名为“menu_share_ways”的字符串数组资源从命名来看这个数组大概率是用于存储菜单中分享相关的方式选项内容 -->
<item>短信</item>
<!-- 字符串数组中的一个元素,表示一种分享方式,这里是“短信”,意味着在对应的分享菜单中,用户可以选择通过短信来分享相关内容 -->
<item>邮件</item>
<!-- 字符串数组中的另一个元素,表示另一种分享方式,即用户还可以通过邮件的方式来分享相关内容 -->
</string-array>
</resources>

@ -1,261 +1,126 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- <resources>是安卓资源文件的根标签用于定义各种资源这里引入了两个命名空间“android”用于安卓相关的资源属性设置等操作“xliff”常用于国际化文本处理相关场景 -->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">便签</string>
<!-- 定义名为“app_name”的字符串资源此资源大概率用于表示整个应用程序的名称在这里被设置为“便签”表明这是一款与便签功能相关的应用 -->
<string name="app_widget2x2">便签2x2</string>
<!-- 定义名为“app_widget2x2”的字符串资源推测是用于描述应用中尺寸为 2x2 的小部件对应的显示名称方便用户识别和区分不同尺寸的小部件这里显示为“便签2x2” -->
<string name="app_widget4x4">便签4x4</string>
<!-- 定义名为“app_widget4x4”的字符串资源同理应该是用于表示应用里尺寸为 4x4 的小部件的显示名称起到标识该特定尺寸小部件的作用名称为“便签4x4” -->
<string name="widget_havenot_content">没有关联内容,点击新建便签。</string>
<!-- 定义名为“widget_havenot_content”的字符串资源从其内容来看可能是在小部件上显示的提示信息当没有与之关联的便签内容时提示用户点击可以去创建新的便签 -->
<string name="widget_under_visit_mode">访客模式下,便签内容不可见</string>
<!-- 定义名为“widget_under_visit_mode”的字符串资源推测是用于小部件处于访客模式下时向用户展示的提示文本告知用户在此模式下无法查看便签的具体内容 -->
<string name="notelist_string_info">...</string>
<!-- 定义名为“notelist_string_info”的字符串资源仅从“...”不太明确其确切用途,不过可能是在便签列表相关界面中用于展示某种简略信息或者占位性质的文本内容 -->
<string name="notelist_menu_new">新建便签</string>
<!-- 定义名为“notelist_menu_new”的字符串资源用于在便签列表对应的菜单里作为创建新便签这一菜单项所显示的文字内容明确提示用户点击该菜单项可进行添加便签的操作 -->
<string name="delete_remind_time_message">成功删除提醒</string>
<!-- 定义名为“delete_remind_time_message”的字符串资源大概率是在成功删除便签的提醒时间后向用户展示的提示消息告知用户相应的删除提醒操作已经顺利完成 -->
<string name="set_remind_time_message">创建提醒</string>
<!-- 定义名为“set_remind_time_message”的字符串资源应该是在执行设置便签提醒时间相关操作时向用户呈现的提示文本表明当前正在进行设置提醒的动作 -->
<string name="note_alert_expired">已过期</string>
<!-- 定义名为“note_alert_expired”的字符串资源可能是在便签的提醒功能过期时用于显示给用户的提示文字比如在提醒相关界面展示“已过期”字样让用户知晓提醒已过期 -->
<string name="format_date_ymd">yyyyMMdd</string>
<!-- 定义名为“format_date_ymd”的字符串资源这是定义了一种日期格式采用“yyyyMMdd”这种形式常用于对日期数据进行格式化输出比如按照此格式来存储、展示便签相关的日期信息等 -->
<string name="format_datetime_mdhm">MM月dd日 kk:mm</string>
<!-- 定义名为“format_datetime_mdhm”的字符串资源同样是一种日期时间格式的定义按照“MM月dd日 kk:mm”的格式来规范日期时间数据的展示方便在应用中统一处理和显示这类信息 -->
<string name="notealert_ok">知道了</string>
<!-- 定义名为“notealert_ok”的字符串资源推测是在便签相关提醒的操作场景里当用户确认知晓或者完成某个操作后对应的按钮或者提示文本会显示“知道了”表示用户明白了、已确认的意思 -->
<string name="notealert_enter">查看</string>
<!-- 定义名为“notealert_enter”的字符串资源可能是在便签提醒相关的交互中用于引导用户点击去查看具体便签内容的提示文字提示用户点击相应区域可以查看详情 -->
<string name="note_link_tel">呼叫电话</string>
<!-- 定义名为“note_link_tel”的字符串资源大概率是当便签中包含电话号码链接等情况时在相应位置显示的操作提示文本告知用户点击此处可以进行拨打电话的操作 -->
<string name="note_link_email">发送邮件</string>
<!-- 定义名为“note_link_email”的字符串资源应该是在便签里有邮件链接相关内容时显示给用户的提示文字提示用户点击可触发发送邮件的操作 -->
<string name="note_link_web">浏览网页</string>
<!-- 定义名为“note_link_web”的字符串资源可能是在便签中存在网页链接的情况下向用户展示的提示文本告知用户点击该链接可以浏览对应的网页内容 -->
<string name="note_link_other">打开地图</string>
<!-- 定义名为“note_link_other”的字符串资源推测是在便签涉及到地图相关链接等情况时显示的提示文字提示用户点击可以打开地图应用进行相关操作 -->
<!-- note list string -->
<!-- 这是一个注释说明,告知下面的字符串资源是与便签列表相关的一些字符串内容 -->
<string name="menu_create_folder">新建文件夹</string>
<!-- 定义名为“menu_create_folder”的字符串资源用于在应用的菜单中作为创建新文件夹这一菜单项所显示的文字内容清晰地提示用户点击该菜单项可进行新建文件夹的操作 -->
<string name="menu_export_text">导出文本</string>
<!-- 定义名为“menu_export_text”的字符串资源用于在菜单里作为导出文本这个菜单项显示的文本内容告知用户点击该菜单项就能执行文本导出的相关操作 -->
<string name="menu_sync">同步</string>
<!-- 定义名为“menu_sync”的字符串资源用于在菜单中作为同步相关操作的菜单项所显示的文字内容提示用户点击它可以发起数据同步的操作 -->
<string name="menu_sync_cancel">取消同步</string>
<!-- 定义名为“menu_sync_cancel”的字符串资源用于在正在进行同步操作的过程中在菜单里作为取消同步这一菜单项显示的文本内容方便用户点击来终止同步操作 -->
<string name="menu_setting">设置</string>
<!-- 定义名为“menu_setting”的字符串资源用于在菜单中作为进入设置界面或者执行设置相关操作的菜单项所显示的文字内容引导用户点击该菜单项以进入设置相关功能区域 -->
<string name="menu_search">搜索</string>
<!-- 定义名为“menu_search”的字符串资源用于在菜单中作为搜索相关操作的菜单项显示的文本内容提示用户点击该菜单项可以进行搜索相关的操作比如查找便签内容等 -->
<string name="menu_delete">删除</string>
<!-- 定义名为“menu_delete”的字符串资源用于在菜单中作为删除相关操作的菜单项显示的文本内容告知用户点击该菜单项可以执行删除相应内容的操作例如删除便签、文件夹等 -->
<string name="menu_move">移动到文件夹</string>
<!-- 定义名为“menu_move”的字符串资源用于在菜单中作为将相关内容移动到文件夹这一菜单项显示的文本内容提示用户点击该菜单项可进行把某些内容移动到指定文件夹的操作 -->
<string name="menu_select_title">选中了 %d 项</string>
<!-- 定义名为“menu_select_title”的字符串资源从格式“选中了 %d 项”来看,它是用于在有多个项目被选中后,展示选中数量相关提示信息的文本,会根据实际选中的项目数量替换“%d”来准确告知用户选中情况 -->
<string name="menu_select_none">没有选中项,操作无效</string>
<!-- 定义名为“menu_select_none”的字符串资源用于在没有任何项目被选中的情况下向用户显示的提示文本告知用户由于没有选中内容当前要执行的操作是无效的 -->
<string name="menu_select_all">全选</string>
<!-- 定义名为“menu_select_all”的字符串资源用于在菜单中作为全选相关操作的菜单项显示的文本内容提示用户点击该菜单项可以一次性选中所有相关的项目 -->
<string name="menu_deselect_all">取消全选</string>
<!-- 定义名为“menu_deselect_all”的字符串资源用于在菜单中作为取消全选相关操作的菜单项显示的文本内容提示用户点击该菜单项可以将已经全选的状态取消即取消选中所有项目 -->
<string name="menu_font_size">文字大小</string>
<!-- 定义名为“menu_font_size”的字符串资源用于在菜单中作为调整文字大小相关操作的菜单项显示的文本内容引导用户点击该菜单项来进行文字大小相关的设置操作 -->
<string name="menu_font_small"></string>
<!-- 定义名为“menu_font_small”的字符串资源可能是在文字大小设置的相关菜单选项里作为表示小字号这一选项所显示的文字内容便于用户选择小字体来显示文本 -->
<string name="menu_font_normal">正常</string>
<!-- 定义名为“menu_font_normal”的字符串资源推测是在文字大小设置相关的菜单中作为表示正常字号这一选项显示的文字内容方便用户将文本字体设置为正常大小 -->
<string name="menu_font_large"></string>
<!-- 定义名为“menu_font_large”的字符串资源应该是在文字大小设置相关的菜单里作为表示大字号这一选项所展示的文字内容让用户可以选择大字体来显示文本 -->
<string name="menu_font_super">超大</string>
<!-- 定义名为“menu_font_super”的字符串资源可能是在文字大小设置相关的菜单中作为表示超大字号这一选项显示的文字内容供用户选择超大字体来展示文本 -->
<string name="menu_list_mode">进入清单模式</string>
<!-- 定义名为“menu_list_mode”的字符串资源用于在菜单中作为进入清单模式比如待办事项清单等类似的模式相关操作的菜单项显示的文本内容提示用户点击该菜单项可进入对应的清单模式方便对相关内容进行清单式管理 -->
<string name="menu_normal_mode">退出清单模式</string>
<!-- 定义名为“menu_normal_mode”的字符串资源用于在菜单中作为离开清单模式例如待办事项清单等相关操作的菜单项显示的文本内容提示用户点击该菜单项可退出当前所处的清单模式恢复到常规显示状态 -->
<string name="menu_folder_view">查看文件夹</string>
<!-- 定义名为“menu_folder_view”的字符串资源用于在菜单里作为查看文件夹相关操作的菜单项所显示的文本内容告知用户点击该菜单项后可以查看指定文件夹内的内容比如查看文件夹里包含的便签等信息 -->
<string name="menu_folder_delete">刪除文件夹</string>
<!-- 定义名为“menu_folder_delete”的字符串资源用于在菜单中作为删除文件夹相关操作的菜单项显示的文本内容提示用户点击该菜单项会执行删除文件夹的操作通常可能还会有相应确认提示以防误删 -->
<string name="menu_folder_change_name">修改文件夹名称</string>
<!-- 定义名为“menu_folder_change_name”的字符串资源用于在菜单中作为更改文件夹名称相关操作的菜单项显示的文本内容引导用户点击该菜单项来对已有的文件夹重新命名使其名称更符合需求或便于识别 -->
<string name="folder_exist">文件夹 %1$s 已存在,请重新命名</string>
<!-- 定义名为“folder_exist”的字符串资源从格式“文件夹 %1$s 已存在,请重新命名”来看,它是一种带有占位符(%1$s的提示文本通常在创建文件夹时如果要创建的文件夹名称已存在就会用实际的文件夹名称替换占位符显示该提示信息告知用户需要重命名后再进行操作 -->
<string name="menu_share">分享</string>
<!-- 定义名为“menu_share”的字符串资源用于在菜单中作为分享相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行分享操作比如分享便签内容到其他应用或者平台等 -->
<string name="menu_send_to_desktop">发送到桌面</string>
<!-- 定义名为“menu_send_to_desktop”的字符串资源用于在菜单中作为将相关内容发送到桌面例如创建桌面快捷方式等相关操作的菜单项显示的文本内容告知用户点击该菜单项可把对应的内容发送到桌面方便快速访问 -->
<string name="menu_alert">提醒我</string>
<!-- 定义名为“menu_alert”的字符串资源用于在菜单中作为设置提醒相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行提醒相关设置比如设置某个便签的提醒时间等 -->
<string name="menu_remove_remind">删除提醒</string>
<!-- 定义名为“menu_remove_remind”的字符串资源用于在菜单中作为删除提醒相关操作的菜单项显示的文本内容提示用户点击该菜单项可删除已设置好的提醒取消之前设定的提醒功能 -->
<string name="menu_title_select_folder">选择文件夹</string>
<!-- 定义名为“menu_title_select_folder”的字符串资源用于在执行选择文件夹相关操作时作为提示用户当前操作内容的文本比如在弹出的选择文件夹界面上方显示该文字让用户明确知晓正在进行选择文件夹的动作 -->
<string name="menu_move_parent_folder">上一级文件夹</string>
<!-- 定义名为“menu_move_parent_folder”的字符串资源通常用于在涉及将内容移动到当前所在文件夹的上一级文件夹的操作场景中作为提示用户可进行此操作的文本告知用户点击相应按钮或选项可将文件、便签等内容移动到上一级文件夹中 -->
<string name="info_note_enter_desktop">已添加到桌面</string>
<!-- 定义名为“info_note_enter_desktop”的字符串资源一般是在便签成功添加到桌面例如创建了便签对应的桌面快捷方式向用户显示的提示信息告知用户对应的便签已经添加到桌面了方便用户知晓操作结果 -->
<string name="alert_title_delete">删除</string>
<!-- 定义名为“alert_title_delete”的字符串资源用于在弹出与删除操作相关的提示框时作为提示框的标题文本简洁明了地告知用户当前操作是关于删除相关内容让用户快速了解提示框所关联的操作性质 -->
<string name="alert_message_delete_notes">确认要删除所选的 %d 条便签吗?</string>
<!-- 定义名为“alert_message_delete_notes”的字符串资源从格式“确认要删除所选的 %d 条便签吗?”来看,它带有一个占位符“%d”在用户执行删除多条便签的操作时会根据实际选中要删除的便签数量替换该占位符用于弹出提示框询问用户是否确认执行删除操作以避免误删 -->
<string name="alert_message_delete_note">确认要删除该条便签吗?</string>
<!-- 定义名为“alert_message_delete_note”的字符串资源用于在用户尝试删除单条便签时弹出提示框显示的询问信息询问用户是否确实要删除当前这一条便签获取用户的明确操作意向避免误操作导致便签丢失 -->
<string name="alert_message_delete_folder">确认删除文件夹及所包含的便签吗?</string>
<!-- 定义名为“alert_message_delete_folder”的字符串资源在用户进行删除文件夹操作时该文件夹下通常包含有便签等内容弹出提示框显示的询问文本询问用户是否确认执行删除该文件夹以及里面所有便签的操作需要用户明确回应以保障数据安全 -->
<string name="format_move_notes_to_folder">已将所选 %1$d 条便签移到 %2$s 文件夹</string>
<!-- 定义名为“format_move_notes_to_folder”的字符串资源从格式来看它带有两个占位符%1$d 和 %2$s在成功将选中的便签移动到指定文件夹后会用实际移动便签的数量替换“%1$d”用具体的文件夹名称替换“%2$s”用于显示提示信息告知用户移动操作的具体情况让用户清楚知晓便签的移动结果 -->
<!-- export text -->
<!-- 这是一个注释说明,告知下面的字符串资源是与文本导出相关的一些提示信息 -->
<string name="error_sdcard_unmounted">SD卡被占用不能操作</string>
<!-- 定义名为“error_sdcard_unmounted”的字符串资源当 SD 卡处于被其他程序占用等忙碌状态,导致当前应用无法对其进行操作(例如导出文本到 SD 卡等操作)时,显示该提示信息,告知用户当前 SD 卡不可用,无法进行相应操作 -->
<string name="error_sdcard_export">导出文本时发生错误请检查SD卡</string>
<!-- 定义名为“error_sdcard_export”的字符串资源在执行导出文本到 SD 卡的操作过程中,如果出现错误(可能是 SD 卡本身故障、空间不足等原因),就会显示此提示信息,提示用户去检查 SD 卡的相关情况,以便排查问题所在 -->
<string name="error_note_not_exist">要查看的便签不存在</string>
<!-- 定义名为“error_note_not_exist”的字符串资源当用户尝试查看某个便签但该便签在系统中实际并不存在例如被误删除或者从未创建等情况显示该提示信息告知用户想要查看的便签找不到了操作无法进行 -->
<string name="error_note_empty_for_clock">不能为空便签设置闹钟提醒</string>
<!-- 定义名为“error_note_empty_for_clock”的字符串资源用于在用户试图对没有任何内容的空便签设置闹钟提醒比如设置提醒时间等与时间提醒相关操作显示的提示信息告知用户不能在空白便签上进行此类操作需要先添加便签内容等 -->
<string name="error_note_empty_for_send_to_desktop">不能将空便签发送到桌面</string>
<!-- 定义名为“error_note_empty_for_send_to_desktop”的字符串资源在用户尝试把内容为空的便签发送到桌面例如创建桌面快捷方式显示该提示信息告知用户不可以对空便签执行此操作可能需要先完善便签内容后再进行发送 -->
<string name="success_sdcard_export">导出成功</string>
<!-- 定义名为“success_sdcard_export”的字符串资源在文本成功从应用导出到 SD 卡后,用于显示的提示信息,告知用户导出操作已经顺利完成,让用户知晓操作结果 -->
<string name="failed_sdcard_export">导出失败</string>
<!-- 定义名为“failed_sdcard_export”的字符串资源当文本导出到 SD 卡的操作未能成功完成时,显示该提示信息,简单告知用户导出失败了,不过通常还需要结合其他相关错误提示进一步排查具体原因 -->
<string name="format_exported_file_location">已将文本文件(%1$s)输出至SD卡(%2$s)目录</string>
<!-- 定义名为“format_exported_file_location”的字符串资源从格式来看它带有两个占位符%1$s 和 %2$s在需要告知用户文本导出文件在 SD 卡中的具体存放位置时,会用实际的文件名替换“%1$s”用 SD 卡的具体目录路径替换“%2$s”清晰展示导出文件的所在位置情况 -->
<!-- Sync -->
<!-- 这是一个注释说明告知下面的字符串资源是与便签同步Sync相关的一些提示信息 -->
<string name="ticker_syncing">同步便签...</string>
<!-- 定义名为“ticker_syncing”的字符串资源在便签同步操作开始进行时用于显示的提示信息告知用户当前正在同步便签一般可能会以滚动提示条文字等形式展示让用户知晓操作正在进行中 -->
<string name="ticker_success">同步成功</string>
<!-- 定义名为“ticker_success”的字符串资源在便签同步操作顺利完成后用于显示的提示信息告知用户同步已经成功让用户了解操作结果 -->
<string name="ticker_fail">同步失败</string>
<!-- 定义名为“ticker_fail”的字符串资源当便签同步操作未能成功出现错误时用于显示的提示信息告知用户同步失败了通常还需要结合其他相关错误提示进一步排查具体原因 -->
<string name="ticker_cancel">同步已取消</string>
<!-- 定义名为“ticker_cancel”的字符串资源在便签同步操作被取消比如用户手动点击取消按钮或者因程序异常等情况自动取消用于显示的提示信息告知用户同步操作已经被取消让用户知晓当前状态变化 -->
<string name="success_sync_account">与%1$s同步成功</string>
<!-- 定义名为“success_sync_account”的字符串资源从格式“与%1$s同步成功”来看它带有一个占位符“%1$s”在使用特定账户成功完成便签同步操作后会用实际的账户名称替换该占位符告知用户是与哪个账户同步成功了明确同步相关情况 -->
<string name="error_sync_network">同步失败,请检查网络和帐号设置</string>
<!-- 定义名为“error_sync_network”的字符串资源当便签同步操作失败且原因可能与网络连接不稳定或者账号设置有误例如账号密码错误、账号未授权等情况相关时显示该提示信息提示用户去检查网络以及账号设置情况以排查同步失败的问题所在 -->
<string name="error_sync_internal">同步失败,发生内部错误</string>
<!-- 定义名为“error_sync_internal”的字符串资源在便签同步操作因应用自身内部出现问题比如代码逻辑错误、与服务器交互出现异常等情况导致失败时显示该提示信息告知用户同步失败是由于内部发生了错误不过具体原因可能还需要进一步深入排查分析 -->
<string name="error_sync_cancelled">同步已取消</string>
<!-- 定义名为“error_sync_cancelled”的字符串资源在同步操作被取消例如因系统资源不足等原因导致程序自动取消同步用于显示的提示信息告知用户同步操作已被取消与前面手动取消同步操作后显示的提示信息类似只是触发取消的原因有所不同 -->
<string name="sync_progress_login">登录%1$s...</string>
<!-- 定义名为“sync_progress_login”的字符串资源从格式“登录%1$s...”来看,它带有一个占位符“%1$s”在便签同步操作过程中当正在登录相关同步账户例如登录到云端服务账户用于同步便签会用实际的账户名称替换该占位符告知用户正在登录哪个账户让用户了解同步操作的进展情况 -->
<string name="sync_progress_init_list">正在获取服务器便签列表...</string>
<!-- 定义名为“sync_progress_init_list”的字符串资源在便签同步操作里当正在从服务器获取便签列表比如从云端存储获取便签记录以便和本地便签进行对比同步用于显示的提示信息告知用户当前正在进行获取服务器便签列表的操作体现同步操作的进度状态 -->
<string name="sync_progress_syncing">正在同步本地便签...</string>
<!-- 定义名为“sync_progress_syncing”的字符串资源在便签同步操作进行到将本地便签与服务器端可能是与谷歌相关服务等如 google task的便签进行同步的实际阶段时用于显示的提示信息告知用户当前正在进行具体的便签同步操作步骤让用户知晓同步进展 -->
<!-- Preferences -->
<!-- 这是一个注释说明告知下面的字符串资源是与应用偏好设置Preferences相关的一些提示信息 -->
<string name="preferences_title">设置</string>
<!-- 定义名为“preferences_title”的字符串资源用于在应用的偏好设置界面或者相关菜单中作为显示标题的文本内容告知用户当前进入的是设置相关的功能区域方便用户识别和操作 -->
<string name="preferences_account_title">同步账号</string>
<!-- 定义名为“preferences_account_title”的字符串资源用于在偏好设置中与同步账号相关的设置区域作为显示标题的文本内容提示用户该部分设置是针对同步账号进行操作的比如选择、更改、添加或删除同步账号等 -->
<string name="preferences_account_summary">与google task同步便签记录</string>
<!-- 定义名为“preferences_account_summary”的字符串资源用于在同步账号相关设置区域作为对该设置功能的简要说明文本内容告知用户在这里可以将便签记录与谷歌任务google task进行同步让用户了解该设置选项的作用 -->
<string name="preferences_last_sync_time">上次同步于 %1$s</string>
<!-- 定义名为“preferences_last_sync_time”的字符串资源从格式“上次同步于 %1$s”来看它带有一个占位符“%1$s”通常用于在显示上次便签同步操作的具体时间信息时会用实际的时间数据按照一定格式存储的时间字符串替换该占位符准确告知用户上次同步是什么时候进行的 -->
<string name="preferences_add_account">添加账号</string>
<!-- 定义名为“preferences_add_account”的字符串资源用于在偏好设置中作为添加账户比如添加用于同步便签的新账户相关操作的菜单项或按钮显示的文本内容提示用户点击可进行添加账户的操作 -->
<string name="preferences_menu_change_account">更换账号</string>
<!-- 定义名为“preferences_menu_change_account”的字符串资源用于在偏好设置的菜单中作为更改同步账号相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行更改当前同步账号的操作 -->
<string name="preferences_menu_remove_account">删除账号</string>
<!-- 定义名为“preferences_menu_remove_account”的字符串资源用于在偏好设置的菜单中作为移除同步账号相关操作的菜单项显示的文本内容提示用户点击该菜单项可执行移除已有的同步账号的操作 -->
<string name="preferences_menu_cancel">取消</string>
<!-- 定义名为“preferences_menu_cancel”的字符串资源用于在偏好设置相关操作过程中比如正在添加、更改、移除账户等操作时作为取消当前操作的菜单项或按钮显示的文本内容提示用户点击可取消正在进行的操作回到之前的状态 -->
<string name="preferences_button_sync_immediately">立即同步</string>
<!-- 定义名为“preferences_button_sync_immediately”的字符串资源用于在偏好设置界面或者相关区域作为立即进行同步操作的按钮显示的文本内容提示用户点击该按钮可马上发起便签同步操作无需等待其他定时同步等情况 -->
<string name="preferences_button_sync_cancel">取消同步</string>
<!-- 定义名为“preferences_button_sync_cancel”的字符串资源用于在正在进行同步操作时在偏好设置界面或者相关区域作为取消同步操作的按钮显示的文本内容提示用户点击该按钮可终止当前正在进行的同步操作 -->
<string name="preferences_dialog_change_account_title">当前帐号 %1$s</string>
<!-- 定义名为“preferences_dialog_change_account_title”的字符串资源从格式“当前帐号 %1$s”来看它带有一个占位符“%1$s”在弹出更改账号相关的对话框时会用实际的当前账号名称替换该占位符作为对话框的标题显示明确告知用户当前正在操作的是哪个账号 -->
<string name="preferences_dialog_change_account_warn_msg">如更换同步帐号,过去的帐号同步信息将被清空,再次切换的同时可能会造成数据重复</string>
<!-- 定义名为“preferences_dialog_change_account_warn_msg”的字符串资源用于在弹出更改账号相关对话框时作为显示警告信息的文本内容告知用户如果更换同步账号那么之前该账号相关的同步信息都会被删除并且在后续再次切换账号等操作时有可能会出现数据重复的情况提醒用户谨慎操作 -->
<string name="preferences_dialog_select_account_title">同步便签</string>
<!-- 定义名为“preferences_dialog_select_account_title”的字符串资源用于在弹出选择账号用于同步便签相关的对话框时作为对话框的标题显示的文本内容告知用户当前对话框是用于选择同步便签的账号让用户明确操作意图 -->
<string name="preferences_dialog_select_account_tips">请选择google帐号便签将与该帐号的google task内容同步。</string>
<!-- 定义名为“preferences_dialog_select_account_tips”的字符串资源用于在弹出选择账号相关对话框时作为提示信息的文本内容告知用户需要选择一个谷歌账号并且提示用户选择该账号后本地便签将会与该账号对应的 google task 内容进行同步 -->
<string name="preferences_toast_cannot_change_account">正在同步中,不能修改同步帐号</string>
<!-- 定义名为“preferences_toast_cannot_change_account”的字符串资源用于在便签正在进行同步操作的过程中当用户尝试更改同步账号时以弹出提示框Toast的形式显示该提示信息告知用户由于同步正在进行此时不允许修改同步账号需等待同步完成后再操作 -->
<string name="preferences_toast_success_set_accout">同步帐号已设置为%1$s</string>
<!-- 定义名为“preferences_toast_success_set_accout”的字符串资源从格式“同步帐号已设置为%1$s”来看它带有一个占位符“%1$s”在成功将某个账号设置为同步账号后会用实际的账号名称替换该占位符以弹出提示框Toast的形式告知用户同步账号已经设置成功以及具体设置的是哪个账号 -->
<string name="preferences_bg_random_appear_title">新建便签背景颜色随机</string>
<!-- 定义名为“preferences_bg_random_appear_title”的字符串资源用于在应用中与新建便签相关的设置区域作为一个功能标题显示的文本内容提示用户可以设置新建便签时其背景颜色是否随机出现让用户了解该设置选项的作用 -->
<string name="button_delete">删除</string>
<!-- 定义名为“button_delete”的字符串资源通常用于在界面上作为按钮显示的文本内容提示用户点击该按钮可执行删除相关的操作比如删除某个便签、文件夹或者其他数据项等 -->
<string name="call_record_folder_name">通话便签</string>
<!-- 定义名为“call_record_folder_name”的字符串资源推测是用于表示存放与通话相关记录的便签所在的文件夹名称方便在应用中对这类特定内容的便签进行归类和管理使其更易于识别和查找 -->
<string name="hint_foler_name">请输入名称</string>
<!-- 定义名为“hint_foler_name”的字符串资源大概率是用于在需要用户输入文件夹名称的场景下作为提示信息显示给用户告知用户在此处输入相应的
<string name="search_label">正在搜索便签</string>
<string name="search_hint">搜索便签</string>
<string name="search_setting_description">便签中的文字</string>
<string name="search">便签</string>
<string name="datetime_dialog_ok">设置</string>
<string name="datetime_dialog_cancel">取消</string>
<plurals name="search_results_title">
<item quantity="other"><xliff:g id="NUMBER">%1$s</xliff:g> 条符合“<xliff:g id="SEARCH">%2$s</xliff:g>”的搜索结果</item>
</plurals>
</resources>

@ -1,28 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources>
<!-- <resources> 是安卓资源文件中的根标签,用于集中定义各类资源,像字符串、颜色、数组等不同类型的资源都可以在这个标签内部进行定义 -->
<string-array name="menu_share_ways">
<!-- 定义一个名为“menu_share_ways”的字符串数组资源从名字可以推测这个数组是用来存放菜单里分享功能相关的可选方式的 -->
<item>短信</item>
<!-- 这是字符串数组中的一个元素,表示一种分享途径,即用户可以通过发送短信的方式来分享相关内容 -->
<item>郵件</item>
<!-- 同样是字符串数组中的元素,此处应该是“邮件”的意思(可能是书写上稍有误,正确写法通常为“邮件”),意味着用户也能够选择通过发送邮件这种方式来分享相关内容 -->
</string-array>
</resources>

@ -1,296 +1,127 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- <resources>标签是安卓资源文件的根标签用于定义各种资源这里引入了两个命名空间“android”用于安卓相关资源属性设置等操作“xliff”常用于国际化文本处理相关场景 -->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">便簽</string>
<!-- 定义名为“app_name”的字符串资源此资源用于表示整个应用程序的名称在这里被设置为“便簽”表明这是一款与便签功能相关的应用 -->
<string name="app_widget2x2">便簽2x2</string>
<!-- 定义名为“app_widget2x2”的字符串资源推测是用于描述应用中尺寸为 2x2 的小部件对应的显示名称方便用户识别和区分不同尺寸的小部件这里显示为“便簽2x2” -->
<string name="app_widget4x2">便簽4x4</string>
<!-- 定义名为“app_widget4x4”的字符串资源同理应该是用于表示应用里尺寸为 4x4 的小部件的显示名称起到标识该特定尺寸小部件的作用名称为“便簽4x4” -->
<string name="app_widget4x4">便簽4x4</string>
<string name="widget_havenot_content">沒有關聯內容,點擊新建便簽。</string>
<!-- 定义名为“widget_havenot_content”的字符串资源从其内容来看可能是在小部件上显示的提示信息当没有与之关联的便签内容时提示用户点击可以去创建新的便签 -->
<string name="widget_under_visit_mode">訪客模式下,便籤內容不可見</string>
<!-- 定义名为“widget_under_visit_mode”的字符串资源推测是用于小部件处于访客模式下时向用户展示的提示文本告知用户在此模式下无法查看便签的具体内容 -->
<string name="notelist_string_info">...</string>
<!-- 定义名为“notelist_string_info”的字符串资源仅从“...”不太明确其确切用途,不过可能是在便签列表相关界面中用于展示某种简略信息或者占位性质的文本内容 -->
<string name="notelist_menu_new">新建便簽</string>
<!-- 定义名为“notelist_menu_new”的字符串资源用于在便签列表对应的菜单里作为创建新便签这一菜单项所显示的文字内容明确提示用户点击该菜单项可进行添加便签的操作 -->
<string name="delete_remind_time_message">成功刪除提醒</string>
<!-- 定义名为“delete_remind_time_message”的字符串资源大概率是在成功删除便签的提醒时间后向用户展示的提示消息告知用户相应的删除提醒操作已经顺利完成 -->
<string name="set_remind_time_message">創建提醒</string>
<!-- 定义名为“set_remind_time_message”的字符串资源应该是在执行设置便签提醒时间相关操作时向用户呈现的提示文本表明当前正在进行设置提醒的动作 -->
<string name="note_alert_expired">已過期</string>
<!-- 定义名为“note_alert_expired”的字符串资源可能是在便签的提醒功能过期时用于显示给用户的提示文字比如在提醒相关界面展示“已過期”字样让用户知晓提醒已过期 -->
<string name="format_date_ymd">yyyyMMdd</string>
<!-- 定义名为“format_date_ymd”的字符串资源这是定义了一种日期格式采用“yyyyMMdd”这种形式常用于对日期数据进行格式化输出比如按照此格式来存储、展示便签相关的日期信息等 -->
<string name="format_datetime_mdhm">MM月dd日 kk:mm</string>
<!-- 定义名为“format_datetime_mdhm”的字符串资源同样是一种日期时间格式的定义按照“MM月dd日 kk:mm”的格式来规范日期时间数据的展示方便在应用中统一处理和显示这类信息 -->
<string name="notealert_ok">知道了</string>
<!-- 定义名为“notealert_ok”的字符串资源推测是在便签相关提醒的操作场景里当用户确认知晓或者完成某个操作后对应的按钮或者提示文本会显示“知道了”表示用户明白了、已确认的意思 -->
<string name="notealert_enter">查看</string>
<!-- 定义名为“notealert_enter”的字符串资源可能是在便签提醒相关的交互中用于引导用户点击去查看具体便签内容的提示文字提示用户点击相应区域可以查看详情 -->
<string name="note_link_tel">呼叫電話</string>
<!-- 定义名为“note_link_tel”的字符串资源大概率是当便签中包含电话号码链接等情况时在相应位置显示的操作提示文本告知用户点击此处可以进行拨打电话的操作 -->
<string name="note_link_email">發送郵件</string>
<!-- 定义名为“note_link_email”的字符串资源应该是在便签里有邮件链接相关内容时显示给用户的提示文字提示用户点击可触发发送邮件的操作 -->
<string name="note_link_web">浏覽網頁</string>
<!-- 定义名为“note_link_web”的字符串资源可能是在便签中存在网页链接的情况下向用户展示的提示文本告知用户点击该链接可以浏览对应的网页内容 -->
<string name="note_link_other">打開地圖</string>
<!-- 定义名为“note_link_other”的字符串资源推测是在便签涉及到地图相关链接等情况时显示的提示文字提示用户点击可以打开地图应用进行相关操作 -->
<string name="format_move_notes_to_folder">已將所選 %1$d 便籤移到 %2$s 文件夾</string>
<!-- 定义名为“format_move_notes_to_folder”的字符串资源从格式来看它带有两个占位符%1$d 和 %2$s在成功将选中的便签移动到指定文件夹后会用实际移动便签的数量替换“%1$d”用具体的文件夹名称替换“%2$s”用于显示提示信息告知用户移动操作的具体情况让用户清楚知晓便签的移动结果 -->
<!-- note list string -->
<!-- 这是一个注释说明,告知下面的字符串资源是与便签列表相关的一些字符串内容 -->
<string name="menu_create_folder">新建文件夾</string>
<!-- 定义名为“menu_create_folder”的字符串资源用于在应用的菜单中作为创建新文件夹这一菜单项所显示的文字内容清晰地提示用户点击该菜单项可进行新建文件夹的操作 -->
<string name="menu_export_text">導出文本</string>
<!-- 定义名为“menu_export_text”的字符串资源用于在菜单里作为导出文本这个菜单项显示的文本内容告知用户点击该菜单项就能执行文本导出的相关操作 -->
<string name="menu_sync">同步</string>
<!-- 定义名为“menu_sync”的字符串资源用于在菜单中作为同步相关操作的菜单项所显示的文字内容提示用户点击它可以发起数据同步的操作 -->
<string name="menu_sync_cancel">取消同步</string>
<!-- 定义名为“menu_sync_cancel”的字符串资源用于在正在进行同步操作的过程中在菜单里作为取消同步这一菜单项显示的文本内容方便用户点击来终止同步操作 -->
<string name="menu_setting">設置</string>
<!-- 定义名为“menu_setting”的字符串资源用于在菜单中作为进入设置界面或者执行设置相关操作的菜单项所显示的文字内容引导用户点击该菜单项以进入设置相关功能区域 -->
<string name="menu_search">搜尋</string>
<!-- 定义名为“menu_search”的字符串资源用于在菜单中作为搜索相关操作的菜单项显示的文本内容提示用户点击该菜单项可以进行搜索相关的操作比如查找便签内容等 -->
<string name="menu_delete">刪除</string>
<!-- 定义名为“menu_delete”的字符串资源用于在菜单中作为删除相关操作的菜单项显示的文本内容告知用户点击该菜单项可以执行删除相应内容的操作例如删除便签、文件夹等 -->
<string name="menu_move">移動到文件夾</string>
<!-- 定义名为“menu_move”的字符串资源用于在菜单中作为将相关内容移动到文件夹这一菜单项显示的文本内容提示用户点击该菜单项可进行把某些内容移动到指定文件夹的操作 -->
<string name="menu_select_title">選中了 %d 項</string>
<!-- 定义名为“menu_select_title”的字符串资源从格式“選中了 %d 項”来看,它是用于在有多个项目被选中后,展示选中数量相关提示信息的文本,会根据实际选中的项目数量替换“%d”来准确告知用户选中情况 -->
<string name="menu_select_none">沒有選中項,操作無效</string>
<!-- 定义名为“menu_select_none”的字符串资源用于在没有任何项目被选中的情况下向用户显示的提示文本告知用户由于没有选中内容当前要执行的操作是无效的 -->
<string name="menu_select_all">全選</string>
<!-- 定义名为“menu_select_all”的字符串资源用于在菜单中作为全选相关操作的菜单项显示的文本内容提示用户点击该菜单项可以一次性选中所有相关的项目 -->
<string name="menu_deselect_all">取消全選</string>
<!-- 定义名为“menu_deselect_all”的字符串资源用于在菜单中作为取消全选相关操作的菜单项显示的文本内容提示用户点击该菜单项可以将已经全选的状态取消即取消选中所有项目 -->
<string name="menu_font_size">文字大小</string>
<!-- 定义名为“menu_font_size”的字符串资源用于在菜单中作为调整文字大小相关操作的菜单项显示的文本内容引导用户点击该菜单项来进行文字大小相关的设置操作 -->
<string name="menu_font_small"></string>
<!-- 定义名为“menu_font_small”的字符串资源可能是在文字大小设置的相关菜单选项里作为表示小字号这一选项所显示的文字内容便于用户选择小字体来显示文本 -->
<string name="menu_font_normal">正常</string>
<!-- 定义名为“menu_font_normal”的字符串资源推测是在文字大小设置相关的菜单中作为表示正常字号这一选项显示的文字内容方便用户将文本字体设置为正常大小 -->
<string name="menu_font_large"></string>
<!-- 定义名为“menu_font_large”的字符串资源应该是在文字大小设置相关的菜单里作为表示大字号这一选项所展示的文字内容让用户可以选择大字体来显示文本 -->
<string name="menu_font_super">超大</string>
<!-- 定义名为“menu_font_super”的字符串资源可能是在文字大小设置相关的菜单中作为表示超大字号这一选项显示的文字内容供用户选择超大字体来展示文本 -->
<string name="menu_list_mode">進入清單模式</string>
<!-- 定义名为“menu_list_mode”的字符串资源用于在菜单中作为进入清单模式比如待办事项清单等类似的模式相关操作的菜单项显示的文本内容提示用户点击该菜单项可进入对应的清单模式方便对相关内容进行清单式管理 -->
<string name="menu_normal_mode">退出清單模式</string>
<!-- 定义名为“menu_normal_mode”的字符串资源用于在菜单中作为离开清单模式例如待办事项清单等相关操作的菜单项显示的文本内容提示用户点击该菜单项可退出当前所处的清单模式恢复到常规显示状态 -->
<string name="menu_folder_view">查看文件夾</string>
<!-- 定义名为“menu_folder_view”的字符串资源用于在菜单里作为查看文件夹相关操作的菜单项所显示的文本内容告知用户点击该菜单项后可以查看指定文件夹内的内容比如查看文件夹里包含的便签等信息 -->
<string name="menu_folder_delete">刪除文件夾</string>
<!-- 定义名为“menu_folder_delete”的字符串资源用于在菜单中作为删除文件夹相关操作的菜单项显示的文本内容提示用户点击该菜单项会执行删除文件夹的操作通常可能还会有相应确认提示以防误删 -->
<string name="menu_folder_change_name">修改文件夾名稱</string>
<!-- 定义名为“menu_folder_change_name”的字符串资源用于在菜单中作为更改文件夹名称相关操作的菜单项显示的文本内容引导用户点击该菜单项来对已有的文件夹重新命名使其名称更符合需求或便于识别 -->
<string name="folder_exist">文件夾 %1$s 已存在,請重新命名</string>
<!-- 定义名为“folder_exist”的字符串资源从格式“文件夾 %1$s 已存在,請重新命名”来看,它是一种带有占位符(%1$s的提示文本通常在创建文件夹时如果要创建的文件夹名称已存在就会用实际的文件夹名称替换占位符显示该提示信息告知用户需要重命名后再进行操作 -->
<string name="menu_share">分享</string>
<!-- 定义名为“menu_share”的字符串资源用于在菜单中作为分享相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行分享操作比如分享便签内容到其他应用或者平台等 -->
<string name="menu_send_to_desktop">發送到桌面</string>
<!-- 定义名为“menu_send_to_desktop”的字符串资源用于在菜单中作为将相关内容发送到桌面例如创建桌面快捷方式等相关操作的菜单项显示的文本内容告知用户点击该菜单项可把对应的内容发送到桌面方便快速访问 -->
<string name="menu_alert">提醒我</string>
<!-- 定义名为“menu_alert”的字符串资源用于在菜单中作为设置提醒相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行提醒相关设置比如设置某个便签的提醒时间等 -->
<string name="menu_remove_remind">刪除提醒</string>
// 定义了一个名为"menu_remove_remind"的字符串资源,其显示的文本内容为"删除提醒",可能用于菜单选项等场景中表示删除相关提醒的操作提示。
<string name="menu_title_select_folder">選擇文件夾</string>
// 定义名为"menu_title_select_folder"的字符串资源,文本内容是"选择文件夹",推测是用于菜单标题中,提示用户进行文件夹选择的相关操作。
<string name="menu_move_parent_folder">上一級文件夾</string>
// 此字符串资源名为"menu_move_parent_folder",内容为"上一级文件夹",通常用于表示在文件管理相关操作中,可执行返回上一级文件夹的操作提示。
<string name="info_note_enter_desktop">已添加到桌面</string>
// 名为"info_note_enter_desktop"的字符串资源,文本表示某个笔记(便签)已经被添加到桌面了,用于给用户提示相应操作结果。
<string name="alert_title_delete">刪除</string>
// 定义的"alert_title_delete"字符串资源,文本是"删除",可能作为弹出提示框(如确认删除操作时)的标题,让用户明确操作类型是删除相关。
<string name="alert_message_delete_notes">确认要刪除所選的 %d 條便籤嗎?</string>
//
名为"alert_message_delete_notes"的字符串资源,包含了格式化占位符%d用于在需要确认删除多条便签时向用户显示询问是否删除所选具体数量通过占位符替换实际数字的便签的提示消息。
<string name="alert_message_delete_note">确认要删除該條便籤嗎?</string>
// 定义了"alert_message_delete_note"字符串资源,用于提示用户确认是否删除某一条特定便签,向用户发起删除单个便签的确认询问。
<string name="alert_message_delete_folder">確認刪除檔夾及所包含的便簽嗎?</string>
// 这个名为"alert_message_delete_folder"的字符串资源,用于在要删除文件夹及其包含的所有便签时,弹出提示框询问用户是否确认执行该删除操作。
<string name="error_sdcard_unmounted">SD卡被佔用不能操作</string>
// 定义的"error_sdcard_unmounted"字符串资源文本表示SD卡处于被占用状态无法进行相关操作用于向用户反馈SD卡操作受阻的原因。
<string name="error_sdcard_export">導出TXT時發生錯誤請檢查SD卡</string>
// 名为"error_sdcard_export"的字符串资源用于在导出TXT文件出现错误时提示用户去检查SD卡告知用户错误与SD卡相关并引导排查。
<string name="error_note_not_exist">要查看的便籤不存在</string>
// 定义了"error_note_not_exist"字符串资源,当用户尝试查看某个便签但该便签实际不存在时,用于向用户反馈相应的错误提示信息。
<string name="error_note_empty_for_clock">不能爲空便籤設置鬧鐘提醒</string>
// 此字符串资源名为"error_note_empty_for_clock",用于提示用户不能给内容为空的便签设置闹钟提醒,告知用户操作不符合要求的原因。
<string name="error_note_empty_for_send_to_desktop">不能將空便籤發送到桌面</string>
// 名为"error_note_empty_for_send_to_desktop"的字符串资源,提示用户不可以将内容为空的便签发送到桌面,说明相应操作限制情况。
<string name="success_sdcard_export">導出成功</string>
// 定义的"success_sdcard_export"字符串资源用于在成功导出SD卡相关文件比如TXT等向用户反馈操作成功的提示信息。
<string name="failed_sdcard_export">導出失敗</string>
// 名为"failed_sdcard_export"的字符串资源在导出SD卡相关文件失败时向用户显示操作失败的提示消息。
<string name="format_exported_file_location">已將文本文件(%1$s)導出至SD(%2$s)目錄</string>
//
定义了"format_exported_file_location"字符串资源,包含了格式化占位符%1$s和%2$s用于按照实际的文件名和SD卡目录路径等信息进行替换展示具体的导出文件位置情况给用户。
<!-- Sync -->
// 以下是一组和同步Sync相关的字符串资源定义这里的注释"Sync"可能是用于分组标识,方便代码阅读和维护,表明下面的字符串都和同步功能有关。
<string name="ticker_syncing">同步便簽...</string>
// 名为"ticker_syncing"的字符串资源,用于在同步便签过程中向用户展示正在同步的提示信息,告知用户当前正在执行同步操作。
<string name="ticker_success">同步成功</string>
// 定义的"ticker_success"字符串资源,在便签同步操作成功完成后,向用户反馈同步成功的提示消息。
<string name="ticker_fail">同步失敗</string>
// 名为"ticker_fail"的字符串资源,当便签同步操作失败时,用于向用户显示同步失败的提示内容。
<string name="ticker_cancel">同步已取消</string>
// 此字符串资源名为"ticker_cancel",用于在同步操作被取消后,告知用户同步已取消这一情况。
<string name="success_sync_account">與%1$s同步成功</string>
// 定义了"success_sync_account"字符串资源,包含格式化占位符%1$s用于在和特定账号实际账号名称替换占位符同步成功时向用户展示具体与哪个账号同步成功的提示信息。
<string name="error_sync_network">同步失敗,請檢查網絡和帳號設置</string>
// 名为"error_sync_network"的字符串资源,在同步失败且原因可能和网络、账号设置相关时,提示用户去检查网络连接以及账号相关设置情况。
<string name="error_sync_internal">同步失敗,發生內部錯誤</string>
// 定义的"error_sync_internal"字符串资源,用于在同步失败是由于内部错误导致时,向用户反馈同步失败是因为内部出现问题这一情况。
<string name="error_sync_cancelled">同步已取消</string>
// 此字符串资源和前面的"ticker_cancel"类似,用于在同步被取消后,向用户提示同步已取消的消息,可能在不同的代码逻辑位置使用来反馈这一情况。
<string name="sync_progress_login">登陸%1$s...</string>
// 名为"sync_progress_login"的字符串资源,包含格式化占位符%1$s用于在同步过程中登录某个账号具体账号名替换占位符向用户展示正在登录的提示信息。
<string name="sync_progress_init_list">正在獲取服務器便籤列表...</string>
// 定义了"sync_progress_init_list"字符串资源,用于在同步操作中,正在从服务器获取便签列表时,向用户反馈当前正在进行的操作阶段情况。
<string name="sync_progress_syncing">正在同步本地便籤...</string>
// 此字符串资源名为"sync_progress_syncing",用于向用户提示当前正在进行本地便签和服务器等之间的同步操作,告知用户同步操作的具体阶段。
<!-- Preferences -->
// 以下是一组和偏好设置Preferences相关的字符串资源定义注释"Preferences"用于分组标识,表明下面的字符串都与应用的偏好设置功能相关。
<string name="preferences_title">設置</string>
// 定义名为"preferences_title"的字符串资源,文本内容为"设置",可能用于作为整个应用设置界面的标题显示。
<string name="preferences_account_title">同步賬號</string>
// 名为"preferences_account_title"的字符串资源,文本表示"同步账号",推测是在设置界面中用于标识与同步账号相关设置板块的标题。
<string name="preferences_account_summary">与google task同步便簽記錄</string>
// 定义了"preferences_account_summary"字符串资源用于简要说明同步账号相关功能即告知用户通过该设置可以和google
task进行便签记录的同步操作。
<string name="preferences_last_sync_time">上次同步于 %1$s</string>
// 此字符串资源名为"preferences_last_sync_time",包含格式化占位符%1$s用于显示上次同步操作具体发生的时间实际时间替换占位符方便用户了解同步历史情况。
<string name="preferences_add_account">添加賬號</string>
// 定义的"preferences_add_account"字符串资源,文本内容为"添加账号"用于在设置界面中提示用户可执行添加账号的操作比如添加用于同步的google账号等。
<string name="preferences_menu_change_account">更換賬號</string>
// 名为"preferences_menu_change_account"的字符串资源,提示用户在相关菜单中可以进行更换同步账号的操作,告知用户存在此功能选项。
<string name="preferences_menu_remove_account">刪除賬號</string>
// 定义了"preferences_menu_remove_account"字符串资源,用于提示用户在相应菜单中可执行删除账号的操作,比如删除已添加的用于同步的账号等。
<string name="preferences_menu_cancel">取消</string>
// 此字符串资源名为"preferences_menu_cancel",在相关操作场景下提示用户可以执行取消操作,比如取消正在进行的设置更改等操作。
<string name="preferences_button_sync_immediately">立即同步</string>
// 定义的"preferences_button_sync_immediately"字符串资源,文本为"立即同步",通常用于设置界面中的按钮显示文本,提示用户点击该按钮可马上触发同步操作。
<string name="preferences_button_sync_cancel">取消同步</string>
// 名为"preferences_button_sync_cancel"的字符串资源,用于设置界面中按钮显示文本,提示用户点击该按钮可取消正在进行的同步操作。
<string name="preferences_dialog_change_account_title">當前帳號 %1$s</string>
//
定义了"preferences_dialog_change_account_title"字符串资源,包含格式化占位符%1$s用于在弹出对话框中显示当前账号的具体名称实际账号名替换占位符比如在更换账号等相关操作的对话框中展示当前账号信息。
<string name="preferences_dialog_change_account_warn_msg">如更換同步帳號,過去的帳號同步信息將被清空,再次切換的同時可能會造成數據重復</string>
//
此字符串资源名为"preferences_dialog_change_account_warn_msg",用于在用户进行更换同步账号操作时,弹出提示框向用户警告更换账号会导致过去账号的同步信息被清空,以及再次切换账号可能出现数据重复的情况,提醒用户谨慎操作。
<string name="preferences_dialog_select_account_title">同步便簽</string>
//
定义的"preferences_dialog_select_account_title"字符串资源用于作为选择账号比如选择用于同步便签的google账号相关对话框的标题提示用户该对话框的用途是进行同步便签账号相关操作。
<string name="preferences_dialog_select_account_tips">請選擇google帳號便簽將與該帳號的google task內容同步。</string>
//
名为"preferences_dialog_select_account_tips"的字符串资源在选择账号的对话框中向用户提示具体操作要求即让用户选择google账号以便后续便签能和该账号对应的google
task内容进行同步。
<string name="preferences_toast_cannot_change_account">正在同步中,不能修改同步帳號</string>
//
定义了"preferences_toast_cannot_change_account"字符串资源,用于在同步操作正在进行时,若用户尝试修改同步账号,弹出提示框告知用户当前不能进行修改账号操作,限制用户的不当操作。
<string name="preferences_toast_success_set_accout">同步帳號已設置為%1$s</string>
//
此字符串资源名为"preferences_toast_success_set_accout",包含格式化占位符%1$s用于在成功设置同步账号后向用户展示具体设置成了哪个账号实际账号名替换占位符的提示信息。
<string name="preferences_bg_random_appear_title">新建便籤背景顏色隨機</string>
// 定义的"preferences_bg_random_appear_title"字符串资源,文本表示新建便签时背景颜色会随机出现,用于在相关设置界面等地方提示用户有这样一个功能特性。
<string name="button_delete">刪除</string>
// 定义了一个名为"button_delete"的字符串资源,其文本内容为"删除",通常会被用作按钮上显示的文字,提示用户点击该按钮可执行删除相关的操作。
<string name="call_record_folder_name">通話便籤</string>
// 名为"call_record_folder_name"的字符串资源,文本表示"通话便签",可能用于标识与通话记录相关的便签所在文件夹的名称,方便用户知晓其用途和内容关联。
<string name="hint_foler_name">請輸入名稱</string>
// 此字符串资源名为"hint_foler_name",文本内容是"请输入名称",一般用于提示用户在相应的输入框等地方输入名称,比如创建文件夹或者给某个项目命名时引导用户操作。
<string name="search_label">正在搜索便籤</string>
// 定义了"search_label"字符串资源,文本显示为"正在搜索便签",常用来在界面上向用户反馈当前正在进行便签搜索这一操作状态,让用户知晓系统正在执行的任务。
<string name="search_hint">搜索便籤</string>
// 名为"search_hint"的字符串资源,内容是"搜索便签",多用于作为输入框的提示文字,提示用户在此处可以输入相关内容来进行便签的搜索操作。
<string name="search_setting_description">便籤中的文字</string>
//
定义的"search_setting_description"字符串资源,文本表明"便签中的文字",推测是用于对搜索设置相关功能进行描述,比如说明搜索是基于便签内包含的文字内容来进行的情况等。
<string name="search">便籤</string>
// 此字符串资源名为"search",文本为"便签",可能在不同的搜索相关场景下使用,比如作为菜单选项、功能名称等体现与便签搜索相关的概念。
<string name="datetime_dialog_ok">設置</string>
// 名为"datetime_dialog_ok"的字符串资源,文本是"设置",通常会用于日期时间相关对话框中的确认按钮文字显示,提示用户点击该按钮可进行相应的时间等设置操作。
<string name="datetime_dialog_cancel">取消</string>
// 定义了"datetime_dialog_cancel"字符串资源,文本为"取消",多用于日期时间相关对话框中的取消按钮文字显示,方便用户在不想进行设置等操作时点击取消当前操作流程。
<plurals name="search_results_title">
<item quantity="other"><xliff:g id="NUMBER">%1$s</xliff:g> 條符合”<xliff:g id="SEARCH">%2$s</xliff:g>“的搜尋結果</item>
</plurals>
// 定义了一个名为"search_results_title"的复数形式plurals的字符串资源。
// 它里面的
<item>元素用于根据数量情况来展示不同的文本内容这里quantity="other"表示在其他数量(非特定单一数量情况)时的显示规则。
// 其中包含了两个格式化占位符<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="SEARCH">
%2$s</xliff:g>,分别用于替换实际的符合结果数量以及搜索的具体内容,整体用于向用户展示搜索便签后得到的符合特定搜索条件的结果数量及相应搜索内容的提示信息。
</resources>

@ -1,42 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources>
<!-- 这是一个用于定义各种资源的根标签,在安卓开发中,像字符串、数组、颜色等资源都可以在这里面进行定义 -->
<!-- Backup format -->
<!-- 此处是一个注释,用于说明下面定义的资源数组与备份格式相关,方便开发者理解其用途 -->
<string-array name="format_for_exported_note">
<!-- 定义一个名为“format_for_exported_note”的字符串数组从命名推测可能是用于格式化导出笔记时相关信息的格式 -->
<item>-%s</item> <!-- format_folder_name -->
<!-- 数组中的一个元素,这里是一个字符串格式的占位符(%s从注释来看可能是用于格式化文件夹名称相关信息具体内容会在后续代码中替换该占位符 -->
<item>--%s</item> <!-- format_folder_note_date -->
<!-- 数组中的另一个元素,同样是字符串格式占位符,推测是用于格式化文件夹内笔记日期相关信息 -->
<item>--%s</item> <!-- format_note_date -->
<!-- 数组中的元素,用于格式化笔记本身日期相关信息的占位符 -->
<item>--%s</item> <!-- format_note_content -->
<!-- 数组中的元素,用于格式化笔记内容相关信息的占位符 -->
</string-array>
<string-array name="menu_share_ways">
<!-- 定义一个名为“menu_share_ways”的字符串数组从命名推测是用于表示分享菜单中可选择的分享方式相关信息 -->
<item>Messaging</item>
<!-- 数组中的一个元素代表一种分享方式这里是“Messaging”消息应用意味着用户可以通过消息应用来分享相关内容 -->
<item>Email</item>
<!-- 数组中的另一个元素,代表另一种分享方式,即通过电子邮件来分享相关内容 -->
</string-array>
</resources>

@ -1,26 +1,20 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources>
<!-- <resources>标签是安卓资源文件中的根标签,用于定义各种类型的资源,比如字符串、颜色、数组等资源都可以放在这里面定义 -->
<color name="user_query_highlight">
<!-- 定义一个名为“user_query_highlight”的颜色资源从命名推测可能是用于突出显示用户查询相关内容时的颜色设定 -->
#335b5b5b
<!-- 具体的颜色值,这里使用十六进制格式来表示颜色,格式为 #AARRGGBB其中 AA 表示透明度RR、GG、BB 分别表示红、绿、蓝三种颜色通道的值),在这个例子中,透明度为 51十六进制的 33红色、绿色、蓝色通道的值均为 91十六进制的 5b整体定义了一种偏灰色且带有一定透明度的颜色 -->
</color>
</resources>
<color name="user_query_highlight">#335b5b5b</color>
</resources>

@ -1,46 +1,24 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources>
<!-- <resources>标签是安卓资源文件中的根标签,用于定义各种类型的资源,像尺寸、字符串、颜色等不同类型资源都可以在此标签内进行定义 -->
<dimen name="text_font_size_super">
<!-- 定义一个名为“text_font_size_super”的尺寸资源从命名推测是用于设置文本字体超级大的字号尺寸 -->
33sp
<!-- 具体的尺寸值这里使用“sp”可缩放像素作为单位意味着该字号大小会根据用户在设备上设置的字体缩放比例进行相应的缩放此处字号大小设定为 33 可缩放像素 -->
</dimen>
<dimen name="text_font_size_large">
<!-- 定义一个名为“text_font_size_large”的尺寸资源推测是用于设置文本字体较大的字号尺寸 -->
26sp
<!-- 具体的尺寸值为 26 可缩放像素,同样会随用户设备字体缩放设置而变化 -->
</dimen>
<dimen name="text_font_size_medium">
<!-- 定义一个名为“text_font_size_medium”的尺寸资源通常可用于设置文本字体中等大小的字号尺寸 -->
20sp
<!-- 对应的尺寸值是 20 可缩放像素,其字号大小会根据设备相关设置动态调整 -->
</dimen>
<dimen name="text_font_size_normal">
<!-- 定义一个名为“text_font_size_normal”的尺寸资源大概率是用于设置文本字体常规大小的字号尺寸 -->
17sp
<!-- 具体字号大小设定为 17 可缩放像素,会依据设备的字体缩放配置进行相应改变 -->
</dimen>
<dimen name="text_font_size_small">
<!-- 定义一个名为“text_font_size_small”的尺寸资源应该是用于设置文本字体较小的字号尺寸 -->
14sp
<!-- 尺寸值为 14 可缩放像素,其大小可随用户设备字体缩放情况而变动 -->
</dimen>
<dimen name="text_font_size_super">33sp</dimen>
<dimen name="text_font_size_large">26sp</dimen>
<dimen name="text_font_size_medium">20sp</dimen>
<dimen name="text_font_size_normal">17sp</dimen>
<dimen name="text_font_size_small">14sp</dimen>
</resources>

@ -1,300 +1,135 @@
<?xml version="1.0" encoding="utf-8"?><!-- XML声明表明该 XML 文件遵循的版本是 1.0,使用的编码格式是 utf-8这是 XML 文件开头的标准标识,用于告知解析器按照此版本和编码规则来正确解析该文件 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
此处是版权相关声明,说明代码所属的开源社区是 The MiCode Open Source Community版权时间范围在 2010 - 2011 年。
Licensed under the Apache License, Version 2.0 (the "License");
表示此文件遵循 Apache License 2.0 开源协议进行授权许可,意味着若要使用该文件,必须遵守该协议的相关规定。
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
告知可以通过访问网址http://www.apache.org/licenses/LICENSE-2.0)获取 Apache 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.
提示查看协议内容,以了解关于权限及限制方面的详细规定。 -->
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- <resources>是安卓资源文件的根标签用于定义各类资源这里引入了两个命名空间“android”用于安卓相关的资源属性设置等操作“xliff”常用于国际化文本处理相关场景 -->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Notes</string>
<!-- 定义一个名为“app_name”的字符串资源该资源大概率用于表示整个应用程序的名称在这里被设置为“Notes”很可能是一款笔记类应用的名称显示 -->
<string name="app_widget2x2">Notes 2x2</string>
<!-- 定义名为“app_widget2x2”的字符串资源推测是用于描述应用中尺寸为 2x2 的小部件对应的显示名称,方便用户识别和区分不同尺寸的小部件 -->
<string name="app_widget4x4">Notes 4x4</string>
<!-- 定义名为“app_widget4x4”的字符串资源同理应该是用于表示应用里尺寸为 4x4 的小部件的显示名称,起到标识该特定尺寸小部件的作用 -->
<string name="widget_havenot_content">No associated note found, click to create associated note.</string>
<!-- 定义名为“widget_havenot_content”的字符串资源从其内容来看可能是在小部件上显示的提示信息当没有与之关联的笔记时提示用户点击可以去创建关联的笔记 -->
<string name="widget_under_visit_mode">Privacy modecan not see note content</string>
<!-- 定义名为“widget_under_visit_mode”的字符串资源推测是用于小部件处于隐私访问模式下时向用户展示的提示文本告知用户在此模式下无法查看笔记的具体内容 -->
<string name="notelist_string_info">...</string>
<!-- 定义名为“notelist_string_info”的字符串资源仅从“...”不太明确其确切用途,不过可能是在笔记列表相关界面中用于展示某种简略信息或者占位性质的文本内容 -->
<string name="notelist_menu_new">Add note</string>
<!-- 定义名为“notelist_menu_new”的字符串资源用于在笔记列表对应的菜单里作为创建新笔记这一菜单项所显示的文字内容明确提示用户点击该菜单项可进行添加笔记的操作 -->
<string name="delete_remind_time_message">Delete reminder successfully</string>
<!-- 定义名为“delete_remind_time_message”的字符串资源大概率是在成功删除提醒时间后向用户展示的提示消息告知用户相应的删除提醒操作已经顺利完成 -->
<string name="set_remind_time_message">Set reminder</string>
<!-- 定义名为“set_remind_time_message”的字符串资源应该是在执行设置提醒时间相关操作时向用户呈现的提示文本表明当前正在进行设置提醒的动作 -->
<string name="note_alert_expired">Expired</string>
<!-- 定义名为“note_alert_expired”的字符串资源可能是在笔记的提醒功能过期时用于显示给用户的提示文字比如在提醒相关界面展示“Expired”字样让用户知晓提醒已过期 -->
<string name="format_date_ymd">yyyyMMdd</string>
<!-- 定义名为“format_date_ymd”的字符串资源这是定义了一种日期格式采用“yyyyMMdd”这种形式常用于对日期数据进行格式化输出比如按照此格式来存储、展示笔记相关的日期信息等 -->
<string name="format_datetime_mdhm">MMMd kk:mm</string>
<!-- 定义名为“format_datetime_mdhm”的字符串资源同样是一种日期时间格式的定义按照“MMMd kk:mm”的格式来规范日期时间数据的展示方便在应用中统一处理和显示这类信息 -->
<string name="notealert_ok">Got it</string>
<!-- 定义名为“notealert_ok”的字符串资源推测是在笔记相关提醒的操作场景里当用户确认知晓或者完成某个操作后对应的按钮或者提示文本会显示“Got it”表示用户明白了、已确认的意思 -->
<string name="notealert_enter">Take a look</string>
<!-- 定义名为“notealert_enter”的字符串资源可能是在笔记提醒相关的交互中用于引导用户点击去查看具体笔记内容的提示文字提示用户点击相应区域可以查看详情 -->
<string name="note_link_tel">Call</string>
<!-- 定义名为“note_link_tel”的字符串资源大概率是当笔记中包含电话号码链接等情况时在相应位置显示的操作提示文本告知用户点击此处可以进行拨打电话的操作 -->
<string name="note_link_email">Send email</string>
<!-- 定义名为“note_link_email”的字符串资源应该是在笔记里有邮件链接相关内容时显示给用户的提示文字提示用户点击可触发发送邮件的操作 -->
<string name="note_link_web">Browse web</string>
<!-- 定义名为“note_link_web”的字符串资源可能是在笔记中存在网页链接的情况下向用户展示的提示文本告知用户点击该链接可以浏览对应的网页内容 -->
<string name="note_link_other">Open map</string>
<!-- 定义名为“note_link_other”的字符串资源推测是在笔记涉及到地图相关链接等情况时显示的提示文字提示用户点击可以打开地图应用进行相关操作 -->
<!-- Text export file information -->
<!-- 这是一个注释说明,告知下面的字符串资源是与文本导出文件相关的一些信息 -->
<string name="file_path">/MIUI/notes/</string>
<!-- 定义名为“file_path”的字符串资源此资源用于指定文本导出文件在设备中的存储路径这里设定的路径为“/MIUI/notes/”,也就是导出的文件会存放在该目录下 -->
<string name="file_name_txt_format">notes_%s.txt</string>
<!-- 定义名为“file_name_txt_format”的字符串资源它规定了文本导出文件的文件名格式其中“%s”是一个占位符后续会根据具体情况替换为相应内容以此生成实际的文件名整体格式为“notes_具体内容.txt” -->
<!-- notes list string -->
<!-- 注释说明下面的字符串资源是和笔记列表相关的字符串内容 -->
<string name="format_folder_files_count">(%d)</string>
<!-- 定义名为“format_folder_files_count”的字符串资源从格式“(%d)”来看,它是一种占位符形式的字符串,通常用于在展示文件夹内文件数量相关信息时,会将实际的文件数量替换“%d”从而准确显示数量情况 -->
<string name="menu_create_folder">New Folder</string>
<!-- 定义名为“menu_create_folder”的字符串资源用于在应用的菜单中作为创建新文件夹这一菜单项所显示的文字内容清晰地提示用户点击该菜单项可进行新建文件夹的操作 -->
<string name="menu_export_text">Export text</string>
<!-- 定义名为“menu_export_text”的字符串资源用于在菜单里作为导出文本这个菜单项显示的文本内容告知用户点击该菜单项就能执行文本导出的相关操作 -->
<string name="menu_sync">Sync</string>
<!-- 定义名为“menu_sync”的字符串资源用于在菜单中作为同步相关操作的菜单项所显示的文字内容提示用户点击它可以发起数据同步的操作 -->
<string name="menu_sync_cancel">Cancel syncing</string>
<!-- 定义名为“menu_sync_cancel”的字符串资源用于在正在进行同步操作的过程中在菜单里作为取消同步这一菜单项显示的文本内容方便用户点击来终止同步操作 -->
<string name="menu_setting">Settings</string>
<!-- 定义名为“menu_setting”的字符串资源用于在菜单中作为进入设置界面或者执行设置相关操作的菜单项所显示的文字内容引导用户点击该菜单项以进入设置相关功能区域 -->
<string name="menu_search">Search</string>
<!-- 定义名为“menu_search”的字符串资源用于在菜单中作为搜索相关操作的菜单项显示的文本内容提示用户点击该菜单项可以进行搜索相关的操作比如查找笔记内容等 -->
<string name="menu_delete">Delete</string>
<!-- 定义名为“menu_delete”的字符串资源用于在菜单中作为删除相关操作的菜单项显示的文本内容告知用户点击该菜单项可以执行删除相应内容的操作例如删除笔记、文件夹等 -->
<string name="menu_move">Move to folder</string>
<!-- 定义名为“menu_move”的字符串资源用于在菜单中作为将相关内容移动到文件夹这一菜单项显示的文本内容提示用户点击该菜单项可进行把某些内容移动到指定文件夹的操作 -->
<string name="menu_select_title">%d selected</string>
<!-- 定义名为“menu_select_title”的字符串资源从格式“%d selected”来看它是用于在有多个项目被选中后展示选中数量相关提示信息的文本会根据实际选中的项目数量替换“%d”来准确告知用户选中情况 -->
<string name="menu_select_none">Nothing selected, the operation is invalid</string>
<!-- 定义名为“menu_select_none”的字符串资源用于在没有任何项目被选中的情况下向用户显示的提示文本告知用户由于没有选中内容当前要执行的操作是无效的 -->
<string name="menu_select_all">Select all</string>
<!-- 定义名为“menu_select_all”的字符串资源用于在菜单中作为全选相关操作的菜单项显示的文本内容提示用户点击该菜单项可以一次性选中所有相关的项目 -->
<string name="menu_deselect_all">Deselect all</string>
<!-- 定义名为“menu_deselect_all”的字符串资源用于在菜单中作为取消全选相关操作的菜单项显示的文本内容提示用户点击该菜单项可以将已经全选的状态取消即取消选中所有项目 -->
<string name="menu_font_size">Font size</string>
<!-- 定义名为“menu_font_size”的字符串资源用于在菜单中作为调整字体大小相关操作的菜单项显示的文本内容引导用户点击该菜单项来进行字体大小相关的设置操作 -->
<string name="menu_font_small">Small</string>
<!-- 定义名为“menu_font_small”的字符串资源可能是在字体大小设置的相关菜单选项里作为表示小字号这一选项所显示的文字内容便于用户选择小字体来显示文本 -->
<string name="menu_font_normal">Medium</string>
<!-- 定义名为“menu_font_normal”的字符串资源推测是在字体大小设置相关的菜单中作为表示中等字号这一选项显示的文字内容方便用户将文本字体设置为中等大小 -->
<string name="menu_font_large">Large</string>
<!-- 定义名为“menu_font_large”的字符串资源应该是在字体大小设置相关的菜单里作为表示大字号这一选项所展示的文字内容让用户可以选择大字体来显示文本 -->
<string name="menu_font_super">Super</string>
<!-- 定义名为“menu_font_super”的字符串资源可能是在字体大小设置相关的菜单中作为表示超大字号这一选项显示的文字内容供用户选择超大字体来展示文本 -->
<string name="menu_list_mode">Enter check list</string>
<!-- 定义名为“menu_list_mode”的字符串资源用于在菜单中作为进入清单模式比如待办事项清单等类似的模式相关操作的菜单项显示的文本内容提示用户点击该菜单项可进入对应的清单模式方便对相关内容进行清单式管理 -->
<string name="menu_normal_mode">Leave check list</string>
<!-- 定义名为“menu_normal_mode”的字符串资源用于在菜单中作为离开清单模式例如待办事项清单等相关操作的菜单项显示的文本内容提示用户点击该菜单项可退出当前所处的清单模式恢复到常规显示状态 -->
<string name="menu_folder_view">View folder</string>
<!-- 定义名为“menu_folder_view”的字符串资源用于在菜单里作为查看文件夹相关操作的菜单项所显示的文本内容告知用户点击该菜单项后可以查看指定文件夹内的内容比如查看文件夹里包含的笔记等信息 -->
<string name="menu_folder_delete">Delete folder</string>
<!-- 定义名为“menu_folder_delete”的字符串资源用于在菜单中作为删除文件夹相关操作的菜单项显示的文本内容提示用户点击该菜单项会执行删除文件夹的操作通常可能还会有相应确认提示以防误删 -->
<string name="menu_folder_change_name">Change folder name</string>
<!-- 定义名为“menu_folder_change_name”的字符串资源用于在菜单中作为更改文件夹名称相关操作的菜单项显示的文本内容引导用户点击该菜单项来对已有的文件夹重新命名使其名称更符合需求或便于识别 -->
<string name="folder_exist">The folder %1$s exist, please rename</string>
<!-- 定义名为“folder_exist”的字符串资源从格式“The folder %1$s exist, please rename”来看它是一种带有占位符%1$s的提示文本通常在创建文件夹时如果要创建的文件夹名称已存在就会用实际的文件夹名称替换占位符显示该提示信息告知用户需要重命名后再进行操作 -->
<string name="menu_share">Share</string>
<!-- 定义名为“menu_share”的字符串资源用于在菜单中作为分享相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行分享操作比如分享笔记内容到其他应用或者平台等 -->
<string name="menu_send_to_desktop">Send to home</string>
<!-- 定义名为“menu_send_to_desktop”的字符串资源用于在菜单中作为将相关内容发送到桌面例如创建桌面快捷方式等相关操作的菜单项显示的文本内容告知用户点击该菜单项可把对应的内容发送到桌面方便快速访问 -->
<string name="menu_alert">Remind me</string>
<!-- 定义名为“menu_alert”的字符串资源用于在菜单中作为设置提醒相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行提醒相关设置比如设置某个笔记的提醒时间等 -->
<string name="menu_remove_remind">Delete reminder</string>
<!-- 定义名为“menu_remove_remind”的字符串资源用于在菜单中作为删除提醒相关操作的菜单项显示的文本内容提示用户点击该菜单项可删除已设置好的提醒取消之前设定的提醒功能 -->
<string name="menu_title_select_folder">Select folder</string>
<!-- 定义名为“menu_title_select_folder”的字符串资源用于在选择文件夹相关操作时作为标题类提示文本显示告知用户当前正在进行选择文件夹的操作让用户明确操作意图 -->
<string name="menu_move_parent_folder">Parent folder</string>
<!-- 定义名为“menu_move_parent_folder”的字符串资源用于在涉及将内容移动到上级文件夹等相关操作时作为提示文本显示告知用户可以选择将相应内容移动到当前所在文件夹的上级文件夹中 -->
<string name="info_note_enter_desktop">Note added to home</string>
<!-- 定义名为“info_note_enter_desktop”的字符串资源可能是在笔记成功添加到桌面比如创建桌面快捷方式成功等情况用于显示的提示信息告知用户对应的笔记已经被添加到桌面了方便用户知晓操作结果 -->
<string name="alert_message_delete_folder">Confirm to delete folder and its notes?</string>
<!-- 定义名为“alert_message_delete_folder”的字符串资源用于在要删除文件夹及其内部笔记时弹出提示框显示的询问信息询问用户是否确认执行删除该文件夹以及里面所有笔记的操作需要用户明确回应以避免误操作 -->
<string name="alert_title_delete">Delete selected notes</string>
<!-- 定义名为“alert_title_delete”的字符串资源用于在删除选中笔记相关操作时弹出提示框的标题文本清晰地告知用户当前操作是针对已选中的笔记进行删除让用户快速了解提示框所关联的操作内容 -->
<string name="alert_message_delete_notes">Confirm to delete the selected %d notes?</string>
<!-- 定义名为“alert_message_delete_notes”的字符串资源从格式“Confirm to delete the selected %d notes?”来看,它是在要删除多个选中笔记时,弹出提示框显示的询问信息,会根据实际选中笔记的数量替换占位符“%d”来准确询问用户是否确认删除相应数量的笔记 -->
<string name="alert_message_delete_note">Confirm to delete this note?</string>
<!-- 定义名为“alert_message_delete_note”的字符串资源用于在要删除单个笔记时弹出提示框显示的询问信息询问用户是否确认删除当前这一个笔记获取用户的明确操作意向 -->
<string name="format_move_notes_to_folder">Have moved selected %1$d notes to %2$s folder</string>
<!-- 定义名为“format_move_notes_to_folder”的字符串资源从格式来看它是用于在成功将选中笔记移动到指定文件夹后显示的提示信息会用实际移动笔记的数量替换占位符“%1$d”用具体的文件夹名称替换“%2$s”告知用户移动操作的具体情况 -->
<!-- Error information -->
<!-- 这是一个注释说明,告知下面的字符串资源是与错误相关的提示信息 -->
<string name="error_sdcard_unmounted">SD card busy, not available now</string>
<!-- 定义名为“error_sdcard_unmounted”的字符串资源用于在 SD 卡处于忙碌状态(比如正在被其他程序使用、出现故障等情况),导致无法正常使用时,显示的提示信息,告知用户当前 SD 卡不可用,无法进行相关操作 -->
<string name="error_sdcard_export">Export failed, please check SD card</string>
<!-- 定义名为“error_sdcard_export”的字符串资源在文本导出操作失败且原因可能与 SD 卡相关(比如 SD 卡空间不足、连接异常等)时,显示该提示信息,提示用户去检查 SD 卡的情况,以便排查问题所在 -->
<string name="error_note_not_exist">The note is not exist</string>
<!-- 定义名为“error_note_not_exist”的字符串资源当要操作的笔记不存在比如查找、编辑、删除某个不存在的笔记时会显示该提示信息告知用户指定的笔记不存在操作无法进行 -->
<string name="error_note_empty_for_clock">Sorry, can not set clock on empty note</string>
<!-- 定义名为“error_note_empty_for_clock”的字符串资源用于在尝试对空白笔记没有内容的笔记设置闹钟提醒等与时间相关操作时显示的提示信息告知用户无法在空白笔记上进行此类操作需要先添加内容等 -->
<string name="error_note_empty_for_send_to_desktop">Sorry, can not send and empty note to home</string>
<!-- 定义名为“error_note_empty_for_send_to_desktop”的字符串资源在试图将空白笔记发送到桌面比如创建桌面快捷方式显示该提示信息告知用户不能将空白笔记发送到桌面可能需要先完善笔记内容等 -->
<string name="success_sdcard_export">Export successful</string>
<!-- 定义名为“success_sdcard_export”的字符串资源在文本导出到 SD 卡操作成功后,用于显示的提示信息,告知用户导出操作已经顺利完成,让用户知晓操作结果 -->
<string name="failed_sdcard_export">Export fail</string>
<!-- 定义名为“failed_sdcard_export”的字符串资源当文本导出到 SD 卡操作失败时,显示该提示信息,简单告知用户导出失败了,不过可能还需要结合其他错误提示进一步排查原因 -->
<string name="format_exported_file_location">Export text file (%1$s) to SD (%2$s) directory</string>
<!-- 定义名为“format_exported_file_location”的字符串资源从格式来看它带有两个占位符%1$s 和 %2$s通常用于在告知用户文本导出文件的存放位置信息时会用实际的文件名替换“%1$s”用 SD 卡的具体目录路径替换“%2$s”清晰展示导出文件的具体位置情况 -->
<!-- Sync -->
<!-- 这是一个注释说明告知下面的字符串资源是与同步Sync相关的提示信息 -->
<string name="ticker_syncing">Syncing notes...</string>
<!-- 定义名为“ticker_syncing”的字符串资源在开始进行笔记同步操作时用于显示的提示信息告知用户正在同步笔记让用户知晓当前操作状态一般可能会以滚动条文字等形式展示 -->
<string name="ticker_success">Sync is successful</string>
<!-- 定义名为“ticker_success”的字符串资源在笔记同步操作成功完成后用于显示的提示信息告知用户同步已经顺利完成让用户了解操作结果 -->
<string name="ticker_fail">Sync is failed</string>
<!-- 定义名为“ticker_fail”的字符串资源当笔记同步操作失败时用于显示的提示信息告知用户同步失败了通常可能还需要结合其他相关错误提示进一步排查原因 -->
<string name="ticker_cancel">Sync is canceled</string>
<!-- 定义名为“ticker_cancel”的字符串资源在同步操作被取消比如用户手动点击取消按钮等情况用于显示的提示信息告知用户同步操作已被取消让用户知晓当前状态变化 -->
<string name="success_sync_account">Sync is successful with account %1$s</string>
<!-- 定义名为“success_sync_account”的字符串资源从格式“Sync is successful with account %1$s”来看它带有一个占位符%1$s在使用特定账户成功完成同步操作后会用实际的账户名称替换占位符告知用户使用哪个账户同步成功了明确同步相关情况 -->
<string name="error_sync_network">Sync failed, please check network and account settings</string>
<!-- 定义名为“error_sync_network”的字符串资源当笔记同步操作失败且原因可能与网络或者账户设置相关比如网络连接不稳定、账户密码错误等显示该提示信息提示用户去检查网络以及账户设置情况以排查同步失败的问题所在 -->
<string name="error_sync_internal">Sync failed, internal error occurs</string>
<!-- 定义名为“error_sync_internal”的字符串资源在笔记同步操作因内部错误比如应用自身的代码逻辑问题、服务器端问题等导致失败时显示该提示信息告知用户同步失败是由于内部出现错误不过具体原因可能还需要进一步排查分析 -->
<string name="error_sync_cancelled">Sync is canceled</string>
<!-- 定义名为“error_sync_cancelled”的字符串资源在同步操作被取消比如因程序异常等情况自动取消用于显示的提示信息告知用户同步操作已被取消与前面手动取消同步操作后显示的提示信息类似只是触发取消的原因不同 -->
<string name="sync_progress_login">Logging into %1$s...</string>
<!-- 定义名为“sync_progress_login”的字符串资源从格式“Logging into %1$s...”来看,它带有一个占位符(%1$s在同步操作过程中当正在登录相关账户比如登录到云端服务账户用于同步笔记会用实际的账户名称替换占位符告知用户正在登录哪个账户让用户了解同步操作的进展情况 -->
<string name="sync_progress_init_list">Getting remote note list...</string>
<!-- 定义名为“sync_progress_init_list”的字符串资源在同步操作中当正在获取远程笔记列表比如从云端服务器获取存储的笔记列表以便和本地笔记进行对比同步用于显示的提示信息告知用户当前正在获取远程笔记列表体现同步操作的进度状态 -->
<string name="sync_progress_syncing">Synchronize local notes with Google Task...</string>
<!-- 定义名为“sync_progress_syncing”的 string 资源,在同步操作进行到将本地笔记与 Google Task可能是谷歌的某种任务管理或笔记服务用于存储和同步笔记等进行同步的阶段时用于显示的提示信息告知用户当前正在进行具体的笔记同步操作步骤让用户知晓同步进展 -->
<!-- Preferences -->
<!-- 这是一个注释说明告知下面的字符串资源是与偏好设置Preferences相关的提示信息 -->
<string name="preferences_title">Settings</string>
<!-- 定义名为“preferences_title”的字符串资源用于在应用的偏好设置界面或者相关菜单中作为显示标题的文本内容告知用户当前进入的是设置相关的功能区域方便用户识别和操作 -->
<string name="preferences_account_title">Sync account</string>
<!-- 定义名为“preferences_account_title”的字符串资源用于在偏好设置中与同步账户相关的设置区域作为显示标题的文本内容提示用户该部分设置是针对同步账户进行操作的比如选择、更改同步账户等 -->
<string name="preferences_account_summary">Sync notes with google task</string>
<!-- 定义名为“preferences_account_summary”的字符串资源用于在同步账户相关设置区域作为对该设置功能的简要说明文本内容告知用户在这里可以将笔记与谷歌任务进行同步让用户了解该设置选项的作用 -->
<string name="preferences_last_sync_time">Last sync time %1$s</string>
<!-- 定义名为“preferences_last_sync_time”的字符串资源从格式“Last sync time %1$s”来看它带有一个占位符%1$s通常用于在显示上次同步时间信息时会用实际的时间数据按照一定格式存储的时间字符串替换占位符准确告知用户上次同步操作是什么时候进行的 -->
<string name="preferences_last_sync_time_format">yyyy-MM-dd hh:mm:ss</string>
<!-- 定义名为“preferences_last_sync_time_format”的字符串资源它规定了上次同步时间的显示格式采用“yyyy-MM-dd hh:mm:ss”这种常见的年--日 时:分:秒的格式,便于统一展示和识别同步时间信息 -->
<string name="preferences_add_account">Add account</string>
<!-- 定义名为“preferences_add_account”的字符串资源用于在偏好设置中作为添加账户比如添加用于同步笔记的新账户相关操作的菜单项或按钮显示的文本内容提示用户点击可进行添加账户的操作 -->
<string name="preferences_menu_change_account">Change sync account</string>
<!-- 定义名为“preferences_menu_change_account”的字符串资源用于在偏好设置的菜单中作为更改同步账户相关操作的菜单项显示的文本内容提示用户点击该菜单项可进行更改当前同步账户的操作 -->
<string name="preferences_menu_remove_account">Remove sync account</string>
<!-- 定义名为“preferences_menu_remove_account”的字符串资源用于在偏好设置的菜单中作为移除同步账户相关操作的菜单项显示的文本内容提示用户点击该菜单项可执行移除已有的同步账户的操作 -->
<string name="preferences_menu_cancel">Cancel</string>
<!-- 定义名为“preferences_menu_cancel”的字符串资源用于在偏好设置相关操作过程中比如正在添加、更改、移除账户等操作时作为取消当前操作的菜单项或按钮显示的文本内容提示用户点击可取消正在进行的操作回到之前的状态 -->
<string name="preferences_button_sync_immediately">Sync immediately</string>
<!-- 定义名为“preferences_button_sync_immediately”的字符串资源用于在偏好设置界面或者相关区域作为立即进行同步操作的按钮显示的文本内容提示用户点击该按钮可马上发起笔记同步操作无需等待其他定时同步等情况 -->
<string name="preferences_button_sync_cancel">Cancel syncing</string>
<!-- 定义名为“preferences_button_sync_cancel”的字符串资源用于在正在进行同步操作时在偏好设置界面或者相关区域作为取消同步操作的按钮显示的文本内容提示用户点击该按钮可终止当前正在进行的同步操作 -->
<string name="preferences_dialog_change_account_title">Current account %1$s</string>
<!-- 定义名为“preferences_dialog_change_account_title”的字符串资源从格式“Current account %1$s”来看它带有一个占位符%1$s在弹出更改账户相关的对话框时会用实际的当前账户名称替换占位符作为对话框的标题显示明确告知用户当前正在操作的是哪个账户 -->
<string name="preferences_dialog_change_account_warn_msg">All sync related information will be deleted, which may result in duplicated items sometime</string>
<!-- 定义名为“preferences_dialog_change_account_warn_msg”的字符串资源用于在弹出更改账户相关对话框时作为显示警告信息的文本内容告知用户更改账户操作会导致所有与同步相关的信息被删除并且有可能会出现重复的项目提醒用户谨慎操作 -->
<string name="preferences_dialog_select_account_title">Sync notes</string>
<!-- 定义名为“preferences_dialog_select_account_title”的字符串资源用于在弹出选择账户用于同步笔记相关的对话框时作为对话框的标题显示的文本内容告知用户当前对话框是用于选择同步笔记的账户让用户明确操作意图 -->
<string name="preferences_dialog_select_account_tips">Please select a google account. Local notes will be synced with google task.</string>
<!-- 定义名为“preferences_dialog_select_account_tips”的字符串资源用于在弹出选择账户相关对话框时作为提示信息的文本内容告知用户需要选择一个谷歌账户并且提示用户选择-->
<string name="button_delete">Delete</string>
<!-- 定义名为“button_delete”的字符串资源通常用于在界面上作为按钮显示的文本内容提示用户点击该按钮可执行删除相关的操作比如删除某个笔记、文件或者其他数据项等 -->
<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="button_delete">Delete</string>
<string name="call_record_folder_name">Call notes</string>
<!-- 定义名为“call_record_folder_name”的字符串资源推测是用于表示存放通话记录相关笔记或者类似与通话相关内容记录的文件等的文件夹名称方便在应用中对这类特定内容进行归类和识别 -->
<string name="hint_foler_name">Input name</string>
<!-- 定义名为“hint_foler_name”的字符串资源大概率是用于在需要用户输入文件夹名称的场景下作为提示信息显示给用户告知用户在此处输入相应的名称引导用户完成命名操作 -->
<string name="search_label">Searching Notes</string>
<!-- 定义名为“search_label”的字符串资源可能是在搜索功能启动后用于显示正在搜索笔记这一状态的提示文本比如在搜索框附近或者搜索界面上展示让用户知晓当前正在进行搜索操作 -->
<string name="search_hint">Search notes</string>
<!-- 定义名为“search_hint”的字符串资源一般用于作为搜索框内的占位提示文字提示用户在此处输入内容来进行笔记搜索引导用户使用搜索功能查找想要的笔记内容 -->
<string name="search_setting_description">Text in your notes</string>
<!-- 定义名为“search_setting_description”的字符串资源或许是用于在搜索相关设置界面中作为对搜索功能的描述文本告知用户搜索的范围是笔记内包含的文本内容让用户了解搜索的具体情况 -->
<string name="search">Notes</string>
<!-- 定义名为“search”的字符串资源可能是用于标识搜索功能或者搜索相关区域的名称等例如在菜单中作为搜索选项对应的显示文字提示用户点击可进入搜索相关操作界面 -->
<string name="datetime_dialog_ok">set</string>
<!-- 定义名为“datetime_dialog_ok”的字符串资源通常是在日期时间相关的对话框比如设置提醒时间、编辑笔记时间等涉及时间选择的对话框作为确认按钮显示的文本内容提示用户点击该按钮可完成时间设置等相关操作即表示“确定、设置”的意思 -->
<string name="datetime_dialog_cancel">cancel</string>
<!-- 定义名为“datetime_dialog_cancel”的字符串资源同样是在日期时间相关的对话框中作为取消按钮显示的文本内容提示用户点击该按钮可取消当前正在进行的时间相关操作关闭对话框且不保存更改等 -->
<plurals name="search_results_title">
<!-- 定义名为“search_results_title”的复数形式的字符串资源用于根据搜索结果数量的不同情况单数或复数来显示相应合适的标题文本常用于展示搜索到的笔记数量对应的提示信息 -->
<item quantity="one"><xliff:g example="1" id="number">%1$s</xliff:g> result for \"<xliff:g example="???" id="search">%2$s</xliff:g>\"</item>
<!-- 定义复数资源中的一个子项当搜索结果数量为“一”quantity="one")时显示此文本内容。其中包含了两个占位符(<xliff:g>标签定义),%1$s 通常会被替换为实际的结果数量数字,%2$s 会被替换为搜索的关键词内容,用于准确告知用户搜索到了一个结果以及对应的搜索关键词是什么 -->
<item quantity="one"><xliff:g id="number" example="1">%1$s</xliff:g> result for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
<!-- Case of 0 or 2 or more results. -->
<item quantity="other"><xliff:g id="number" example="15">%1$s</xliff:g> results for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
<!-- 定义复数资源中的另一个子项当搜索结果数量为“零”或者“两个及以上”quantity="other")时显示此文本内容。同样包含两个占位符,作用与上面类似,会根据实际结果数量和搜索关键词来替换占位符,告知用户搜索到的结果数量以及对应的搜索关键词情况 -->
</plurals>
</resources>
</resources>

@ -1,119 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
// XML 声明,指定该 XML 文件的版本为 1.0,字符编码采用 UTF-8 格式,这是 XML 文件开头的标准声明部分,用于告知解析器如何处理该文件内容。
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
<!-- 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
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
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.
-->
// 版权声明及开源许可相关注释说明该代码文件的版权归属MiCode 开源社区,时间范围是 2010 - 2011 年),以及所遵循的 Apache 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.
-->
<resources>
// XML 资源标签的开始,用于定义一系列的 Android
应用资源比如样式styles、尺寸dimens、颜色colors等各种资源都会在这个标签内部进行定义。
<style name="TextAppearanceSuper">
<item name="android:textSize">@dimen/text_font_size_super</item>
<item name="android:textColorLink">#0000ff</item>
</style>
// 定义了一个名为"TextAppearanceSuper"的样式资源。
// 其中包含两个子项(<item>
// 第一个子项通过"@dimen/text_font_size_super"设置了文本的字号大小,这里引用了名为"text_font_size_super"的尺寸资源(通常在
dimens.xml 文件中定义具体数值)来确定实际字号大小;
// 第二个子项将链接文本的颜色设置为蓝色(十六进制颜色码 #0000ff用于指定当文本作为链接显示时的颜色样式。
<style name="TextAppearanceLarge">
<item name="android:textSize">@dimen/text_font_size_large</item>
<item name="android:textColorLink">#0000ff</item>
</style>
// 定义名为"TextAppearanceLarge"的样式资源。
// 同样包含两个子项:
// 第一个子项利用"@dimen/text_font_size_large"来设置文本字号,引用对应的尺寸资源确定大小;
// 第二个子项也是把链接文本颜色设为蓝色(#0000ff与上面类似规定了链接文本颜色的显示样式。
<style name="TextAppearanceMedium">
<item name="android:textSize">@dimen/text_font_size_medium</item>
<item name="android:textColorLink">#0000ff</item>
</style>
// 定义"TextAppearanceMedium"样式资源。
// 包含两个子项,分别通过引用"text_font_size_medium"尺寸资源设置文本字号以及将链接文本颜色设为蓝色(#0000ff用于特定的文本显示样式设定。
<style name="TextAppearanceNormal">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColorLink">#0000ff</item>
</style>
// 定义"TextAppearanceNormal"样式资源。
// 其两个子项中,一个借助"text_font_size_normal"尺寸资源来规定文本字号大小,另一个将链接文本颜色设定为蓝色(#0000ff以定义相应的文本外观样式。
<style name="TextAppearancePrimaryItem">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColor">@color/primary_text_dark</item>
</style>
// 定义名为"TextAppearancePrimaryItem"的样式资源。
// 有两个子项:
// 第一个子项根据"text_font_size_normal"尺寸资源确定文本字号大小;
// 第二个子项通过引用"@color/primary_text_dark"来设置文本的颜色,这里会使用名为"primary_text_dark"的颜色资源(通常在
colors.xml 文件中定义具体颜色值)来确定文本实际显示的颜色,用于特定主要项目文本的外观样式定义。
<style name="TextAppearanceSecondaryItem">
<item name="android:textSize">@dimen/text_font_size_small</item>
<item name="android:textColor">@color/secondary_text_dark</item>
</style>
// 定义"TextAppearanceSecondaryItem"样式资源。
// 包含两个子项:
// 第一个子项按照"text_font_size_small"尺寸资源设置文本字号,使其呈现较小的字号样式;
// 第二个子项引用"@color/secondary_text_dark"颜色资源来设定文本颜色,用于特定次要项目文本的外观样式定义,比如一些辅助说明性文字等。
<style name="TextAppearanceUnderMenuIcon">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColor">@android:color/black</item>
</style>
// 定义"TextAppearanceUnderMenuIcon"样式资源。
// 它的两个子项中,一个依据"text_font_size_normal"尺寸资源确定文本字号大小保持正常字号;
// 另一个直接使用 Android 系统内置的黑色(@android:color/black来设置文本颜色用于在菜单图标下方等相关位置文本的外观样式设定。
<style name="HighlightTextAppearancePrimary">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColor">@color/primary_text_dark</item>
</style>
// 定义"HighlightTextAppearancePrimary"样式资源。
//
同样有两个子项,分别通过"text_font_size_normal"尺寸资源确定文本字号以及引用"@color/primary_text_dark"颜色资源设置文本颜色,用于特定主要内容的突出显示文本(比如高亮显示的主要文本)的外观样式定义。
<style name="HighlightTextAppearanceSecondary">
<item name="android:textSize">@dimen/text_font_size_small</item>
<item name="android:textColor">@color/secondary_text_dark</item>
</style>
// 定义"HighlightTextAppearanceSecondary"样式资源。
//
其两个子项分别按照"text_font_size_small"尺寸资源设置较小的文本字号,并通过引用"@color/secondary_text_dark"颜色资源确定文本颜色,用于次要内容的突出显示文本(比如高亮显示的次要文本)的外观样式定义。
<style name="NoteTheme" parent="@android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">@style/NoteActionBarStyle</item>
</style>
// 定义名为"NoteTheme"的主题样式资源,它继承自 Android
系统内置的"@android:style/Theme.Holo.Light"主题样式(即基于该主题样式进行扩展和定制)。
//
其中包含一个子项,通过"@style/NoteActionBarStyle"来设置该主题下的ActionBar操作栏的样式将其关联到名为"NoteActionBarStyle"的自定义样式资源上,用于整体主题中操作栏样式的定制设定。
<style name="NoteActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid">
<item name="android:displayOptions" />
<item name="android:visibility">gone</item>
</style>
// 定义名为"NoteActionBarStyle"的样式资源,它继承自 Android
系统内置的"@android:style/Widget.Holo.Light.ActionBar.Solid"样式(在继承基础上做进一步修改)。
// 包含两个子项:
//
第一个子项对"android:displayOptions"属性进行了设置这里虽然没有具体值但可能会在后续代码中根据需求动态赋值或者通过代码逻辑来处理该属性相关情况用于控制ActionBar的显示相关选项
// 第二个子项将"android:visibility"属性设置为"gone",意味着该操作栏在使用这个样式时将被隐藏,不显示在界面上,用于定制操作栏的显示状态。
</resources>// XML 资源标签的结束,表示资源定义部分的结束。
</resources>

@ -2,19 +2,14 @@
buildscript {
repositories {
jcenter()
google()
mavenCentral()
}
dependencies {
//classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.android.tools.build:gradle:2.3.2'
}
}
allprojects {
repositories {
jcenter()
google()
mavenCentral()
}
}

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-rc-1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

@ -1 +0,0 @@
Subproject commit 794f72546dfb5dcfb791a421deb77b15f6a1e53f
Loading…
Cancel
Save