diff --git a/.gitignore b/.gitignore index 7df8dff..bc32818 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ project.properties .settings/ .classpath .project +/.idea/ diff --git a/doc/小米便签开源代码的泛读报告.docx b/doc/小米便签开源代码的泛读报告.docx index 379d40e..b0a26fb 100644 Binary files a/doc/小米便签开源代码的泛读报告.docx and b/doc/小米便签开源代码的泛读报告.docx differ diff --git a/doc/小米便签开源代码的泛读报告改版.docx b/doc/小米便签开源代码的泛读报告改版.docx deleted file mode 100644 index 379d40e..0000000 Binary files a/doc/小米便签开源代码的泛读报告改版.docx and /dev/null differ diff --git a/doc/小米便签开源代码的质量分析报告.docx b/doc/小米便签开源代码的质量分析报告.docx index 10d1ead..3db82a1 100644 Binary files a/doc/小米便签开源代码的质量分析报告.docx and b/doc/小米便签开源代码的质量分析报告.docx differ diff --git a/doc/小米便签开源代码的质量分析报告改版.docx b/doc/小米便签开源代码的质量分析报告改版.docx deleted file mode 100644 index 10d1ead..0000000 Binary files a/doc/小米便签开源代码的质量分析报告改版.docx and /dev/null differ diff --git a/src/net/micode/notes/model/Note.java b/src/net/micode/notes/model/Note.java index f4f5021..6706cf6 100644 --- a/src/net/micode/notes/model/Note.java +++ b/src/net/micode/notes/model/Note.java @@ -1,21 +1,43 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.micode.notes.model; - -import android.content.ContentProviderOperation;//批量的更新、插入、删除数据。 -import android.content.ContentProviderResult;//操作的结果 -import android.content.ContentUris;//用于添加和获取Uri后面的ID -import android.content.ContentValues;//一种用来存储基本数据类型数据的存储机制 -import android.content.Context;//需要用该类来弄清楚调用者的实例 -import android.content.OperationApplicationException;//操作应用程序容错 -import android.net.Uri;//表示待操作的数据 -import android.os.RemoteException;//远程容错 -import android.util.Log;//输出日志,比如说出错、警告等 - +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.OperationApplicationException; +import android.net.Uri; +import android.os.RemoteException; +import android.util.Log; + +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.CallNote; +import net.micode.notes.data.Notes.DataColumns; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.data.Notes.TextNote; + +import java.util.ArrayList; + + public class Note { - // private ContentValues mNoteDiffValues; - ContentValues mNoteDiffValues;// + private ContentValues mNoteDiffValues; private NoteData mNoteData; private static final String TAG = "Note"; - /** * Create a new note id for adding a new note to databases */ @@ -27,67 +49,66 @@ public class Note { values.put(NoteColumns.MODIFIED_DATE, createdTime); values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); values.put(NoteColumns.LOCAL_MODIFIED, 1); - values.put(NoteColumns.PARENT_ID, folderId);//将数据写入数据库表格 + values.put(NoteColumns.PARENT_ID, folderId); Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); - //ContentResolver()主要是实现外部应用对ContentProvider中的数据 - //进行添加、删除、修改和查询操作 + long noteId = 0; try { noteId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { Log.e(TAG, "Get note id error :" + e.toString()); noteId = 0; - }//try-catch异常处理 + } if (noteId == -1) { throw new IllegalStateException("Wrong note id:" + noteId); } return noteId; } - + public Note() { mNoteDiffValues = new ContentValues(); mNoteData = new NoteData(); - }//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容 - + } + public void setNoteValue(String key, String value) { mNoteDiffValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); - }//设置数据库表格的标签属性数据 - + } + public void setTextData(String key, String value) { mNoteData.setTextData(key, value); - }//设置数据库表格的标签文本内容的数据 - + } + public void setTextDataId(long id) { mNoteData.setTextDataId(id); - }//设置文本数据的ID - + } + public long getTextDataId() { return mNoteData.mTextDataId; - }//得到文本数据的ID - + } + public void setCallDataId(long id) { mNoteData.setCallDataId(id); - }//设置电话号码数据的ID - + } + public void setCallData(String key, String value) { mNoteData.setCallData(key, value); - }//得到电话号码数据的ID - + } + public boolean isLocalModified() { return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); - }//判断是否是本地修改 - + } + public boolean syncNote(Context context, long noteId) { if (noteId <= 0) { throw new IllegalArgumentException("Wrong note id:" + noteId); } - + if (!isLocalModified()) { return true; } - + /** * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the @@ -100,74 +121,74 @@ public class Note { // Do not return, fall through } mNoteDiffValues.clear(); - + if (mNoteData.isLocalModified() && (mNoteData.pushIntoContentResolver(context, noteId) == null)) { return false; } - + return true; - }//判断数据是否同步 - - private class NoteData {//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据 + } + + private class NoteData { private long mTextDataId; - - private ContentValues mTextDataValues;//文本数据 - + + private ContentValues mTextDataValues; + private long mCallDataId; - - private ContentValues mCallDataValues;//电话号码数据 - + + private ContentValues mCallDataValues; + private static final String TAG = "NoteData"; - + public NoteData() { mTextDataValues = new ContentValues(); mCallDataValues = new ContentValues(); mTextDataId = 0; mCallDataId = 0; } - //下面是上述几个函数的具体实现 + boolean isLocalModified() { return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; } - + void setTextDataId(long id) { if(id <= 0) { throw new IllegalArgumentException("Text data id should larger than 0"); } mTextDataId = id; } - + void setCallDataId(long id) { if (id <= 0) { throw new IllegalArgumentException("Call data id should larger than 0"); } mCallDataId = id; } - + void setCallData(String key, String value) { mCallDataValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } - + void setTextData(String key, String value) { mTextDataValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } - //下面函数的作用是将新的数据通过Uri的操作存储到数据库 + Uri pushIntoContentResolver(Context context, long noteId) { /** * Check for safety */ if (noteId <= 0) { throw new IllegalArgumentException("Wrong note id:" + noteId); - }//判断数据是否合法 - + } + ArrayList operationList = new ArrayList(); - ContentProviderOperation.Builder builder = null;//数据库的操作列表 - + ContentProviderOperation.Builder builder = null; + if(mTextDataValues.size() > 0) { mTextDataValues.put(DataColumns.NOTE_ID, noteId); if (mTextDataId == 0) { @@ -188,8 +209,8 @@ public class Note { operationList.add(builder.build()); } mTextDataValues.clear(); - }//把文本数据存入DataColumns - + } + if(mCallDataValues.size() > 0) { mCallDataValues.put(DataColumns.NOTE_ID, noteId); if (mCallDataId == 0) { @@ -210,8 +231,8 @@ public class Note { operationList.add(builder.build()); } mCallDataValues.clear(); - }//把电话号码数据存入DataColumns - + } + if (operationList.size() > 0) { try { ContentProviderResult[] results = context.getContentResolver().applyBatch( @@ -225,8 +246,8 @@ public class Note { Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); return null; } - }//存储过程中的异常处理 + } return null; } } -} \ No newline at end of file +} diff --git a/src/net/micode/notes/model/WorkingNote.java b/src/net/micode/notes/model/WorkingNote.java index f67a01f..be081e4 100644 --- a/src/net/micode/notes/model/WorkingNote.java +++ b/src/net/micode/notes/model/WorkingNote.java @@ -1,5 +1,37 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.micode.notes.model; - + +import android.appwidget.AppWidgetManager; +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.text.TextUtils; +import android.util.Log; + +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.CallNote; +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.Notes.TextNote; +import net.micode.notes.tool.ResourceParser.NoteBgResources; + + public class WorkingNote { // Note for the working note private Note mNote; @@ -9,22 +41,27 @@ public class WorkingNote { private String mContent; // Note mode private int mMode; - + private long mAlertDate; + private long mModifiedDate; + private int mBgColorId; + private int mWidgetId; + private int mWidgetType; + private long mFolderId; + private Context mContext; - + private static final String TAG = "WorkingNote"; - + private boolean mIsDeleted; - + private NoteSettingChangedListener mNoteSettingStatusListener; - - // 声明 DATA_PROJECTION字符串数组 + public static final String[] DATA_PROJECTION = new String[] { DataColumns.ID, DataColumns.CONTENT, @@ -34,8 +71,7 @@ public class WorkingNote { DataColumns.DATA3, DataColumns.DATA4, }; - - // 声明 NOTE_PROJECTION字符串数组 + public static final String[] NOTE_PROJECTION = new String[] { NoteColumns.PARENT_ID, NoteColumns.ALERTED_DATE, @@ -44,20 +80,29 @@ public class WorkingNote { NoteColumns.WIDGET_TYPE, NoteColumns.MODIFIED_DATE }; - + private static final int DATA_ID_COLUMN = 0; + private static final int DATA_CONTENT_COLUMN = 1; + private static final int DATA_MIME_TYPE_COLUMN = 2; + private static final int DATA_MODE_COLUMN = 3; + private static final int NOTE_PARENT_ID_COLUMN = 0; + private static final int NOTE_ALERTED_DATE_COLUMN = 1; + private static final int NOTE_BG_COLOR_ID_COLUMN = 2; + private static final int NOTE_WIDGET_ID_COLUMN = 3; + private static final int NOTE_WIDGET_TYPE_COLUMN = 4; + private static final int NOTE_MODIFIED_DATE_COLUMN = 5; - + // New note construct - public WorkingNote(Context context, long folderId) { + private WorkingNote(Context context, long folderId) { mContext = context; mAlertDate = 0; mModifiedDate = System.currentTimeMillis(); @@ -68,8 +113,7 @@ public class WorkingNote { mMode = 0; mWidgetType = Notes.TYPE_WIDGET_INVALIDE; } - - // WorkingNote的构造函数 + // Existing note construct private WorkingNote(Context context, long noteId, long folderId) { mContext = context; @@ -79,15 +123,12 @@ public class WorkingNote { mNote = new Note(); loadNote(); } - - // 加载Note - // 通过数据库调用query函数找到第一个条目 + private void loadNote() { Cursor cursor = mContext.getContentResolver().query( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, null, null); - - // 若存在,储存相应信息 + if (cursor != null) { if (cursor.moveToFirst()) { mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); @@ -98,24 +139,21 @@ public class WorkingNote { mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); } cursor.close(); - // 若不存在,报错 } else { Log.e(TAG, "No note with id:" + mNoteId); throw new IllegalArgumentException("Unable to find note with id " + mNoteId); } loadNoteData(); } - - // 加载NoteData + private void loadNoteData() { Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { String.valueOf(mNoteId) }, null); - + if (cursor != null) { - // 查到信息不为空 - if (cursor.moveToFirst()) { // 查看第一项是否存在 + if (cursor.moveToFirst()) { do { String type = cursor.getString(DATA_MIME_TYPE_COLUMN); if (DataConstants.NOTE.equals(type)) { @@ -127,7 +165,7 @@ public class WorkingNote { } else { Log.d(TAG, "Wrong note type with type:" + type); } - } while (cursor.moveToNext());//查阅所有项,直到为空 + } while (cursor.moveToNext()); } cursor.close(); } else { @@ -135,35 +173,31 @@ public class WorkingNote { throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); } } - - // 创建空的Note - // 传参:context,文件夹id,widget,背景颜色 + public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, int widgetType, int defaultBgColorId) { WorkingNote note = new WorkingNote(context, folderId); - // 设定相关属性 note.setBgColorId(defaultBgColorId); note.setWidgetId(widgetId); note.setWidgetType(widgetType); return note; } - + public static WorkingNote load(Context context, long id) { return new WorkingNote(context, id, 0); } - - // 保存Note + public synchronized boolean saveNote() { - if (isWorthSaving()) { //是否值得保存 - if (!existInDatabase()) { // 是否存在数据库中 + if (isWorthSaving()) { + if (!existInDatabase()) { if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { Log.e(TAG, "Create new note fail with id:" + mNoteId); return false; } } - + mNote.syncNote(mContext, mNoteId); - + /** * Update widget content if there exist any widget of this note */ @@ -177,15 +211,12 @@ public class WorkingNote { return false; } } - - // 是否在数据库中存在 + public boolean existInDatabase() { return mNoteId > 0; } - - // 是否值得保存 + private boolean isWorthSaving() { - // 被删除,或(不在数据库中 内容为空),或 本地已保存过 if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) || (existInDatabase() && !mNote.isLocalModified())) { return false; @@ -193,15 +224,11 @@ public class WorkingNote { return true; } } - - - // 设置mNoteSettingStatusListener + public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { mNoteSettingStatusListener = l; } - - // 设置AlertDate - // 若 mAlertDate与data不同,则更改mAlertDate并设定NoteValue + public void setAlertDate(long date, boolean set) { if (date != mAlertDate) { mAlertDate = date; @@ -211,21 +238,17 @@ public class WorkingNote { mNoteSettingStatusListener.onClockAlertChanged(date, set); } } - - // 设定删除标记 + public void markDeleted(boolean mark) { - // 设定标记 mIsDeleted = mark; if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onWidgetChanged(); - // 调用mNoteSettingStatusListener的 onWidgetChanged方法 } } - - // 设定背景颜色 + public void setBgColorId(int id) { - if (id != mBgColorId) { //设定条件 id != mBgColorId + if (id != mBgColorId) { mBgColorId = id; if (mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onBackgroundColorChanged(); @@ -233,11 +256,9 @@ public class WorkingNote { mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); } } - - // 设定检查列表模式 - // 参数:mode + public void setCheckListMode(int mode) { - if (mMode != mode) { //设定条件 mMode != mode + if (mMode != mode) { if (mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); } @@ -245,125 +266,98 @@ public class WorkingNote { mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); } } - - - // 设定WidgetType - // 参数:type + public void setWidgetType(int type) { - if (type != mWidgetType) {//设定条件 type != mWidgetType + if (type != mWidgetType) { mWidgetType = type; mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); - // 调用Note的setNoteValue方法更改WidgetType } } - - // 设定WidgetId - // 参数:id + public void setWidgetId(int id) { - if (id != mWidgetId) {//设定条件 id != mWidgetId + if (id != mWidgetId) { mWidgetId = id; mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); - // 调用Note的setNoteValue方法更改WidgetId } } - - // 设定WorkingTex - // 参数:更改的text + public void setWorkingText(String text) { - if (!TextUtils.equals(mContent, text)) {//设定条件 mContent, text内容不同 + if (!TextUtils.equals(mContent, text)) { mContent = text; mNote.setTextData(DataColumns.CONTENT, mContent); - // 调用Note的setTextData方法更改WorkingText } } - - // 转变mNote的CallData及CallNote信息 - // 参数:String phoneNumber, long callDate + public void convertToCallNote(String phoneNumber, long callDate) { mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); } - - // 判断是否有时钟题型 + public boolean hasClockAlert() { return (mAlertDate > 0 ? true : false); } - - // 获取Content + public String getContent() { return mContent; } - - // 获取AlertDate + public long getAlertDate() { return mAlertDate; } - - // 获取ModifiedDate + public long getModifiedDate() { return mModifiedDate; } - - // 获取背景颜色来源id + public int getBgColorResId() { return NoteBgResources.getNoteBgResource(mBgColorId); } - - // 获取背景颜色id + public int getBgColorId() { return mBgColorId; } - - // 获取标题背景颜色id + public int getTitleBgResId() { return NoteBgResources.getNoteTitleBgResource(mBgColorId); } - - // 获取CheckListMode + public int getCheckListMode() { return mMode; } - - // 获取便签id + public long getNoteId() { return mNoteId; } - - // 获取文件夹id + public long getFolderId() { return mFolderId; } - - // 获取WidgetId + public int getWidgetId() { return mWidgetId; } - - // 获取WidgetType + public int getWidgetType() { return mWidgetType; } - - // 创建接口 NoteSettingChangedListener,便签更新监视 - // 为NoteEditActivity提供接口 - // 提供函数有 - public interface NoteSettingChangedListener { + + public interface NoteSettingChangedListener { /** * Called when the background color of current note has just changed */ void onBackgroundColorChanged(); - + /** * Called when user set clock */ void onClockAlertChanged(long date, boolean set); - + /** * Call when user create note from widget */ void onWidgetChanged(); - + /** * Call when switch between check list mode and normal mode * @param oldMode is previous mode before change @@ -371,4 +365,4 @@ public class WorkingNote { */ void onCheckListModeChanged(int oldMode, int newMode); } -} \ No newline at end of file +} diff --git a/src/net/micode/notes/tool/BackupUtils.java b/src/net/micode/notes/tool/BackupUtils.java index 1b3f64e..39f6ec4 100644 --- a/src/net/micode/notes/tool/BackupUtils.java +++ b/src/net/micode/notes/tool/BackupUtils.java @@ -1,58 +1,90 @@ +/* + * 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.tool; - + +import android.content.Context; +import android.database.Cursor; +import android.os.Environment; +import android.text.TextUtils; +import android.text.format.DateFormat; +import android.util.Log; + +import net.micode.notes.R; +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 java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + + public class BackupUtils { - private static final String TAG = "BackupUtils"; + private static final String TAG = "BackupUtils"; // Singleton stuff - private static BackupUtils sInstance; //类里面为什么可以定义自身类的对象? - + private static BackupUtils sInstance; + public static synchronized BackupUtils getInstance(Context context) { - //ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A) - //运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。 - //它包括两种用法:synchronized 方法和 synchronized 块。 if (sInstance == null) { - //如果当前备份不存在,则新声明一个 sInstance = new BackupUtils(context); } return sInstance; } - + /** * Following states are signs to represents backup or restore * status */ - // Currently, the sdcard is not mounted SD卡没有被装入手机 - public static final int STATE_SD_CARD_UNMOUONTED = 0; - // The backup file not exist 备份文件夹不存在 + // Currently, the sdcard is not mounted + public static final int STATE_SD_CARD_UNMOUONTED = 0; + // The backup file not exist public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; - // The data is not well formated, may be changed by other programs 数据已被破坏,可能被修改 + // The data is not well formated, may be changed by other programs public static final int STATE_DATA_DESTROIED = 2; - // Some run-time exception which causes restore or backup fails 超时异常 + // Some run-time exception which causes restore or backup fails public static final int STATE_SYSTEM_ERROR = 3; - // Backup or restore success 成功存储 + // Backup or restore success public static final int STATE_SUCCESS = 4; - + private TextExport mTextExport; - - private BackupUtils(Context context) { //初始化函数 + + private BackupUtils(Context context) { mTextExport = new TextExport(context); } - - private static boolean externalStorageAvailable() { //外部存储功能是否可用 + + private static boolean externalStorageAvailable() { return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); } - + public int exportToText() { return mTextExport.exportToText(); } - + public String getExportedTextFileName() { return mTextExport.mFileName; } - + public String getExportedTextFileDir() { return mTextExport.mFileDirectory; } - + private static class TextExport { private static final String[] NOTE_PROJECTION = { NoteColumns.ID, @@ -60,13 +92,13 @@ public class BackupUtils { NoteColumns.SNIPPET, NoteColumns.TYPE }; - + private static final int NOTE_COLUMN_ID = 0; - + private static final int NOTE_COLUMN_MODIFIED_DATE = 1; - + private static final int NOTE_COLUMN_SNIPPET = 2; - + private static final String[] DATA_PROJECTION = { DataColumns.CONTENT, DataColumns.MIME_TYPE, @@ -75,71 +107,71 @@ public class BackupUtils { DataColumns.DATA3, DataColumns.DATA4, }; - + private static final int DATA_COLUMN_CONTENT = 0; - + private static final int DATA_COLUMN_MIME_TYPE = 1; - + private static final int DATA_COLUMN_CALL_DATE = 2; - + private static final int DATA_COLUMN_PHONE_NUMBER = 4; - + private final String [] TEXT_FORMAT; private static final int FORMAT_FOLDER_NAME = 0; private static final int FORMAT_NOTE_DATE = 1; private static final int FORMAT_NOTE_CONTENT = 2; - + private Context mContext; private String mFileName; private String mFileDirectory; - + public TextExport(Context context) { TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); mContext = context; - mFileName = ""; //为什么为空? + mFileName = ""; mFileDirectory = ""; } - - private String getFormat(int id) { //获取文本的组成部分 + + private String getFormat(int id) { return TEXT_FORMAT[id]; } - + /** * Export the folder identified by folder id to text */ - private void exportFolderToText(String folderId, PrintStream ps) { - // Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note + private void exportFolderToText(String folderId, PrintStream ps) { + // Query notes belong to this folder Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { folderId }, null); - - if (notesCursor != null) { + + if (notesCursor != null) { if (notesCursor.moveToFirst()) { do { - // Print note's last modified date ps里面保存有这份note的日期 + // Print note's last modified date ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( mContext.getString(R.string.format_datetime_mdhm), notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); // Query data belong to this note String noteId = notesCursor.getString(NOTE_COLUMN_ID); - exportNoteToText(noteId, ps); //将文件导出到text + exportNoteToText(noteId, ps); } while (notesCursor.moveToNext()); } notesCursor.close(); } } - + /** * Export note identified by id to a print stream */ - private void exportNoteToText(String noteId, PrintStream ps) { + private void exportNoteToText(String noteId, PrintStream ps) { Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { noteId }, null); - - if (dataCursor != null) { //利用光标来扫描内容,区别为callnote和note两种,靠ps.printline输出 + + if (dataCursor != null) { if (dataCursor.moveToFirst()) { do { String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); @@ -148,8 +180,8 @@ public class BackupUtils { String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER); long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); String location = dataCursor.getString(DATA_COLUMN_CONTENT); - - if (!TextUtils.isEmpty(phoneNumber)) { //判断是否为空字符 + + if (!TextUtils.isEmpty(phoneNumber)) { ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), phoneNumber)); } @@ -182,29 +214,29 @@ public class BackupUtils { Log.e(TAG, e.toString()); } } - + /** * Note will be exported as text which is user readable */ - public int exportToText() { //总函数,调用上面的exportFolder和exportNote + public int exportToText() { if (!externalStorageAvailable()) { Log.d(TAG, "Media was not mounted"); return STATE_SD_CARD_UNMOUONTED; } - + PrintStream ps = getExportToTextPrintStream(); if (ps == null) { Log.e(TAG, "get print stream error"); return STATE_SYSTEM_ERROR; } - // First export folder and its notes 导出文件夹,就是导出里面包含的便签 + // First export folder and its notes Cursor folderCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null); - + if (folderCursor != null) { if (folderCursor.moveToFirst()) { do { @@ -224,14 +256,14 @@ public class BackupUtils { } folderCursor.close(); } - - // Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出) + + // Export notes in root's folder Cursor noteCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID + "=0", null, null); - + if (noteCursor != null) { if (noteCursor.moveToFirst()) { do { @@ -246,14 +278,14 @@ public class BackupUtils { noteCursor.close(); } ps.close(); - + return STATE_SUCCESS; } - + /** * Get a print stream pointed to the file {@generateExportedTextFile} */ - private PrintStream getExportToTextPrintStream() { + private PrintStream getExportToTextPrintStream() { File file = generateFileMountedOnSDcard(mContext, R.string.file_path, R.string.file_name_txt_format); if (file == null) { @@ -265,7 +297,7 @@ public class BackupUtils { PrintStream ps = null; try { FileOutputStream fos = new FileOutputStream(file); - ps = new PrintStream(fos); //将ps输出流输出到特定的文件,目的就是导出到文件,而不是直接输出 + ps = new PrintStream(fos); } catch (FileNotFoundException e) { e.printStackTrace(); return null; @@ -276,22 +308,22 @@ public class BackupUtils { return ps; } } - + /** * Generate the text file to store imported data */ private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { StringBuilder sb = new StringBuilder(); - sb.append(Environment.getExternalStorageDirectory()); //外部(SD卡)的存储路径 - sb.append(context.getString(filePathResId)); //文件的存储路径 - File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息 + sb.append(Environment.getExternalStorageDirectory()); + sb.append(context.getString(filePathResId)); + File filedir = new File(sb.toString()); sb.append(context.getString( fileNameFormatResId, DateFormat.format(context.getString(R.string.format_date_ymd), System.currentTimeMillis()))); File file = new File(sb.toString()); - - try { //如果这些文件不存在,则新建 + + try { if (!filedir.exists()) { filedir.mkdir(); } @@ -304,9 +336,9 @@ public class BackupUtils { } catch (IOException e) { e.printStackTrace(); } -// try catch 异常处理 + return null; } } - + diff --git a/src/net/micode/notes/tool/DataUtils.java b/src/net/micode/notes/tool/DataUtils.java index df7a068..2a14982 100644 --- a/src/net/micode/notes/tool/DataUtils.java +++ b/src/net/micode/notes/tool/DataUtils.java @@ -1,8 +1,43 @@ +/* + * 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.tool; - + +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.os.RemoteException; +import android.util.Log; + +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.CallNote; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; + +import java.util.ArrayList; +import java.util.HashSet; + + public class DataUtils { public static final String TAG = "DataUtils"; - public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { //直接删除多个笔记 + public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { if (ids == null) { Log.d(TAG, "the ids is null"); return true; @@ -11,20 +46,19 @@ public class DataUtils { Log.d(TAG, "no id is in the hashset"); return true; } - - ArrayList operationList = new ArrayList(); //提供一个任务列表 + + ArrayList operationList = new ArrayList(); for (long id : ids) { if(id == Notes.ID_ROOT_FOLDER) { Log.e(TAG, "Don't delete system folder root"); continue; - } //如果发现是根文件夹,则不删除 + } ContentProviderOperation.Builder builder = ContentProviderOperation - .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //用newDelete实现删除功能 - operationList.add(builder.build()); // + .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); + operationList.add(builder.build()); } try { - ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);//主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。 - //数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行 + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); if (results == null || results.length == 0 || results[0] == null) { Log.d(TAG, "delete notes failed, ids:" + ids.toString()); return false; @@ -37,33 +71,33 @@ public class DataUtils { } return false; } - + public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { ContentValues values = new ContentValues(); values.put(NoteColumns.PARENT_ID, desFolderId); values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); values.put(NoteColumns.LOCAL_MODIFIED, 1); - resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); //对需要移动的便签进行数据更新,然后用update实现 + resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); } - + public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, long folderId) { if (ids == null) { Log.d(TAG, "the ids is null"); return true; } - + ArrayList operationList = new ArrayList(); for (long id : ids) { ContentProviderOperation.Builder builder = ContentProviderOperation - .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //通过withAppendedId方法,为该Uri加上ID + .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); builder.withValue(NoteColumns.PARENT_ID, folderId); builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); operationList.add(builder.build()); - }//将ids里包含的每一列的数据逐次加入到operationList中,等待最后的批量处理 - + } + try { - ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //applyBatch一次性处理一个操作列表 + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); if (results == null || results.length == 0 || results[0] == null) { Log.d(TAG, "delete notes failed, ids:" + ids.toString()); return false; @@ -76,7 +110,7 @@ public class DataUtils { } return false; } - + /** * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} */ @@ -85,13 +119,13 @@ public class DataUtils { new String[] { "COUNT(*)" }, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, - null); //筛选条件:源文件不为trash folder - + null); + int count = 0; if(cursor != null) { if(cursor.moveToFirst()) { try { - count = cursor.getInt(0); + count = cursor.getInt(0); } catch (IndexOutOfBoundsException e) { Log.e(TAG, "get folder count failed:" + e.toString()); } finally { @@ -100,29 +134,29 @@ public class DataUtils { } } return count; - } - + } + public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { - Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), //通过withAppendedId方法,为该Uri加上ID + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, - new String [] {String.valueOf(type)}, - null); //查询条件:type符合,且不属于垃圾文件夹 - + new String [] {String.valueOf(type)}, + null); + boolean exist = false; if (cursor != null) { - if (cursor.getCount() > 0) {//用getcount函数判断cursor是否为空 + if (cursor.getCount() > 0) { exist = true; } cursor.close(); } return exist; } - + public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, null, null, null); - + boolean exist = false; if (cursor != null) { if (cursor.getCount() > 0) { @@ -132,11 +166,11 @@ public class DataUtils { } return exist; } - + public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null, null, null, null); - + boolean exist = false; if (cursor != null) { if (cursor.getCount() > 0) { @@ -146,14 +180,13 @@ public class DataUtils { } return exist; } - + public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + " AND " + NoteColumns.SNIPPET + "=?", new String[] { name }, null); - //通过名字查询文件是否存在 boolean exist = false; if(cursor != null) { if(cursor.getCount() > 0) { @@ -163,14 +196,14 @@ public class DataUtils { } return exist; } - + public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) { Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, NoteColumns.PARENT_ID + "=?", new String[] { String.valueOf(folderId) }, - null); //查询条件:父ID是传入的folderId; - + null); + HashSet set = null; if (c != null) { if (c.moveToFirst()) { @@ -178,26 +211,26 @@ public class DataUtils { do { try { AppWidgetAttribute widget = new AppWidgetAttribute(); - widget.widgetId = c.getInt(0); //0对应的NoteColumns.WIDGET_ID - widget.widgetType = c.getInt(1); //1对应的NoteColumns.WIDGET_TYPE + widget.widgetId = c.getInt(0); + widget.widgetType = c.getInt(1); set.add(widget); } catch (IndexOutOfBoundsException e) { Log.e(TAG, e.toString()); } - } while (c.moveToNext()); //查询下一条 + } while (c.moveToNext()); } c.close(); } return set; } - + public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.PHONE_NUMBER }, CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, null); - + if (cursor != null && cursor.moveToFirst()) { try { return cursor.getString(0); @@ -209,7 +242,7 @@ public class DataUtils { } return ""; } - + public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.NOTE_ID }, @@ -217,12 +250,11 @@ public class DataUtils { + CallNote.PHONE_NUMBER + ",?)", new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, null); - //通过数据库操作,查询条件是(callDate和phoneNumber匹配传入参数的值) - + if (cursor != null) { if (cursor.moveToFirst()) { try { - return cursor.getLong(0); //0对应的CallNote.NOTE_ID + return cursor.getLong(0); } catch (IndexOutOfBoundsException e) { Log.e(TAG, "Get call note id fails " + e.toString()); } @@ -231,14 +263,14 @@ public class DataUtils { } return 0; } - + public static String getSnippetById(ContentResolver resolver, long noteId) { Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, new String [] { NoteColumns.SNIPPET }, NoteColumns.ID + "=?", new String [] { String.valueOf(noteId)}, - null);//查询条件:noteId - + null); + if (cursor != null) { String snippet = ""; if (cursor.moveToFirst()) { @@ -249,7 +281,8 @@ public class DataUtils { } throw new IllegalArgumentException("Note is not found with id: " + noteId); } - public static String getFormattedSnippet(String snippet) { //对字符串进行格式处理,将字符串两头的空格去掉,同时将换行符去掉 + + public static String getFormattedSnippet(String snippet) { if (snippet != null) { snippet = snippet.trim(); int index = snippet.indexOf('\n'); @@ -259,5 +292,4 @@ public class DataUtils { } return snippet; } - -} \ No newline at end of file +} diff --git a/src/net/micode/notes/tool/GTaskStringUtils.java b/src/net/micode/notes/tool/GTaskStringUtils.java index 75c0739..666b729 100644 --- a/src/net/micode/notes/tool/GTaskStringUtils.java +++ b/src/net/micode/notes/tool/GTaskStringUtils.java @@ -1,99 +1,113 @@ -//简介:定义了很多的静态字符串,目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面,这是非常好的编程规范 +/* + * 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.tool; - -//这个类就是定义了一堆static string,实际就是为jsonObject提供Key,把这些定义全部写到一个类里,方便查看管理,是一个非常好的编程习惯 -public class GTaskStringUtils { - + +public class GTaskStringUtils { + public final static String GTASK_JSON_ACTION_ID = "action_id"; - + public final static String GTASK_JSON_ACTION_LIST = "action_list"; - + public final static String GTASK_JSON_ACTION_TYPE = "action_type"; - + public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; - + public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; - + public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; - + public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; - + public final static String GTASK_JSON_CREATOR_ID = "creator_id"; - + public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; - + public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; - + public final static String GTASK_JSON_COMPLETED = "completed"; - + public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; - + public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; - + public final static String GTASK_JSON_DELETED = "deleted"; - + public final static String GTASK_JSON_DEST_LIST = "dest_list"; - + public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; - + public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; - + public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; - + public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; - + public final static String GTASK_JSON_GET_DELETED = "get_deleted"; - + public final static String GTASK_JSON_ID = "id"; - + public final static String GTASK_JSON_INDEX = "index"; - + public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; - + public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; - + public final static String GTASK_JSON_LIST_ID = "list_id"; - + public final static String GTASK_JSON_LISTS = "lists"; - + public final static String GTASK_JSON_NAME = "name"; - + public final static String GTASK_JSON_NEW_ID = "new_id"; - + public final static String GTASK_JSON_NOTES = "notes"; - + public final static String GTASK_JSON_PARENT_ID = "parent_id"; - + public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; - + public final static String GTASK_JSON_RESULTS = "results"; - + public final static String GTASK_JSON_SOURCE_LIST = "source_list"; - + public final static String GTASK_JSON_TASKS = "tasks"; - + public final static String GTASK_JSON_TYPE = "type"; - + public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; - + public final static String GTASK_JSON_TYPE_TASK = "TASK"; - + public final static String GTASK_JSON_USER = "user"; - + public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; - + public final static String FOLDER_DEFAULT = "Default"; - + public final static String FOLDER_CALL_NOTE = "Call_Note"; - + public final static String FOLDER_META = "METADATA"; - + public final static String META_HEAD_GTASK_ID = "meta_gid"; - + public final static String META_HEAD_NOTE = "meta_note"; - + public final static String META_HEAD_DATA = "meta_data"; - + public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; - -} \ No newline at end of file + +} diff --git a/src/net/micode/notes/tool/ResourceParser.java b/src/net/micode/notes/tool/ResourceParser.java index 15f5a9e..1ad3ad6 100644 --- a/src/net/micode/notes/tool/ResourceParser.java +++ b/src/net/micode/notes/tool/ResourceParser.java @@ -1,35 +1,44 @@ -package net.micode.notes.tool;/*简介:字面意义是资源分析器,实际上就是获取资源并且在程序中使用,比如颜色图片等 - * 实现方法:主要利用R.java这个类,其中包括 - * R.id 组件资源引用 - * R.drawable 图片资源 (被使用) - * R.layout 布局资源 - * R.menu 菜单资源 - * R.String 文字资源 - * R.style 主题资源 (被使用) - * 在按顺序设置好相应的id后,就可以编写简单的getXXX函数获取需要的资源 - * - * 特殊的变量 : - * @BG_DEFAULT_COLOR 默认背景颜色(黄) - * BG_DEFAULT_FONT_SIZE 默认文本大小(中) +/* + * 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.tool; + +import android.content.Context; +import android.preference.PreferenceManager; + +import net.micode.notes.R; +import net.micode.notes.ui.NotesPreferenceActivity; + public class ResourceParser { - + public static final int YELLOW = 0; public static final int BLUE = 1; public static final int WHITE = 2; public static final int GREEN = 3; public static final int RED = 4; - + public static final int BG_DEFAULT_COLOR = YELLOW; - + public static final int TEXT_SMALL = 0; public static final int TEXT_MEDIUM = 1; public static final int TEXT_LARGE = 2; public static final int TEXT_SUPER = 3; - + public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; - + public static class NoteBgResources { private final static int [] BG_EDIT_RESOURCES = new int [] { R.drawable.edit_yellow, @@ -38,7 +47,7 @@ public class ResourceParser { R.drawable.edit_green, R.drawable.edit_red }; - + private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] { R.drawable.edit_title_yellow, R.drawable.edit_title_blue, @@ -46,17 +55,17 @@ public class ResourceParser { R.drawable.edit_title_green, R.drawable.edit_title_red }; - + public static int getNoteBgResource(int id) { return BG_EDIT_RESOURCES[id]; } - + public static int getNoteTitleBgResource(int id) { return BG_EDIT_TITLE_RESOURCES[id]; } } - //直接获取默认的背景颜色。看不太懂,这个PREFERENCE_SET_BG_COLOR_KEY是个final string,也就是说getBoolean肯定执行else,为什么要这么写 - public static int getDefaultBgId(Context context) { + + public static int getDefaultBgId(Context context) { if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length); @@ -64,7 +73,7 @@ public class ResourceParser { return BG_DEFAULT_COLOR; } } - + public static class NoteItemBgResources { private final static int [] BG_FIRST_RESOURCES = new int [] { R.drawable.list_yellow_up, @@ -73,7 +82,7 @@ public class ResourceParser { R.drawable.list_green_up, R.drawable.list_red_up }; - + private final static int [] BG_NORMAL_RESOURCES = new int [] { R.drawable.list_yellow_middle, R.drawable.list_blue_middle, @@ -81,7 +90,7 @@ public class ResourceParser { R.drawable.list_green_middle, R.drawable.list_red_middle }; - + private final static int [] BG_LAST_RESOURCES = new int [] { R.drawable.list_yellow_down, R.drawable.list_blue_down, @@ -89,7 +98,7 @@ public class ResourceParser { R.drawable.list_green_down, R.drawable.list_red_down, }; - + private final static int [] BG_SINGLE_RESOURCES = new int [] { R.drawable.list_yellow_single, R.drawable.list_blue_single, @@ -97,28 +106,28 @@ public class ResourceParser { R.drawable.list_green_single, R.drawable.list_red_single }; - + public static int getNoteBgFirstRes(int id) { return BG_FIRST_RESOURCES[id]; } - + public static int getNoteBgLastRes(int id) { return BG_LAST_RESOURCES[id]; } - + public static int getNoteBgSingleRes(int id) { return BG_SINGLE_RESOURCES[id]; } - + public static int getNoteBgNormalRes(int id) { return BG_NORMAL_RESOURCES[id]; } - + public static int getFolderBgRes() { return R.drawable.list_folder; } } - + public static class WidgetBgResources { private final static int [] BG_2X_RESOURCES = new int [] { R.drawable.widget_2x_yellow, @@ -127,11 +136,11 @@ public class ResourceParser { R.drawable.widget_2x_green, R.drawable.widget_2x_red, }; - + public static int getWidget2xBgResource(int id) { return BG_2X_RESOURCES[id]; } - + private final static int [] BG_4X_RESOURCES = new int [] { R.drawable.widget_4x_yellow, R.drawable.widget_4x_blue, @@ -139,12 +148,12 @@ public class ResourceParser { R.drawable.widget_4x_green, R.drawable.widget_4x_red }; - + public static int getWidget4xBgResource(int id) { return BG_4X_RESOURCES[id]; } } - + public static class TextAppearanceResources { private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { R.style.TextAppearanceNormal, @@ -152,8 +161,7 @@ public class ResourceParser { R.style.TextAppearanceLarge, R.style.TextAppearanceSuper }; - - //这里有一个容错的函数,防止输入的id大于资源总量,若如此,则自动返回默认的设置结果 + public static int getTexAppearanceResource(int id) { /** * HACKME: Fix bug of store the resource id in shared preference. @@ -165,9 +173,9 @@ public class ResourceParser { } return TEXTAPPEARANCE_RESOURCES[id]; } - + public static int getResourcesSize() { return TEXTAPPEARANCE_RESOURCES.length; } } -} \ No newline at end of file +} diff --git a/src/net/micode/notes/ui/AlarmAlertActivity.java b/src/net/micode/notes/ui/AlarmAlertActivity.java index 39e92ad..85723be 100644 --- a/src/net/micode/notes/ui/AlarmAlertActivity.java +++ b/src/net/micode/notes/ui/AlarmAlertActivity.java @@ -14,138 +14,145 @@ * limitations under the License. */ -package net.micode.notes.ui; // 定义了该类的包路径 - -import android.app.Activity; // 导入Activity类,用于创建Android活动 -import android.app.AlertDialog; // 导入AlertDialog类,用于创建对话框 -import android.content.Context; // 导入Context类,用于获取应用程序环境 -import android.content.DialogInterface; // 导入DialogInterface类,用于处理对话框事件 -import android.content.DialogInterface.OnClickListener; // 导入OnClickListener接口,用于处理对话框按钮点击事件 -import android.content.DialogInterface.OnDismissListener; // 导入OnDismissListener接口,用于处理对话框关闭事件 -import android.content.Intent; // 导入Intent类,用于启动活动和传递数据 -import android.media.AudioManager; // 导入AudioManager类,用于管理音频设置 -import android.media.MediaPlayer; // 导入MediaPlayer类,用于播放音频 -import android.media.RingtoneManager; // 导入RingtoneManager类,用于获取铃声 -import android.net.Uri; // 导入Uri类,用于表示资源路径 -import android.os.Bundle; // 导入Bundle类,用于保存活动状态 -import android.os.PowerManager; // 导入PowerManager类,用于管理电源设置 -import android.provider.Settings; // 导入Settings类,用于获取系统设置 -import android.view.Window; // 导入Window类,用于管理窗口 -import android.view.WindowManager; // 导入WindowManager类,用于管理窗口标志 - -import net.micode.notes.R; // 导入应用内部定义的资源类 -import net.micode.notes.data.Notes; // 导入应用内部定义的笔记数据类 -import net.micode.notes.tool.DataUtils; // 导入应用内部定义的数据工具类 - -import java.io.IOException; // 导入IOException类,用于处理输入输出异常 - -public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { // 定义AlarmAlertActivity类,继承自Activity,并实现OnClickListener和OnDismissListener接口 - private long mNoteId; // 定义笔记的ID - private String mSnippet; // 定义笔记内容的简短预览 - private static final int SNIPPET_PREW_MAX_LEN = 60; // 定义预览文本的最大长度 - private MediaPlayer mPlayer; // 定义用于播放提醒声音的MediaPlayer对象 - +package net.micode.notes.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.DialogInterface.OnDismissListener; +import android.content.Intent; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.PowerManager; +import android.provider.Settings; +import android.view.Window; +import android.view.WindowManager; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.DataUtils; + +import java.io.IOException; + + +public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { + private long mNoteId; + private String mSnippet; + private static final int SNIPPET_PREW_MAX_LEN = 60; + MediaPlayer mPlayer; + @Override - protected void onCreate(Bundle savedInstanceState) { // 重写onCreate方法,在活动创建时调用 - super.onCreate(savedInstanceState); // 调用父类的onCreate方法 - requestWindowFeature(Window.FEATURE_NO_TITLE); // 请求无标题的窗口 - - final Window win = getWindow(); // 获取当前窗口 - win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); // 设置窗口在锁屏时显示 - if (!isScreenOn()) { // 检查屏幕是否处于打开状态 - win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON // 保持屏幕唤醒 - | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON // 打开屏幕 - | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON // 允许在屏幕打开时锁定 - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); // 布局插入装饰 + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + + final Window win = getWindow(); + win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + + if (!isScreenOn()) { + win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); } - - Intent intent = getIntent(); // 获取启动该活动的意图 + + Intent intent = getIntent(); + try { - mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); // 从意图中获取笔记ID - mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); // 获取笔记内容的简短预览 - mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, // 如果预览文本长度超过最大长度,则截取 + mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); + mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); + mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) - : mSnippet; // 否则使用原始预览文本 - } catch (IllegalArgumentException e) { // 捕获非法参数异常 - e.printStackTrace(); // 打印异常信息 - return; // 返回 + : mSnippet; + } catch (IllegalArgumentException e) { + e.printStackTrace(); + return; } - - mPlayer = new MediaPlayer(); // 创建MediaPlayer对象 - if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { // 检查笔记在数据库中是否可见 - showActionDialog(); // 显示动作对话框 - playAlarmSound(); // 播放提醒声音 + + mPlayer = new MediaPlayer(); + if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { + showActionDialog(); + playAlarmSound(); } else { - finish(); // 结束活动 + finish(); } } - - private boolean isScreenOn() { // 定义检查屏幕是否处于打开状态的方法 - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); // 获取电源管理服务 - return pm.isScreenOn(); // 返回屏幕是否处于打开状态 + + private boolean isScreenOn() { + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + return pm.isScreenOn(); } - - private void playAlarmSound() { // 定义播放提醒声音的方法 - Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); // 获取默认的闹钟铃声URI - - int silentModeStreams = Settings.System.getInt(getContentResolver(), // 获取静音模式下影响的音频流 + + private void playAlarmSound() { + Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); + + int silentModeStreams = Settings.System.getInt(getContentResolver(), Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); - - if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { // 检查闹钟音频流是否受静音模式影响 - mPlayer.setAudioStreamType(silentModeStreams); // 设置音频流类型 + + if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { + mPlayer.setAudioStreamType(silentModeStreams); } else { - mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); // 设置音频流类型为闹钟 + mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); } try { - mPlayer.setDataSource(this, url); // 设置数据源 - mPlayer.prepare(); // 准备播放 - mPlayer.setLooping(true); // 设置循环播放 - mPlayer.start(); // 开始播放 - } catch (IllegalArgumentException e) { // 捕获非法参数异常 - e.printStackTrace(); // 打印异常信息 - } catch (SecurityException e) { // 捕获安全异常 - e.printStackTrace(); // 打印异常信息 - } catch (IllegalStateException e) { // 捕获非法状态异常 - e.printStackTrace(); // 打印异常信息 - } catch (IOException e) { // 捕获输入输出异常 - e.printStackTrace(); // 打印异常信息 + mPlayer.setDataSource(this, url); + mPlayer.prepare(); + mPlayer.setLooping(true); + mPlayer.start(); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } - - private void showActionDialog() { // 定义显示动作对话框的方法 - AlertDialog.Builder dialog = new AlertDialog.Builder(this); // 创建对话框构建器 - dialog.setTitle(R.string.app_name); // 设置对话框标题 - dialog.setMessage(mSnippet); // 设置对话框消息 - dialog.setPositiveButton(R.string.notealert_ok, this); // 设置正面按钮 - if (isScreenOn()) { // 检查屏幕是否处于打开状态 - dialog.setNegativeButton(R.string.notealert_enter, this); // 设置负面按钮 + + private void showActionDialog() { + AlertDialog.Builder dialog = new AlertDialog.Builder(this); + dialog.setTitle(R.string.app_name); + dialog.setMessage(mSnippet); + dialog.setPositiveButton(R.string.notealert_ok, this); + if (isScreenOn()) { + dialog.setNegativeButton(R.string.notealert_enter, this); } - dialog.show().setOnDismissListener(this); // 显示对话框并设置关闭监听器 + dialog.show().setOnDismissListener(this); } - - public void onClick(DialogInterface dialog, int which) { // 实现OnClickListener接口的onClick方法,处理对话框按钮点击事件 - switch (which) { // 根据按钮类型进行处理 - case DialogInterface.BUTTON_NEGATIVE: // 如果是负面按钮 - Intent intent = new Intent(this, NoteEditActivity.class); // 创建启动笔记编辑活动的意图 - intent.setAction(Intent.ACTION_VIEW); // 设置动作 - intent.putExtra(Intent.EXTRA_UID, mNoteId); // 传递笔记ID - startActivity(intent); // 启动活动 - break; // 结束处理 - default: // 默认情况 - break; // 结束处理 + + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_NEGATIVE: + Intent intent = new Intent(this, NoteEditActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.putExtra(Intent.EXTRA_UID, mNoteId); + startActivity(intent); + break; + default: + break; } } - - public void onDismiss(DialogInterface dialog) { // 实现OnDismissListener接口的onDismiss方法,处理对话框关闭事件 - stopAlarmSound(); // 停止播放提醒声音 - finish(); // 结束活动 + + public void onDismiss(DialogInterface dialog) { + stopAlarmSound(); + finish(); } - - private void stopAlarmSound() { // 定义停止播放提醒声音的方法 - if (mPlayer != null) { // 检查MediaPlayer对象是否为空 - mPlayer.stop(); // 停止播放 - mPlayer.release(); // 释放资源 - mPlayer = null; // 将MediaPlayer对象设置为空 + + private void stopAlarmSound() { + if (mPlayer != null) { + mPlayer.stop(); + mPlayer.release(); + mPlayer = null; } } -} \ No newline at end of file +} diff --git a/src/net/micode/notes/ui/AlarmInitReceiver.java b/src/net/micode/notes/ui/AlarmInitReceiver.java index b6bea24..f221202 100644 --- a/src/net/micode/notes/ui/AlarmInitReceiver.java +++ b/src/net/micode/notes/ui/AlarmInitReceiver.java @@ -14,72 +14,52 @@ * limitations under the License. */ -/* - * 该类是广播接收器,用于在应用启动时初始化提醒设置。 - * 当系统启动时,它会检查数据库中所有设置了提醒的笔记,并为每个笔记设置相应的提醒。 - */ -package net.micode.notes.ui; // 定义该类的包路径 - -import android.app.AlarmManager; // 导入AlarmManager类,用于设置提醒 -import android.app.PendingIntent; // 导入PendingIntent类,用于延迟执行意图 -import android.content.BroadcastReceiver; // 导入BroadcastReceiver类,用于接收广播 -import android.content.ContentUris; // 导入ContentUris类,用于处理URI -import android.content.Context; // 导入Context类,用于获取应用环境 -import android.content.Intent; // 导入Intent类,用于启动活动和传递数据 -import android.database.Cursor; // 导入Cursor类,用于查询数据库 - -import net.micode.notes.data.Notes; // 导入应用内部定义的笔记数据类 -import net.micode.notes.data.Notes.NoteColumns; // 导入笔记数据类的列定义 - -public class AlarmInitReceiver extends BroadcastReceiver { // 定义AlarmInitReceiver类,继承自BroadcastReceiver - - // 查询笔记时需要的列 - private static final String[] PROJECTION = new String[]{ - NoteColumns.ID, // 笔记ID - NoteColumns.ALERTED_DATE // 提醒日期 +package net.micode.notes.ui; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; + +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; + + +public class AlarmInitReceiver extends BroadcastReceiver { + + private static final String [] PROJECTION = new String [] { + NoteColumns.ID, + NoteColumns.ALERTED_DATE }; - - // 列的索引 - private static final int COLUMN_ID = 0; // ID列的索引 - private static final int COLUMN_ALERTED_DATE = 1; // 提醒日期列的索引 - - /** - * 当接收到广播时执行的操作。主要用于设置所有已记录的提醒时间。 - * - * @param context 上下文,提供访问应用全局功能的入口。 - * @param intent 携带了触发该接收器的广播信息。 - */ + + private static final int COLUMN_ID = 0; + private static final int COLUMN_ALERTED_DATE = 1; + @Override - public void onReceive(Context context, Intent intent) { // 重写onReceive方法,当接收到广播时执行 - // 获取当前日期和时间 - long currentDate = System.currentTimeMillis(); // 获取当前时间戳 - // 查询数据库中所有需要提醒的笔记 - Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, // 查询笔记内容的URI - PROJECTION, // 查询的列 - NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, // 查询条件 - new String[]{String.valueOf(currentDate)}, // 查询参数 - null); // 排序方式 - - if (c != null) { // 检查Cursor是否为空 - // 遍历查询结果,为每个需要提醒的笔记设置提醒 - if (c.moveToFirst()) { // 移动到第一行 + public void onReceive(Context context, Intent intent) { + long currentDate = System.currentTimeMillis(); + Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, + PROJECTION, + NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, + new String[] { String.valueOf(currentDate) }, + null); + + if (c != null) { + if (c.moveToFirst()) { do { - // 获取提醒日期 - long alertDate = c.getLong(COLUMN_ALERTED_DATE); // 获取提醒日期 - // 创建Intent,用于在提醒时间触发AlarmReceiver - Intent sender = new Intent(context, AlarmReceiver.class); // 创建启动AlarmReceiver的意图 - sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); // 设置意图的数据URI - // 创建PendingIntent,它是一个延迟的意图,可以在特定时间由系统触发 - PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); // 创建PendingIntent - // 获取AlarmManager服务,用于设置提醒 + long alertDate = c.getLong(COLUMN_ALERTED_DATE); + Intent sender = new Intent(context, AlarmReceiver.class); + sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); AlarmManager alermManager = (AlarmManager) context - .getSystemService(Context.ALARM_SERVICE); // 获取AlarmManager服务 - // 设置提醒 - alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); // 设置提醒时间 - } while (c.moveToNext()); // 移动到下一行 + .getSystemService(Context.ALARM_SERVICE); + alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); + } while (c.moveToNext()); } - // 关闭Cursor,释放资源 - c.close(); // 关闭Cursor + c.close(); } } -} \ No newline at end of file +} diff --git a/src/net/micode/notes/ui/AlarmReceiver.java b/src/net/micode/notes/ui/AlarmReceiver.java index bde4562..54e503b 100644 --- a/src/net/micode/notes/ui/AlarmReceiver.java +++ b/src/net/micode/notes/ui/AlarmReceiver.java @@ -14,33 +14,17 @@ * limitations under the License. */ -/* - * AlarmReceiver类 - 用于处理闹钟广播接收 - * 当接收到闹钟相关的广播时,该类会启动一个指定的Activity - * - * extends BroadcastReceiver: 继承自Android的BroadcastReceiver类 - */ -package net.micode.notes.ui; // 定义该类的包路径 - -import android.content.BroadcastReceiver; // 导入BroadcastReceiver类,用于接收广播 -import android.content.Context; // 导入Context类,用于获取应用环境 -import android.content.Intent; // 导入Intent类,用于启动活动和传递数据 - -public class AlarmReceiver extends BroadcastReceiver { // 定义AlarmReceiver类,继承自BroadcastReceiver - /* - * onReceive方法 - 系统调用的接收广播的方法 - * 当接收到广播时,该方法会被调用,然后启动AlarmAlertActivity - * - * @param context 上下文对象,提供了调用环境的信息 - * @param intent 包含广播的内容 - */ +package net.micode.notes.ui; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class AlarmReceiver extends BroadcastReceiver { @Override - public void onReceive(Context context, Intent intent) { // 重写onReceive方法,当接收到广播时执行 - // 设置Intent的类,以便启动AlarmAlertActivity - intent.setClass(context, AlarmAlertActivity.class); // 设置Intent的目标Activity为AlarmAlertActivity - // 添加标志,表示在一个新的任务中启动Activity - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 添加标志,确保Activity在一个新的任务中启动 - // 根据设置的Intent启动Activity - context.startActivity(intent); // 启动AlarmAlertActivity + public void onReceive(Context context, Intent intent) { + intent.setClass(context, AlarmAlertActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); } -} \ No newline at end of file +} diff --git a/src/net/micode/notes/ui/DateTimePicker.java b/src/net/micode/notes/ui/DateTimePicker.java index ea05271..496b0cd 100644 --- a/src/net/micode/notes/ui/DateTimePicker.java +++ b/src/net/micode/notes/ui/DateTimePicker.java @@ -14,103 +14,71 @@ * limitations under the License. */ - - package net.micode.notes.ui; - + import java.text.DateFormatSymbols; import java.util.Calendar; - + import net.micode.notes.R; - - + + import android.content.Context; import android.text.format.DateFormat; import android.view.View; import android.widget.FrameLayout; import android.widget.NumberPicker; - + public class DateTimePicker extends FrameLayout { - - // 默认启用状态 + private static final boolean DEFAULT_ENABLE_STATE = true; - - // 半天的小时数 + private static final int HOURS_IN_HALF_DAY = 12; - // 一整天的小时数 private static final int HOURS_IN_ALL_DAY = 24; - // 一周的天数 private static final int DAYS_IN_ALL_WEEK = 7; - // 日期选择器的最小值 private static final int DATE_SPINNER_MIN_VAL = 0; - // 日期选择器的最大值 private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1; - // 24小时制小时选择器的最小值 private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0; - // 24小时制小时选择器的最大值 private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23; - // 12小时制小时选择器的最小值 private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1; - // 12小时制小时选择器的最大值 private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12; - // 分钟选择器的最小值 private static final int MINUT_SPINNER_MIN_VAL = 0; - // 分钟选择器的最大值 private static final int MINUT_SPINNER_MAX_VAL = 59; - // 上下午选择器的最小值 private static final int AMPM_SPINNER_MIN_VAL = 0; - // 上下午选择器的最大值 private static final int AMPM_SPINNER_MAX_VAL = 1; - - // 日期选择器 + private final NumberPicker mDateSpinner; - // 小时选择器 private final NumberPicker mHourSpinner; - // 分钟选择器 private final NumberPicker mMinuteSpinner; - // 上下午选择器 private final NumberPicker mAmPmSpinner; - // 当前日期 private Calendar mDate; - - // 用于显示日期的字符串数组 + private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; - - // 当前是否为上午 + private boolean mIsAm; - - // 当前是否为24小时制视图 + private boolean mIs24HourView; - - // 控件是否启用 + private boolean mIsEnabled = DEFAULT_ENABLE_STATE; - - // 是否正在初始化 + private boolean mInitialising; - - // 日期时间改变监听器 + private OnDateTimeChangedListener mOnDateTimeChangedListener; - - // 日期选择器的值改变监听器 + private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - // 根据新旧值的差异更新日期 mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal); updateDateControl(); onDateTimeChanged(); } }; - - // 小时选择器的值改变监听器 + private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - // 根据小时的变化更新日期和上下午状态 boolean isDateChanged = false; Calendar cal = Calendar.getInstance(); if (!mIs24HourView) { - // 处理12小时制下的日期变化和上下午切换 if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) { cal.setTimeInMillis(mDate.getTimeInMillis()); cal.add(Calendar.DAY_OF_YEAR, 1); @@ -126,7 +94,6 @@ public class DateTimePicker extends FrameLayout { updateAmPmControl(); } } else { - // 处理24小时制下的日期变化 if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) { cal.setTimeInMillis(mDate.getTimeInMillis()); cal.add(Calendar.DAY_OF_YEAR, 1); @@ -137,11 +104,9 @@ public class DateTimePicker extends FrameLayout { isDateChanged = true; } } - // 更新小时并触发日期时间改变事件 int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY); mDate.set(Calendar.HOUR_OF_DAY, newHour); onDateTimeChanged(); - // 如果日期有变化,则更新年月日 if (isDateChanged) { setCurrentYear(cal.get(Calendar.YEAR)); setCurrentMonth(cal.get(Calendar.MONTH)); @@ -149,13 +114,10 @@ public class DateTimePicker extends FrameLayout { } } }; - - - // 分别为分钟和AM/PM选择器监听器设置匿名内部类,实现数值变化时的处理逻辑。 + private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - // 计算小时的偏移量,当从最大值变为最小值或从最小值变为最大值时调整 int minValue = mMinuteSpinner.getMinValue(); int maxValue = mMinuteSpinner.getMaxValue(); int offset = 0; @@ -164,7 +126,6 @@ public class DateTimePicker extends FrameLayout { } else if (oldVal == minValue && newVal == maxValue) { offset -= 1; } - // 根据偏移量更新日期和小时选择器,并检查是否需要切换AM/PM if (offset != 0) { mDate.add(Calendar.HOUR_OF_DAY, offset); mHourSpinner.setValue(getCurrentHour()); @@ -178,16 +139,14 @@ public class DateTimePicker extends FrameLayout { updateAmPmControl(); } } - // 更新分钟值并触发日期变化的回调 mDate.set(Calendar.MINUTE, newVal); onDateTimeChanged(); } }; - + private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - // 切换AM/PM状态,并更新日期和AM/PM选择器 mIsAm = !mIsAm; if (mIsAm) { mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY); @@ -198,238 +157,202 @@ public class DateTimePicker extends FrameLayout { onDateTimeChanged(); } }; - - // 定义日期时间变化的回调接口 + public interface OnDateTimeChangedListener { void onDateTimeChanged(DateTimePicker view, int year, int month, - int dayOfMonth, int hourOfDay, int minute); + int dayOfMonth, int hourOfDay, int minute); } - - // 构造函数:初始化日期时间选择器 + public DateTimePicker(Context context) { this(context, System.currentTimeMillis()); } - - // 构造函数:指定初始日期时间 + public DateTimePicker(Context context, long date) { this(context, date, DateFormat.is24HourFormat(context)); } - - // 构造函数:指定是否使用24小时制视图 + public DateTimePicker(Context context, long date, boolean is24HourView) { super(context); mDate = Calendar.getInstance(); mInitialising = true; mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY; inflate(context, R.layout.datetime_picker, this); - - // 初始化日期、小时、分钟和AM/PM选择器,并设置相应的监听器 + mDateSpinner = (NumberPicker) findViewById(R.id.date); mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL); mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL); mDateSpinner.setOnValueChangedListener(mOnDateChangedListener); - + mHourSpinner = (NumberPicker) findViewById(R.id.hour); mHourSpinner.setOnValueChangedListener(mOnHourChangedListener); - mMinuteSpinner = (NumberPicker) findViewById(R.id.minute); + mMinuteSpinner = (NumberPicker) findViewById(R.id.minute); mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL); mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL); mMinuteSpinner.setOnLongPressUpdateInterval(100); mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener); - + String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm); mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL); mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL); mAmPmSpinner.setDisplayedValues(stringsForAmPm); mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); - - // 更新控件至初始状态 + + // update controls to initial state updateDateControl(); updateHourControl(); updateAmPmControl(); - + set24HourView(is24HourView); - - // 设置为当前时间 + + // set to current time setCurrentDate(date); - + setEnabled(isEnabled()); - - // 设置内容描述 + + // set the content descriptions mInitialising = false; } - - - /** - * 设置控件的启用状态。 - * 如果当前状态与传入状态相同,则不进行任何操作。 - * 启用或禁用日期和时间选择器,并更新内部启用状态。 - * - * @param enabled 控件是否启用 - */ + @Override public void setEnabled(boolean enabled) { if (mIsEnabled == enabled) { return; } super.setEnabled(enabled); - // 同时启用或禁用日期和时间选择器 mDateSpinner.setEnabled(enabled); mMinuteSpinner.setEnabled(enabled); mHourSpinner.setEnabled(enabled); mAmPmSpinner.setEnabled(enabled); mIsEnabled = enabled; } - - /** - * 获取控件的启用状态。 - * - * @return 控件是否启用 - */ + @Override public boolean isEnabled() { return mIsEnabled; } - + /** - * 获取当前日期的时间戳(毫秒)。 + * Get the current date in millis * - * @return 当前日期的毫秒时间戳 + * @return the current date in millis */ public long getCurrentDateInTimeMillis() { return mDate.getTimeInMillis(); } - + /** - * 设置当前日期。 - * 根据传入的毫秒时间戳更新日期选择器的值。 + * Set the current date * * @param date The current date in millis */ public void setCurrentDate(long date) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(date); - // 通过日历实例的详细字段设置当前日期和时间 setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); } - + /** - * 设置当前日期和时间。 - * 分别设置年、月、日、时和分。 + * Set the current date * - * @param year 当前年份 - * @param month 当前月份 - * @param dayOfMonth 当前日 - * @param hourOfDay 当前小时 - * @param minute 当前分钟 + * @param year The current year + * @param month The current month + * @param dayOfMonth The current dayOfMonth + * @param hourOfDay The current hourOfDay + * @param minute The current minute */ public void setCurrentDate(int year, int month, - int dayOfMonth, int hourOfDay, int minute) { - // 分别设置年、月、日、时和分 + int dayOfMonth, int hourOfDay, int minute) { setCurrentYear(year); setCurrentMonth(month); setCurrentDay(dayOfMonth); setCurrentHour(hourOfDay); setCurrentMinute(minute); } - - + /** - * 获取当前年份 + * Get current year * - * @return 当前的年份 + * @return The current year */ public int getCurrentYear() { return mDate.get(Calendar.YEAR); } - + /** - * 设置当前年份 + * Set current year * - * @param year 当前的年份 + * @param year The current year */ public void setCurrentYear(int year) { - // 如果不是初始化状态并且设置的年份与当前年份相同,则直接返回 if (!mInitialising && year == getCurrentYear()) { return; } mDate.set(Calendar.YEAR, year); - updateDateControl(); // 更新日期控件 - onDateTimeChanged(); // 触发日期时间改变事件 + updateDateControl(); + onDateTimeChanged(); } - + /** - * 获取当前月份 + * Get current month in the year * - * @return 当前的月份(从0开始) + * @return The current month in the year */ public int getCurrentMonth() { return mDate.get(Calendar.MONTH); } - + /** - * 设置当前月份 + * Set current month in the year * - * @param month 当前的月份(从0开始) + * @param month The month in the year */ public void setCurrentMonth(int month) { - // 如果不是初始化状态并且设置的月份与当前月份相同,则直接返回 if (!mInitialising && month == getCurrentMonth()) { return; } mDate.set(Calendar.MONTH, month); - updateDateControl(); // 更新日期控件 - onDateTimeChanged(); // 触发日期时间改变事件 + updateDateControl(); + onDateTimeChanged(); } - + /** - * 获取当前日期(月中的天数) + * Get current day of the month * - * @return 当前的日期(月中的天数) + * @return The day of the month */ public int getCurrentDay() { return mDate.get(Calendar.DAY_OF_MONTH); } - + /** - * 设置当前日期(月中的天数) + * Set current day of the month * - * @param dayOfMonth 当前的日期(月中的天数) + * @param dayOfMonth The day of the month */ public void setCurrentDay(int dayOfMonth) { - // 如果不是初始化状态并且设置的日期与当前日期相同,则直接返回 if (!mInitialising && dayOfMonth == getCurrentDay()) { return; } mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); - updateDateControl(); // 更新日期控件 - onDateTimeChanged(); // 触发日期时间改变事件 + updateDateControl(); + onDateTimeChanged(); } - + /** - * 获取当前小时(24小时制),范围为(0~23) - * - * @return 当前的小时(24小时制) + * Get current hour in 24 hour mode, in the range (0~23) + * @return The current hour in 24 hour mode */ public int getCurrentHourOfDay() { return mDate.get(Calendar.HOUR_OF_DAY); } - - /** - * 获取当前小时,根据是否为24小时制返回不同的值。 - * 如果是24小时制,与{@link #getCurrentHourOfDay()}返回相同结果; - * 否则,将小时转换为12小时制,并考虑上午/下午。 - * - * @return 当前的小时(根据视图模式可能是12小时制) - */ + private int getCurrentHour() { - if (mIs24HourView) { + if (mIs24HourView){ return getCurrentHourOfDay(); } else { int hour = getCurrentHourOfDay(); - // 转换为12小时制 if (hour > HOURS_IN_HALF_DAY) { return hour - HOURS_IN_HALF_DAY; } else { @@ -437,20 +360,17 @@ public class DateTimePicker extends FrameLayout { } } } - - + /** - * 设置当前小时(24小时制),范围为(0~23) + * Set current hour in 24 hour mode, in the range (0~23) * - * @param hourOfDay 当前小时数 + * @param hourOfDay */ public void setCurrentHour(int hourOfDay) { - // 如果在初始化中或者小时未改变,则直接返回 if (!mInitialising && hourOfDay == getCurrentHourOfDay()) { return; } mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); - // 如果不是24小时视图,则调整小时数并更新AM/PM控制 if (!mIs24HourView) { if (hourOfDay >= HOURS_IN_HALF_DAY) { mIsAm = false; @@ -468,23 +388,20 @@ public class DateTimePicker extends FrameLayout { mHourSpinner.setValue(hourOfDay); onDateTimeChanged(); } - + /** - * 获取当前分钟数 + * Get currentMinute * - * @return 当前分钟数 + * @return The Current Minute */ public int getCurrentMinute() { return mDate.get(Calendar.MINUTE); } - + /** - * 设置当前分钟数 - * - * @param minute 当前分钟数值 + * Set current minute */ public void setCurrentMinute(int minute) { - // 如果在初始化中或者分钟数未改变,则直接返回 if (!mInitialising && minute == getCurrentMinute()) { return; } @@ -492,23 +409,20 @@ public class DateTimePicker extends FrameLayout { mDate.set(Calendar.MINUTE, minute); onDateTimeChanged(); } - + /** - * 获取当前是否为24小时视图 - * - * @return 如果是24小时视图返回true,否则返回false + * @return true if this is in 24 hour view else false. */ - public boolean is24HourView() { + public boolean is24HourView () { return mIs24HourView; } - + /** - * 设置当前视图为24小时制还是AM/PM制 + * Set whether in 24 hour or AM/PM mode. * - * @param is24HourView 如果为true表示24小时制,false表示AM/PM制 + * @param is24HourView True for 24 hour mode. False for AM/PM mode. */ public void set24HourView(boolean is24HourView) { - // 如果视图模式未改变,则直接返回 if (mIs24HourView == is24HourView) { return; } @@ -519,16 +433,12 @@ public class DateTimePicker extends FrameLayout { setCurrentHour(hour); updateAmPmControl(); } - - /** - * 更新日期控制组件,显示正确的日期选项 - */ + private void updateDateControl() { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(mDate.getTimeInMillis()); cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1); mDateSpinner.setDisplayedValues(null); - // 循环设置一周内每一天的显示文本 for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) { cal.add(Calendar.DAY_OF_YEAR, 1); mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal); @@ -537,10 +447,7 @@ public class DateTimePicker extends FrameLayout { mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); mDateSpinner.invalidate(); } - - /** - * 根据当前是否为24小时视图来更新AM/PM控制组件的显示和值 - */ + private void updateAmPmControl() { if (mIs24HourView) { mAmPmSpinner.setVisibility(View.GONE); @@ -550,10 +457,7 @@ public class DateTimePicker extends FrameLayout { mAmPmSpinner.setVisibility(View.VISIBLE); } } - - /** - * 根据当前是否为24小时视图来更新小时控制组件的最小值和最大值 - */ + private void updateHourControl() { if (mIs24HourView) { mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); @@ -563,19 +467,15 @@ public class DateTimePicker extends FrameLayout { mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); } } - + /** - * 设置点击“设置”按钮时的回调接口 - * - * @param callback 回调接口实例,如果为null则不执行任何操作 + * Set the callback that indicates the 'Set' button has been pressed. + * @param callback the callback, if null will do nothing */ public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) { mOnDateTimeChangedListener = callback; } - - /** - * 当日期时间被改变时调用此方法,如果设置了日期时间改变监听器,则触发监听器的回调方法 - */ + private void onDateTimeChanged() { if (mOnDateTimeChangedListener != null) { mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(), diff --git a/src/net/micode/notes/ui/DateTimePickerDialog.java b/src/net/micode/notes/ui/DateTimePickerDialog.java index 7d80830..2c47ba4 100644 --- a/src/net/micode/notes/ui/DateTimePickerDialog.java +++ b/src/net/micode/notes/ui/DateTimePickerDialog.java @@ -14,124 +14,77 @@ * limitations under the License. */ -/* - * DateTimePickerDialog类提供了一个日期和时间选择器对话框。 - * 用户可以选择一个日期和时间,然后通过监听器回调返回选择的值。 - */ -package net.micode.notes.ui; // 定义包名 - -import java.util.Calendar; // 导入Calendar类,用于处理日期和时间 - -import net.micode.notes.R; // 导入资源类,用于访问资源 -import net.micode.notes.ui.DateTimePicker; // 导入DateTimePicker类,用于日期时间选择器视图 -import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; // 导入日期时间改变监听器接口 - -import android.app.AlertDialog; // 导入AlertDialog类,用于创建对话框 -import android.content.Context; // 导入Context类,用于获取上下文 -import android.content.DialogInterface; // 导入DialogInterface类,用于处理对话框事件 -import android.content.DialogInterface.OnClickListener; // 导入OnClickListener接口,用于处理按钮点击事件 -import android.text.format.DateFormat; // 导入DateFormat类,用于日期时间格式化 -import android.text.format.DateUtils; // 导入DateUtils类,用于日期时间格式化 - -public class DateTimePickerDialog extends AlertDialog implements OnClickListener { // 定义DateTimePickerDialog类,继承自AlertDialog并实现OnClickListener接口 - - // 当前选择的日期和时间 +package net.micode.notes.ui; + +import java.util.Calendar; + +import net.micode.notes.R; +import net.micode.notes.ui.DateTimePicker; +import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.text.format.DateFormat; +import android.text.format.DateUtils; + +public class DateTimePickerDialog extends AlertDialog implements OnClickListener { + private Calendar mDate = Calendar.getInstance(); - // 用于指示日期时间选择器是否使用24小时制 private boolean mIs24HourView; - // 日期时间设置监听器,用于处理日期时间选择后的回调 private OnDateTimeSetListener mOnDateTimeSetListener; - // 日期时间选择器视图 private DateTimePicker mDateTimePicker; - - /** - * 日期时间设置监听器接口。 - * 实现此接口的类需要提供OnDateTimeSet方法来处理日期时间被设置的事件。 - */ + public interface OnDateTimeSetListener { void OnDateTimeSet(AlertDialog dialog, long date); } - - /** - * 构造函数初始化日期时间选择器对话框。 - * - * @param context 上下文对象,通常是指Activity。 - * @param date 初始显示的日期时间值。 - */ + public DateTimePickerDialog(Context context, long date) { - super(context); // 调用父类构造函数 - mDateTimePicker = new DateTimePicker(context); // 创建DateTimePicker实例 - setView(mDateTimePicker); // 设置对话框视图为DateTimePicker - // 设置日期时间改变的监听器 + super(context); + mDateTimePicker = new DateTimePicker(context); + setView(mDateTimePicker); mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { public void onDateTimeChanged(DateTimePicker view, int year, int month, - int dayOfMonth, int hourOfDay, int minute) { - // 更新内部日期时间值 + int dayOfMonth, int hourOfDay, int minute) { mDate.set(Calendar.YEAR, year); mDate.set(Calendar.MONTH, month); mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); mDate.set(Calendar.MINUTE, minute); - // 更新对话框的标题显示 updateTitle(mDate.getTimeInMillis()); } }); - mDate.setTimeInMillis(date); // 设置初始日期时间 - mDate.set(Calendar.SECOND, 0); // 设置秒数为0 - mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); // 设置DateTimePicker的当前日期时间 - // 设置对话框的确认和取消按钮 + mDate.setTimeInMillis(date); + mDate.set(Calendar.SECOND, 0); + mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); setButton(context.getString(R.string.datetime_dialog_ok), this); - setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener) null); - // 根据系统设置决定是否使用24小时制 + setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); set24HourView(DateFormat.is24HourFormat(this.getContext())); - // 更新标题以显示当前选择的日期和时间 updateTitle(mDate.getTimeInMillis()); } - - /** - * 设置日期时间选择器是否使用24小时制。 - * - * @param is24HourView 是否使用24小时制。 - */ + public void set24HourView(boolean is24HourView) { mIs24HourView = is24HourView; } - - /** - * 设置日期时间被设置时的监听器。 - * - * @param callBack 日期时间设置监听器对象。 - */ + public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { mOnDateTimeSetListener = callBack; } - - /** - * 更新对话框标题以显示当前选择的日期和时间。 - * - * @param date 当前选择的日期时间值。 - */ + private void updateTitle(long date) { - // 根据是否使用24小时制来格式化日期时间显示 int flag = - DateUtils.FORMAT_SHOW_YEAR | - DateUtils.FORMAT_SHOW_DATE | - DateUtils.FORMAT_SHOW_TIME; + DateUtils.FORMAT_SHOW_YEAR | + DateUtils.FORMAT_SHOW_DATE | + DateUtils.FORMAT_SHOW_TIME; flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); } - - /** - * 点击按钮时的处理逻辑。 - * 如果设置了日期时间设置监听器,则调用其OnDateTimeSet方法,传入当前选择的日期时间值。 - * - * @param arg0 对话框对象。 - * @param arg1 按钮标识。 - */ + public void onClick(DialogInterface arg0, int arg1) { if (mOnDateTimeSetListener != null) { mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); } } - + } \ No newline at end of file diff --git a/src/net/micode/notes/ui/DropdownMenu.java b/src/net/micode/notes/ui/DropdownMenu.java index cd8483d..613dc74 100644 --- a/src/net/micode/notes/ui/DropdownMenu.java +++ b/src/net/micode/notes/ui/DropdownMenu.java @@ -14,76 +14,48 @@ * limitations under the License. */ -/* - * DropdownMenu类用于创建和管理一个下拉菜单。 - * 该类封装了一个Button和一个PopupMenu,通过点击Button来显示下拉菜单。 - */ -package net.micode.notes.ui; // 定义包名 - -import android.content.Context; // 导入Context类,用于获取上下文 -import android.view.Menu; // 导入Menu类,用于管理菜单项 -import android.view.MenuItem; // 导入MenuItem类,用于表示菜单项 -import android.view.View; // 导入View类,用于处理视图 -import android.view.View.OnClickListener; // 导入OnClickListener接口,用于处理点击事件 -import android.widget.Button; // 导入Button类,用于创建按钮 -import android.widget.PopupMenu; // 导入PopupMenu类,用于创建弹出菜单 -import android.widget.PopupMenu.OnMenuItemClickListener; // 导入OnMenuItemClickListener接口,用于处理菜单项点击事件 - -import net.micode.notes.R; // 导入资源类,用于访问资源 - -public class DropdownMenu { // 定义DropdownMenu类 - private Button mButton; // 弹出下拉菜单的按钮 - private PopupMenu mPopupMenu; // 弹出的下拉菜单 - private Menu mMenu; // 下拉菜单的项目集合 - - /** - * DropdownMenu的构造函数。 - * - * @param context 上下文对象,通常是指Activity。 - * @param button 用于触发下拉菜单显示的按钮。 - * @param menuId 菜单资源ID,用于加载下拉菜单的项目。 - */ +package net.micode.notes.ui; + +import android.content.Context; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.PopupMenu; +import android.widget.PopupMenu.OnMenuItemClickListener; + +import net.micode.notes.R; + +public class DropdownMenu { + private Button mButton; + private PopupMenu mPopupMenu; + private Menu mMenu; + public DropdownMenu(Context context, Button button, int menuId) { - mButton = button; // 初始化按钮 - mButton.setBackgroundResource(R.drawable.dropdown_icon); // 设置按钮背景为下拉图标 - mPopupMenu = new PopupMenu(context, mButton); // 创建PopupMenu实例,锚点为按钮 - mMenu = mPopupMenu.getMenu(); // 获取菜单项的集合 - mPopupMenu.getMenuInflater().inflate(menuId, mMenu); // 加载菜单项 - // 设置按钮点击事件,点击后显示下拉菜单 + mButton = button; + mButton.setBackgroundResource(R.drawable.dropdown_icon); + mPopupMenu = new PopupMenu(context, mButton); + mMenu = mPopupMenu.getMenu(); + mPopupMenu.getMenuInflater().inflate(menuId, mMenu); mButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { - mPopupMenu.show(); // 显示下拉菜单 + mPopupMenu.show(); } }); } - - /** - * 设置下拉菜单项的点击事件监听器。 - * - * @param listener PopupMenu的OnMenuItemClickListener,用于监听菜单项的点击事件。 - */ + public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { if (mPopupMenu != null) { - mPopupMenu.setOnMenuItemClickListener(listener); // 设置菜单项点击监听器 + mPopupMenu.setOnMenuItemClickListener(listener); } } - - /** - * 根据ID查找菜单项。 - * - * @param id 菜单项的ID。 - * @return 返回找到的MenuItem对象,如果未找到则返回null。 - */ + public MenuItem findItem(int id) { - return mMenu.findItem(id); // 根据ID查找菜单项 + return mMenu.findItem(id); } - - /** - * 设置按钮的标题。 - * - * @param title 按钮要显示的标题。 - */ + public void setTitle(CharSequence title) { - mButton.setText(title); // 设置按钮显示的文本 + mButton.setText(title); } } diff --git a/src/net/micode/notes/ui/FoldersListAdapter.java b/src/net/micode/notes/ui/FoldersListAdapter.java index 9d67f3a..96b77da 100644 --- a/src/net/micode/notes/ui/FoldersListAdapter.java +++ b/src/net/micode/notes/ui/FoldersListAdapter.java @@ -14,111 +14,67 @@ * limitations under the License. */ -/* - * FoldersListAdapter 类 - * 用于管理和适配文件夹列表的适配器,继承自 CursorAdapter。 - */ - -package net.micode.notes.ui; // 定义包名 - -// 导入相关类 -import android.content.Context; // 导入Context类,用于获取上下文 -import android.database.Cursor; // 导入Cursor类,用于数据源游标 -import android.view.View; // 导入View类,用于视图 -import android.view.ViewGroup; // 导入ViewGroup类,用于视图的父容器 -import android.widget.CursorAdapter; // 导入CursorAdapter类,用于适配器 -import android.widget.LinearLayout; // 导入LinearLayout类,用于布局 -import android.widget.TextView; // 导入TextView类,用于文本显示 - -import net.micode.notes.R; // 导入资源类,用于访问资源 -import net.micode.notes.data.Notes; // 导入Notes类,用于数据操作 -import net.micode.notes.data.Notes.NoteColumns; // 导入NoteColumns类,用于数据列名 - -public class FoldersListAdapter extends CursorAdapter { // 定义FoldersListAdapter类,继承自CursorAdapter - // 查询时使用的列名数组 - public static final String[] PROJECTION = { - NoteColumns.ID, // 文件夹ID列 - NoteColumns.SNIPPET // 文件夹名称列 +package net.micode.notes.ui; + +import android.content.Context; +import android.database.Cursor; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; + + +public class FoldersListAdapter extends CursorAdapter { + public static final String [] PROJECTION = { + NoteColumns.ID, + NoteColumns.SNIPPET }; - - // 列名数组中的索引常量 - public static final int ID_COLUMN = 0; // ID列索引 - public static final int NAME_COLUMN = 1; // 名称列索引 - - /* - * 构造函数 - * @param context 上下文对象,通常指Activity或Application对象。 - * @param c 数据源游标Cursor。 - */ + + public static final int ID_COLUMN = 0; + public static final int NAME_COLUMN = 1; + public FoldersListAdapter(Context context, Cursor c) { - super(context, c); // 调用父类构造函数 + super(context, c); + // TODO Auto-generated constructor stub } - - /* - * 创建新的列表项View - * @param context 上下文对象。 - * @param cursor 当前数据项的游标。 - * @param parent 视图的父容器。 - * @return 返回新创建的列表项View。 - */ + @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return new FolderListItem(context); // 返回新的FolderListItem实例 + return new FolderListItem(context); } - - /* - * 绑定数据到已有的View上 - * @param view 要绑定数据的视图。 - * @param context 上下文对象。 - * @param cursor 当前数据项的游标。 - */ + @Override public void bindView(View view, Context context, Cursor cursor) { - if (view instanceof FolderListItem) { // 判断视图是否为FolderListItem类型 - // 根据文件夹ID判断是根文件夹还是普通文件夹,并设置文件夹名称 + if (view instanceof FolderListItem) { String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); - ((FolderListItem) view).bind(folderName); // 绑定文件夹名称到视图 + ((FolderListItem) view).bind(folderName); } } - - /* - * 根据位置获取文件夹名称 - * @param context 上下文对象。 - * @param position 列表中的位置。 - * @return 返回该位置上文件夹的名称。 - */ + public String getFolderName(Context context, int position) { - Cursor cursor = (Cursor) getItem(position); // 获取指定位置的游标 + Cursor cursor = (Cursor) getItem(position); return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context - .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); // 返回文件夹名称 + .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); } - - /* - * FolderListItem 内部类 - * 用于表示文件夹列表中的一个项的视图类。 - */ - private class FolderListItem extends LinearLayout { // 定义FolderListItem内部类,继承自LinearLayout - private TextView mName; // 文件夹名称的文本视图 - - /* - * 构造函数 - * @param context 上下文对象。 - */ + + private class FolderListItem extends LinearLayout { + private TextView mName; + public FolderListItem(Context context) { - super(context); // 调用父类构造函数 - // 加载布局文件,并将自己作为根视图 + super(context); inflate(context, R.layout.folder_list_item, this); - mName = (TextView) findViewById(R.id.tv_folder_name); // 获取文件夹名称的视图 + mName = (TextView) findViewById(R.id.tv_folder_name); } - - /* - * 绑定数据到视图上 - * @param name 要显示的文件夹名称。 - */ + public void bind(String name) { - mName.setText(name); // 设置文件夹名称 + mName.setText(name); } } - + } diff --git a/src/net/micode/notes/ui/NoteEditActivity.java b/src/net/micode/notes/ui/NoteEditActivity.java index 6e9be4f..96a9ff8 100644 --- a/src/net/micode/notes/ui/NoteEditActivity.java +++ b/src/net/micode/notes/ui/NoteEditActivity.java @@ -15,7 +15,7 @@ */ package net.micode.notes.ui; - + import android.app.Activity; import android.app.AlarmManager; import android.app.AlertDialog; @@ -51,7 +51,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; - + import net.micode.notes.R; import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.TextNote; @@ -64,168 +64,139 @@ import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener; import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener; import net.micode.notes.widget.NoteWidgetProvider_2x; import net.micode.notes.widget.NoteWidgetProvider_4x; - + import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; - - + + public class NoteEditActivity extends Activity implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener { - /** - * 头部视图的ViewHolder类,用于存储头部视图中的UI组件引用。 - */ private class HeadViewHolder { - public TextView tvModified; // 显示修改日期的文本视图 - public ImageView ivAlertIcon; // 提示图标图像视图 - public TextView tvAlertDate; // 显示提醒日期的文本视图 - public ImageView ibSetBgColor; // 设置背景颜色的图像视图 + public TextView tvModified; + + public ImageView ivAlertIcon; + + public TextView tvAlertDate; + + public ImageView ibSetBgColor; } - - /** - * 背景选择按钮与其对应选中状态图标的映射。 - */ + private static final Map sBgSelectorBtnsMap = new HashMap(); - static { - // 初始化背景选择按钮映射 sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); } - - /** - * 背景选择按钮选中状态与其对应图标的映射。 - */ + private static final Map sBgSelectorSelectionMap = new HashMap(); - static { - // 初始化背景选择按钮选中状态映射 sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select); sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); } - - /** - * 字号选择按钮与其对应字体大小的映射。 - */ + private static final Map sFontSizeBtnsMap = new HashMap(); - static { - // 初始化字号选择按钮映射 sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); } - - /** - * 字号选择按钮选中状态与其对应图标的映射。 - */ + private static final Map sFontSelectorSelectionMap = new HashMap(); - static { - // 初始化字号选择按钮选中状态映射 sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); } - - private static final String TAG = "NoteEditActivity"; // 日志标签 - - private HeadViewHolder mNoteHeaderHolder; // 头部视图的ViewHolder - - private View mHeadViewPanel; // 头部视图面板 - - private View mNoteBgColorSelector; // 笔记背景颜色选择器 - - private View mFontSizeSelector; // 字号选择器 - - private EditText mNoteEditor; // 笔记编辑器 - - private View mNoteEditorPanel; // 笔记编辑器面板 - - private WorkingNote mWorkingNote; // 当前正在编辑的笔记 - - private SharedPreferences mSharedPrefs; // 共享偏好设置 - private int mFontSizeId; // 当前选中的字体大小资源ID - - private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; // 字体大小偏好设置键 - - private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; // 快捷图标标题的最大长度 - - public static final String TAG_CHECKED = String.valueOf('\u221A'); // 标记为已检查的字符串 - public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); // 标记为未检查的字符串 - - private LinearLayout mEditTextList; // 编辑文本列表 - - private String mUserQuery; // 用户查询字符串 - private Pattern mPattern; // 正则表达式模式 - - + + private static final String TAG = "NoteEditActivity"; + + private HeadViewHolder mNoteHeaderHolder; + + private View mHeadViewPanel; + + private View mNoteBgColorSelector; + + private View mFontSizeSelector; + + private EditText mNoteEditor; + + private View mNoteEditorPanel; + + private WorkingNote mWorkingNote; + + private SharedPreferences mSharedPrefs; + private int mFontSizeId; + + private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; + + private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; + + public static final String TAG_CHECKED = String.valueOf('\u221A'); + public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); + + private LinearLayout mEditTextList; + + private String mUserQuery; + private Pattern mPattern; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - this.setContentView(R.layout.note_edit); // 设置活动的视图布局 - - // 检查实例状态是否被保存,如果未保存且初始化活动状态失败,则结束该活动 + this.setContentView(R.layout.note_edit); + if (savedInstanceState == null && !initActivityState(getIntent())) { finish(); return; } - initResources(); // 初始化资源 + initResources(); } - + /** - * 当活动被系统销毁后,为了恢复之前的状态,此方法会被调用。 - * 主要用于处理活动重新创建时的数据恢复。 - * - * @param savedInstanceState 包含之前保存状态的Bundle,如果活动之前保存了状态,这里会传入非空的Bundle。 + * Current activity may be killed when the memory is low. Once it is killed, for another time + * user load this activity, we should restore the former state */ @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); - // 检查是否有保存的状态并且包含必要的UID信息,用于恢复活动状态 if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); - // 使用intent尝试恢复活动状态,如果失败则结束该活动 if (!initActivityState(intent)) { finish(); return; } - Log.d(TAG, "Restoring from killed activity"); // 日志记录,表示活动状态正在从被杀死的状态恢复 + Log.d(TAG, "Restoring from killed activity"); } } - - - /** - * 初始化活动状态,根据传入的Intent确定是查看笔记、新建笔记还是编辑笔记。 - * - * @param intent 传入的Intent,包含了动作类型和相关数据。 - * @return boolean 返回true表示成功初始化活动状态,false表示初始化失败。 - */ + private boolean initActivityState(Intent intent) { - // 如果用户指定的是查看笔记的动作但未提供笔记ID,则跳转到笔记列表活动 + /** + * If the user specified the {@link Intent#ACTION_VIEW} but not provided with id, + * then jump to the NotesListActivity + */ mWorkingNote = null; if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); mUserQuery = ""; - - // 从搜索结果开始 + + /** + * Starting from the searched result + */ if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); } - - // 检查指定的笔记在数据库中是否可见 + if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { Intent jump = new Intent(this, NotesListActivity.class); startActivity(jump); @@ -233,7 +204,6 @@ public class NoteEditActivity extends Activity implements OnClickListener, finish(); return false; } else { - // 加载指定ID的笔记 mWorkingNote = WorkingNote.load(this, noteId); if (mWorkingNote == null) { Log.e(TAG, "load note failed with note id" + noteId); @@ -241,12 +211,11 @@ public class NoteEditActivity extends Activity implements OnClickListener, return false; } } - // 隐藏软键盘 getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - } else if (TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { - // 处理新建或编辑笔记的情况 + } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { + // New note long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); @@ -254,19 +223,17 @@ public class NoteEditActivity extends Activity implements OnClickListener, Notes.TYPE_WIDGET_INVALIDE); int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, ResourceParser.getDefaultBgId(this)); - - // 解析通话记录笔记 + + // Parse call-record note String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); if (callDate != 0 && phoneNumber != null) { - // 根据电话号码和通话日期尝试获取已有笔记ID if (TextUtils.isEmpty(phoneNumber)) { Log.w(TAG, "The call record number is null"); } long noteId = 0; if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(), phoneNumber, callDate)) > 0) { - // 加载该笔记 mWorkingNote = WorkingNote.load(this, noteId); if (mWorkingNote == null) { Log.e(TAG, "load call note failed with note id" + noteId); @@ -274,187 +241,129 @@ public class NoteEditActivity extends Activity implements OnClickListener, return false; } } else { - // 创建新的通话记录笔记 mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, bgResId); mWorkingNote.convertToCallNote(phoneNumber, callDate); } } else { - // 创建普通空笔记 mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, bgResId); } - - // 显示软键盘 + getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); } else { - // 不支持的Intent动作 Log.e(TAG, "Intent not specified action, should not support"); finish(); return false; } - // 设置笔记状态改变的监听器 mWorkingNote.setOnSettingStatusChangedListener(this); return true; } - - - /** - * 当Activity恢复到前台时调用。 - * 主要负责初始化笔记界面。 - */ + @Override protected void onResume() { super.onResume(); initNoteScreen(); } - - /** - * 初始化笔记界面的函数。 - * 该函数设置笔记编辑器的外观,根据笔记类型切换到相应的模式,设置背景和头部信息, - * 以及处理提醒头部的显示。 - */ + private void initNoteScreen() { - // 设置编辑器的文本外观 mNoteEditor.setTextAppearance(this, TextAppearanceResources .getTexAppearanceResource(mFontSizeId)); - // 根据当前笔记的类型,切换到列表模式或高亮查询结果模式 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { switchToListMode(mWorkingNote.getContent()); } else { mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); mNoteEditor.setSelection(mNoteEditor.getText().length()); } - // 隐藏所有背景选择器 for (Integer id : sBgSelectorSelectionMap.keySet()) { findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE); } - // 设置标题和编辑区域的背景 mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); - - // 设置修改时间 + mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(this, mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_YEAR)); - - // 显示提醒头部信息(当前禁用,因DateTimePicker未准备好) + + /** + * TODO: Add the menu for setting alert. Currently disable it because the DateTimePicker + * is not ready + */ showAlertHeader(); } - - /** - * 显示提醒头部信息的方法。 - * 如果当前笔记设置了提醒,该方法将根据提醒时间显示相对的时间或者过期信息。 - */ + private void showAlertHeader() { - // 处理提醒显示 if (mWorkingNote.hasClockAlert()) { long time = System.currentTimeMillis(); - // 如果提醒时间已过,显示提醒已过期的信息 if (time > mWorkingNote.getAlertDate()) { mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); } else { - // 否则,显示相对时间 mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); } - // 设置提醒视图可见 mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); } else { - // 如果没有设置提醒,隐藏提醒视图 mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); - } + }; } - - /** - * 当Activity接收到新的Intent时调用。 - * 用于根据新的Intent重新初始化Activity状态。 - * - * @param intent 新的Intent - */ + @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); initActivityState(intent); } - - /** - * 保存Activity状态时调用。 - * 用于保存当前编辑的笔记,如果该笔记还未保存到数据库,则首先保存它。 - * 并且保存当前笔记的ID到Bundle中。 - * - * @param outState 用于保存Activity状态的Bundle - */ + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - // 如果当前编辑的笔记不存在于数据库中,即还未保存,先保存它 + /** + * For new note without note id, we should firstly save it to + * generate a id. If the editing note is not worth saving, there + * is no id which is equivalent to create new note + */ if (!mWorkingNote.existInDatabase()) { saveNote(); } - // 保存笔记ID outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); } - - - /** - * 分发触摸事件。如果触摸事件不在指定视图范围内,则隐藏该视图。 - * - * @param ev 触摸事件 - * @return 如果事件被消费则返回true,否则返回false - */ + @Override public boolean dispatchTouchEvent(MotionEvent ev) { - // 如果背景颜色选择器可见且不在触摸范围内,则隐藏它并消费事件 if (mNoteBgColorSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mNoteBgColorSelector, ev)) { mNoteBgColorSelector.setVisibility(View.GONE); return true; } - - // 如果字体大小选择器可见且不在触摸范围内,则隐藏它并消费事件 + if (mFontSizeSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mFontSizeSelector, ev)) { mFontSizeSelector.setVisibility(View.GONE); return true; } - // 如果上述条件都不满足,则将事件传递给父类处理 return super.dispatchTouchEvent(ev); } - - /** - * 判断触摸点是否在指定视图范围内。 - * - * @param view 视图 - * @param ev 触摸事件 - * @return 如果触摸点在视图范围内则返回true,否则返回false - */ + private boolean inRangeOfView(View view, MotionEvent ev) { - int[] location = new int[2]; + int []location = new int[2]; view.getLocationOnScreen(location); int x = location[0]; int y = location[1]; - // 判断触摸点是否在视图外 if (ev.getX() < x || ev.getX() > (x + view.getWidth()) || ev.getY() < y || ev.getY() > (y + view.getHeight())) { - return false; - } + return false; + } return true; } - - /** - * 初始化资源,包括视图和偏好设置。 - */ + private void initResources() { - // 初始化头部视图和相关组件 mHeadViewPanel = findViewById(R.id.note_title); mNoteHeaderHolder = new HeadViewHolder(); mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); @@ -462,54 +371,43 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); - // 初始化编辑器和相关组件 mNoteEditor = (EditText) findViewById(R.id.note_edit_view); mNoteEditorPanel = findViewById(R.id.sv_note_edit); mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); - // 设置背景选择器按钮点击监听器 for (int id : sBgSelectorBtnsMap.keySet()) { ImageView iv = (ImageView) findViewById(id); iv.setOnClickListener(this); } - + mFontSizeSelector = findViewById(R.id.font_size_selector); - // 设置字体大小选择器按钮点击监听器 for (int id : sFontSizeBtnsMap.keySet()) { View view = findViewById(id); view.setOnClickListener(this); - } - ; - // 从偏好设置中读取字体大小 + }; mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE); - // 修复存储在偏好设置中的字体大小资源ID的错误 - if (mFontSizeId >= TextAppearanceResources.getResourcesSize()) { + /** + * HACKME: Fix bug of store the resource id in shared preference. + * The id may larger than the length of resources, in this case, + * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} + */ + if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; } - // 初始化编辑列表 mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); } - - /** - * 暂停时保存笔记数据并清除设置状态。 - */ + @Override protected void onPause() { super.onPause(); - // 保存笔记数据 - if (saveNote()) { + if(saveNote()) { Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); } - // 清除设置状态 clearSettingState(); } - - /** - * 更新小部件显示。 - */ + private void updateWidget() { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - // 根据小部件类型设置对应的类 if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { intent.setClass(this, NoteWidgetProvider_2x.class); } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { @@ -518,45 +416,31 @@ public class NoteEditActivity extends Activity implements OnClickListener, Log.e(TAG, "Unspported widget type"); return; } - - // 设置小部件ID - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{ - mWorkingNote.getWidgetId() + + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { + mWorkingNote.getWidgetId() }); - - // 发送广播更新小部件 + sendBroadcast(intent); - // 设置结果为OK setResult(RESULT_OK, intent); } - - - /** - * 点击事件的处理函数。 - * - * @param v 被点击的视图对象。 - */ + public void onClick(View v) { int id = v.getId(); - // 如果点击的是设置背景颜色的按钮 if (id == R.id.btn_set_bg_color) { mNoteBgColorSelector.setVisibility(View.VISIBLE); - // 根据当前笔记的背景颜色,设置对应的色板按钮可见 findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.VISIBLE); + - View.VISIBLE); } else if (sBgSelectorBtnsMap.containsKey(id)) { - // 如果点击的是背景色板上的颜色 findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.GONE); // 隐藏当前选择的背景颜色 - mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); // 更新笔记的背景颜色 - mNoteBgColorSelector.setVisibility(View.GONE); // 隐藏背景颜色选择器 + View.GONE); + mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); + mNoteBgColorSelector.setVisibility(View.GONE); } else if (sFontSizeBtnsMap.containsKey(id)) { - // 如果点击的是字体大小按钮 - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); // 隐藏当前选择的字体大小 - mFontSizeId = sFontSizeBtnsMap.get(id); // 更新选择的字体大小 - mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); // 保存选择的字体大小到SharedPreferences - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); // 设置新选择的字体大小按钮为可见 - // 根据当前笔记是否为清单模式,进行相应的文本更新 + findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); + mFontSizeId = sFontSizeBtnsMap.get(id); + mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); + findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { getWorkingText(); switchToListMode(mWorkingNote.getContent()); @@ -564,80 +448,55 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteEditor.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); } - mFontSizeSelector.setVisibility(View.GONE); // 隐藏字体大小选择器 + mFontSizeSelector.setVisibility(View.GONE); } } - - /** - * 按下返回键时的处理函数。 - */ + @Override public void onBackPressed() { - // 尝试清除设置状态,如果成功,则不执行保存笔记操作 - if (clearSettingState()) { + if(clearSettingState()) { return; } - // 保存笔记并执行父类的onBackPressed()方法(结束当前Activity) + saveNote(); super.onBackPressed(); } - - /** - * 尝试清除设置状态(背景颜色选择或字体大小选择)。 - * - * @return 如果成功清除设置状态,返回true;否则返回false。 - */ + private boolean clearSettingState() { - // 如果背景颜色选择器可见,则隐藏它并返回true if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { mNoteBgColorSelector.setVisibility(View.GONE); return true; - } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { // 如果字体大小选择器可见,则隐藏它并返回true + } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { mFontSizeSelector.setVisibility(View.GONE); return true; } - return false; // 没有可见的设置状态需要清除,返回false + return false; } - - /** - * 当背景颜色发生变化时的处理函数。 - */ + public void onBackgroundColorChanged() { - // 根据当前笔记的背景颜色,设置对应的色板按钮可见,并更新编辑器及标题栏的背景颜色 findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); } - - /** - * 准备选项菜单的函数。 - * - * @param menu 选项菜单对象。 - * @return 总是返回true。 - */ + @Override public boolean onPrepareOptionsMenu(Menu menu) { - // 如果Activity正在结束,则不进行任何操作 if (isFinishing()) { return true; } - // 尝试清除设置状态 clearSettingState(); - menu.clear(); // 清除菜单项 - // 根据笔记所属的文件夹,加载不同的菜单资源 + menu.clear(); if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { getMenuInflater().inflate(R.menu.call_note_edit, menu); } else { getMenuInflater().inflate(R.menu.note_edit, menu); } - // 根据当前笔记的清单模式,更新“清单模式”菜单项的标题 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode); } else { menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); } - // 根据笔记是否有提醒,更新“删除提醒”菜单项的可见性 if (mWorkingNote.hasClockAlert()) { menu.findItem(R.id.menu_alert).setVisible(false); } else { @@ -645,23 +504,14 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return true; } - - - /** - * 处理选项菜单项的选择事件。 - * - * @param item 选中的菜单项 - * @return 总是返回true,表示事件已处理。 - */ + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_new_note: - // 创建新笔记 createNewNote(); break; case R.id.menu_delete: - // 显示删除笔记的确认对话框 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); @@ -669,7 +519,6 @@ public class NoteEditActivity extends Activity implements OnClickListener, builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - // 确认删除当前笔记并结束当前活动 deleteCurrentNote(); finish(); } @@ -678,30 +527,24 @@ public class NoteEditActivity extends Activity implements OnClickListener, builder.show(); break; case R.id.menu_font_size: - // 显示字体大小选择器 mFontSizeSelector.setVisibility(View.VISIBLE); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); break; case R.id.menu_list_mode: - // 切换笔记的列表模式 mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ? TextNote.MODE_CHECK_LIST : 0); break; case R.id.menu_share: - // 获取当前编辑的笔记内容并分享 getWorkingText(); sendTo(this, mWorkingNote.getContent()); break; case R.id.menu_send_to_desktop: - // 将笔记发送到桌面 sendToDesktop(); break; case R.id.menu_alert: - // 设置提醒 setReminder(); break; case R.id.menu_delete_remind: - // 删除提醒设置 mWorkingNote.setAlertDate(0, false); break; default: @@ -709,26 +552,20 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return true; } - - /** - * 弹出日期时间选择器,用于设置提醒时间。 - */ + private void setReminder() { DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis()); d.setOnDateTimeSetListener(new OnDateTimeSetListener() { public void OnDateTimeSet(AlertDialog dialog, long date) { - // 用户设定时间后,设置提醒 - mWorkingNote.setAlertDate(date, true); + mWorkingNote.setAlertDate(date , true); } }); d.show(); } - + /** - * 分享笔记到支持 {@link Intent#ACTION_SEND} 操作和 {@text/plain} 类型的应用。 - * - * @param context 上下文 - * @param info 要分享的信息 + * Share note to apps that support {@link Intent#ACTION_SEND} action + * and {@text/plain} type */ private void sendTo(Context context, String info) { Intent intent = new Intent(Intent.ACTION_SEND); @@ -736,28 +573,19 @@ public class NoteEditActivity extends Activity implements OnClickListener, intent.setType("text/plain"); context.startActivity(intent); } - - /** - * 首先保存当前正在编辑的笔记,然后启动一个新的NoteEditActivity用于创建新笔记。 - */ + private void createNewNote() { - // 首先保存当前笔记 + // Firstly, save current editing notes saveNote(); - - // 安全地开始一个新的NoteEditActivity + + // For safety, start a new NoteEditActivity finish(); Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_INSERT_OR_EDIT); intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); startActivity(intent); } - - - /** - * 删除当前正在编辑的笔记。 - * 如果笔记存在于数据库中,并且当前不是同步模式,将直接删除该笔记; - * 如果处于同步模式,则将笔记移动到回收站文件夹。 - */ + private void deleteCurrentNote() { if (mWorkingNote.existInDatabase()) { HashSet ids = new HashSet(); @@ -768,12 +596,10 @@ public class NoteEditActivity extends Activity implements OnClickListener, Log.d(TAG, "Wrong note id, should not happen"); } if (!isSyncMode()) { - // 非同步模式下直接删除笔记 if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { Log.e(TAG, "Delete Note error"); } } else { - // 同步模式下将笔记移动到回收站 if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { Log.e(TAG, "Move notes to trash folder error, should not happens"); } @@ -781,27 +607,16 @@ public class NoteEditActivity extends Activity implements OnClickListener, } mWorkingNote.markDeleted(true); } - - /** - * 判断当前是否为同步模式。 - * 同步模式是指在设置中配置了同步账户名。 - * - * @return 如果配置了同步账户名返回true,否则返回false。 - */ + private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } - - /** - * 处理时钟提醒变更事件。 - * 首先检查当前笔记是否已保存,未保存则先保存。 - * 如果笔记存在,根据set参数设置或取消提醒。 - * 如果笔记不存在(即无有效ID),记录错误并提示用户输入内容。 - * - * @param date 提醒的日期时间戳 - * @param set 是否设置提醒 - */ + public void onClockAlertChanged(long date, boolean set) { + /** + * User could set clock to an unsaved note, so before setting the + * alert clock, we should save the note first + */ if (!mWorkingNote.existInDatabase()) { saveNote(); } @@ -811,45 +626,40 @@ public class NoteEditActivity extends Activity implements OnClickListener, PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); showAlertHeader(); - if (!set) { + if(!set) { alarmManager.cancel(pendingIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); } } else { + /** + * There is the condition that user has input nothing (the note is + * not worthy saving), we have no note id, remind the user that he + * should input something + */ Log.e(TAG, "Clock alert setting error"); showToast(R.string.error_note_empty_for_clock); } } - - /** - * 更新小部件显示。 - */ + public void onWidgetChanged() { updateWidget(); } - - /** - * 当删除某个编辑框中的文本时的处理逻辑。 - * 重新设置后续编辑框的索引,并将删除的文本添加到前一个或当前编辑框中。 - * - * @param index 被删除文本的编辑框索引 - * @param text 被删除的文本内容 - */ + public void onEditTextDelete(int index, String text) { int childCount = mEditTextList.getChildCount(); if (childCount == 1) { return; } - + for (int i = index + 1; i < childCount; i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) .setIndex(i - 1); } - + mEditTextList.removeViewAt(index); NoteEditText edit = null; - if (index == 0) { + if(index == 0) { edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( R.id.et_edit_text); } else { @@ -861,19 +671,15 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit.requestFocus(); edit.setSelection(length); } - - /** - * 当在编辑框中按下“Enter”键时的处理逻辑。 - * 在列表中添加一个新的编辑框,并重新设置后续编辑框的索引。 - * - * @param index 当前编辑框的索引 - * @param text 当前编辑框中的文本内容 - */ + public void onEditTextEnter(int index, String text) { - if (index > mEditTextList.getChildCount()) { + /** + * Should not happen, check for debug + */ + if(index > mEditTextList.getChildCount()) { Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); } - + View view = getListItem(text, index); mEditTextList.addView(view, index); NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); @@ -884,54 +690,31 @@ public class NoteEditActivity extends Activity implements OnClickListener, .setIndex(i); } } - - - /** - * 切换到列表模式。 - * 将文本分割成多行,并为每行创建一个列表项,展示在编辑文本列表中。 - * - * @param text 要转换成列表模式的文本,每行代表一个列表项。 - */ + private void switchToListMode(String text) { - // 清空当前的视图 mEditTextList.removeAllViews(); - // 使用换行符分割文本,创建列表项 String[] items = text.split("\n"); int index = 0; for (String item : items) { - // 忽略空行 - if (!TextUtils.isEmpty(item)) { + if(!TextUtils.isEmpty(item)) { mEditTextList.addView(getListItem(item, index)); index++; } } - // 添加一个空的列表项作为占位符 mEditTextList.addView(getListItem("", index)); - // 请求焦点以便于编辑 mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); - - // 隐藏编辑器,显示列表 + mNoteEditor.setVisibility(View.GONE); mEditTextList.setVisibility(View.VISIBLE); } - - /** - * 高亮显示查询结果。 - * 在给定的文本中,根据用户查询字符串高亮显示匹配的部分。 - * - * @param fullText 完整的文本。 - * @param userQuery 用户的查询字符串。 - * @return 包含高亮显示的文本的Spannable对象。 - */ + private Spannable getHighlightQueryResult(String fullText, String userQuery) { SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); - // 如果有查询字符串,则进行高亮处理 if (!TextUtils.isEmpty(userQuery)) { mPattern = Pattern.compile(userQuery); Matcher m = mPattern.matcher(fullText); int start = 0; while (m.find(start)) { - // 设置高亮背景 spannable.setSpan( new BackgroundColorSpan(this.getResources().getColor( R.color.user_query_highlight)), m.start(), m.end(), @@ -941,23 +724,12 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return spannable; } - - /** - * 创建列表项视图。 - * 为列表模式创建并配置一个包含文本编辑框和复选框的视图。 - * - * @param item 列表项的文本内容。 - * @param index 列表项的索引。 - * @return 配置好的列表项视图。 - */ + private View getListItem(String item, int index) { - // 加载列表项布局 View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - // 设置文本样式 edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); - // 复选框的监听器,用于切换文本的划线状态 cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { @@ -967,8 +739,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } } }); - - // 根据文本前缀设置复选框状态和文本内容 + if (item.startsWith(TAG_CHECKED)) { cb.setChecked(true); edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); @@ -978,46 +749,29 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); } - - // 设置文本变化监听和索引 + edit.setOnTextViewChangeListener(this); edit.setIndex(index); - // 设置带有查询结果高亮的文本 edit.setText(getHighlightQueryResult(item, mUserQuery)); return view; } - - /** - * 根据文本内容是否为空,切换复选框的可见性。 - * - * @param index 列表项索引。 - * @param hasText 列表项是否包含文本。 - */ + public void onTextChange(int index, boolean hasText) { if (index >= mEditTextList.getChildCount()) { Log.e(TAG, "Wrong index, should not happen"); return; } - // 根据文本内容决定复选框的可见性 - if (hasText) { + if(hasText) { mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); } else { mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE); } } - - /** - * 在切换编辑模式和列表模式时更新UI。 - * - * @param oldMode 旧的编辑模式。 - * @param newMode 新的编辑模式。 - */ + public void onCheckListModeChanged(int oldMode, int newMode) { - // 切换到列表模式 if (newMode == TextNote.MODE_CHECK_LIST) { switchToListMode(mNoteEditor.getText().toString()); } else { - // 切换回编辑模式 if (!getWorkingText()) { mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", "")); @@ -1027,12 +781,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteEditor.setVisibility(View.VISIBLE); } } - - /** - * 根据当前列表项的选中状态,构建并返回工作文本。 - * - * @return 是否有已选中的列表项。 - */ + private boolean getWorkingText() { boolean hasChecked = false; if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { @@ -1040,7 +789,6 @@ public class NoteEditActivity extends Activity implements OnClickListener, for (int i = 0; i < mEditTextList.getChildCount(); i++) { View view = mEditTextList.getChildAt(i); NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - // 构建带有选中状态前缀的文本 if (!TextUtils.isEmpty(edit.getText())) { if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); @@ -1056,35 +804,33 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return hasChecked; } - - /** - * 保存笔记。 - * 更新笔记内容并保存。 - * - * @return 是否成功保存笔记。 - */ + private boolean saveNote() { getWorkingText(); boolean saved = mWorkingNote.saveNote(); if (saved) { - // 设置结果为成功,以便外部调用者知道保存操作的状态 + /** + * There are two modes from List view to edit view, open one note, + * create/edit a node. Opening node requires to the original + * position in the list when back from edit view, while creating a + * new node requires to the top of the list. This code + * {@link #RESULT_OK} is used to identify the create/edit state + */ setResult(RESULT_OK); } return saved; } - - - /** - * 将当前编辑的笔记发送到桌面。首先会检查当前编辑的笔记是否已存在于数据库中, - * 如果不存在,则先保存。如果存在,会创建一个快捷方式放在桌面。 - */ + private void sendToDesktop() { - // 检查当前编辑的笔记是否存在于数据库,若不存在则先保存 + /** + * Before send message to home, we should make sure that current + * editing note is exists in databases. So, for new note, firstly + * save it + */ if (!mWorkingNote.existInDatabase()) { saveNote(); } - - // 如果笔记存在于数据库(有noteId),则创建快捷方式 + if (mWorkingNote.getNoteId() > 0) { Intent sender = new Intent(); Intent shortcutIntent = new Intent(this, NoteEditActivity.class); @@ -1100,42 +846,28 @@ public class NoteEditActivity extends Activity implements OnClickListener, showToast(R.string.info_note_enter_desktop); sendBroadcast(sender); } else { - // 如果用户未输入任何内容,无法创建快捷方式,提醒用户输入内容 + /** + * There is the condition that user has input nothing (the note is + * not worthy saving), we have no note id, remind the user that he + * should input something + */ Log.e(TAG, "Send to desktop error"); showToast(R.string.error_note_empty_for_send_to_desktop); } } - - /** - * 根据笔记内容生成快捷方式的标题。移除内容中的已选和未选标签,并确保标题长度不超过上限。 - * - * @param content 符合快捷方式图标标题要求的笔记内容 - * @return 标题字符串 - */ + private String makeShortcutIconTitle(String content) { content = content.replace(TAG_CHECKED, ""); content = content.replace(TAG_UNCHECKED, ""); return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, SHORTCUT_ICON_TITLE_MAX_LEN) : content; } - - /** - * 显示一个Toast消息。 - * - * @param resId 资源ID,指向要显示的字符串 - */ + private void showToast(int resId) { showToast(resId, Toast.LENGTH_SHORT); } - - /** - * 显示一个指定时长的Toast消息。 - * - * @param resId 资源ID,指向要显示的字符串 - * @param duration 显示时长,可以是Toast.LENGTH_SHORT或Toast.LENGTH_LONG - */ + private void showToast(int resId, int duration) { Toast.makeText(this, resId, duration).show(); } - } diff --git a/src/net/micode/notes/ui/NoteEditText.java b/src/net/micode/notes/ui/NoteEditText.java index 9d117a9..2afe2a8 100644 --- a/src/net/micode/notes/ui/NoteEditText.java +++ b/src/net/micode/notes/ui/NoteEditText.java @@ -14,24 +14,8 @@ * limitations under the License. */ -/* - * 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.ui; - + import android.content.Context; import android.graphics.Rect; import android.text.Layout; @@ -47,143 +31,105 @@ import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import android.view.MotionEvent; import android.widget.EditText; - + import net.micode.notes.R; - + import java.util.HashMap; import java.util.Map; - -/** - * 自定义的可编辑文本视图,支持文本变化监听、删除和新增文本事件。 - */ + public class NoteEditText extends EditText { private static final String TAG = "NoteEditText"; - private int mIndex; // 当前文本视图的索引 - private int mSelectionStartBeforeDelete; // 删除操作前的选择起始位置 - - private static final String SCHEME_TEL = "tel:"; - private static final String SCHEME_HTTP = "http:"; - private static final String SCHEME_EMAIL = "mailto:"; - - // URL方案与对应操作资源ID的映射 + private int mIndex; + private int mSelectionStartBeforeDelete; + + private static final String SCHEME_TEL = "tel:" ; + private static final String SCHEME_HTTP = "http:" ; + private static final String SCHEME_EMAIL = "mailto:" ; + private static final Map sSchemaActionResMap = new HashMap(); - static { sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web); sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); } - + /** - * 文本视图变化监听接口。 + * Call by the {@link NoteEditActivity} to delete or add edit text */ public interface OnTextViewChangeListener { /** - * 当按下删除键且文本为空时,删除当前文本视图。 + * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens + * and the text is null */ void onEditTextDelete(int index, String text); - + /** - * 当按下回车键时,新增一个文本视图。 + * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} + * happen */ void onEditTextEnter(int index, String text); - + /** - * 当文本变化时,隐藏或显示项目选项。 + * Hide or show item option when text change */ void onTextChange(int index, boolean hasText); } - + private OnTextViewChangeListener mOnTextViewChangeListener; - - /** - * 构造函数,初始化编辑文本视图。 - * - * @param context 上下文对象 - */ + public NoteEditText(Context context) { super(context, null); mIndex = 0; } - - /** - * 设置当前文本视图的索引。 - * - * @param index 当前文本视图的索引 - */ + public void setIndex(int index) { mIndex = index; } - - /** - * 设置文本视图变化监听器。 - * - * @param listener 文本视图变化监听器 - */ + public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { mOnTextViewChangeListener = listener; } - - /** - * 构造函数,初始化编辑文本视图。 - * - * @param context 上下文对象 - * @param attrs 属性集 - */ + public NoteEditText(Context context, AttributeSet attrs) { super(context, attrs, android.R.attr.editTextStyle); } - - /** - * 构造函数,初始化编辑文本视图。 - * - * @param context 上下文对象 - * @param attrs 属性集 - * @param defStyle 样式 - */ + public NoteEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + // TODO Auto-generated constructor stub } - - /** - * 处理触摸事件,调整光标位置。 - */ + @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - // 计算触摸位置相对于文本的偏移量,并调整光标位置 + int x = (int) event.getX(); int y = (int) event.getY(); x -= getTotalPaddingLeft(); y -= getTotalPaddingTop(); x += getScrollX(); y += getScrollY(); - + Layout layout = getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); Selection.setSelection(getText(), off); break; } - + return super.onTouchEvent(event); } - - /** - * 处理键盘按下事件。 - */ + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_ENTER: - // 处理回车键事件,准备新增文本视图 if (mOnTextViewChangeListener != null) { return false; } break; case KeyEvent.KEYCODE_DEL: - // 记录删除操作前的选择位置 mSelectionStartBeforeDelete = getSelectionStart(); break; default: @@ -191,15 +137,11 @@ public class NoteEditText extends EditText { } return super.onKeyDown(keyCode, event); } - - /** - * 处理键盘弹起事件。 - */ + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { + switch(keyCode) { case KeyEvent.KEYCODE_DEL: - // 处理删除键事件,若为首个文本且非空,则删除当前文本 if (mOnTextViewChangeListener != null) { if (0 == mSelectionStartBeforeDelete && mIndex != 0) { mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); @@ -210,7 +152,6 @@ public class NoteEditText extends EditText { } break; case KeyEvent.KEYCODE_ENTER: - // 处理回车键事件,新增文本视图 if (mOnTextViewChangeListener != null) { int selectionStart = getSelectionStart(); String text = getText().subSequence(selectionStart, length()).toString(); @@ -225,10 +166,7 @@ public class NoteEditText extends EditText { } return super.onKeyUp(keyCode, event); } - - /** - * 当焦点变化时,通知文本变化情况。 - */ + @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { if (mOnTextViewChangeListener != null) { @@ -240,37 +178,34 @@ public class NoteEditText extends EditText { } super.onFocusChanged(focused, direction, previouslyFocusedRect); } - - /** - * 创建上下文菜单,支持点击URL跳转。 - */ + @Override protected void onCreateContextMenu(ContextMenu menu) { if (getText() instanceof Spanned) { int selStart = getSelectionStart(); int selEnd = getSelectionEnd(); - + int min = Math.min(selStart, selEnd); int max = Math.max(selStart, selEnd); - + final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class); if (urls.length == 1) { int defaultResId = 0; - for (String schema : sSchemaActionResMap.keySet()) { - if (urls[0].getURL().indexOf(schema) >= 0) { + for(String schema: sSchemaActionResMap.keySet()) { + if(urls[0].getURL().indexOf(schema) >= 0) { defaultResId = sSchemaActionResMap.get(schema); break; } } - + if (defaultResId == 0) { defaultResId = R.string.note_link_other; } - + menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener( new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { - // 跳转到URL指向的页面 + // goto a new intent urls[0].onClick(NoteEditText.this); return true; } @@ -280,4 +215,3 @@ public class NoteEditText extends EditText { super.onCreateContextMenu(menu); } } - diff --git a/src/net/micode/notes/ui/NoteItemData.java b/src/net/micode/notes/ui/NoteItemData.java index ae57f0c..0f5a878 100644 --- a/src/net/micode/notes/ui/NoteItemData.java +++ b/src/net/micode/notes/ui/NoteItemData.java @@ -14,242 +14,211 @@ * limitations under the License. */ -package net.micode.notes.ui; // 定义包名 - -import android.content.Context; // 导入Context类,用于获取上下文 -import android.database.Cursor; // 导入Cursor类,用于数据源游标 -import android.text.TextUtils; // 导入TextUtils类,用于字符串操作 - -import net.micode.notes.data.Contact; // 导入Contact类,用于联系人数据操作 -import net.micode.notes.data.Notes; // 导入Notes类,用于笔记数据操作 -import net.micode.notes.data.Notes.NoteColumns; // 导入NoteColumns类,用于笔记数据列名 -import net.micode.notes.tool.DataUtils; // 导入DataUtils类,用于数据工具操作 - -/** - * 代表一个笔记项的数据类,用于存储和管理笔记的各种信息。 - */ -public class NoteItemData { // 定义NoteItemData类 - // 定义查询时要投影的列 - static final String[] PROJECTION = new String[]{ - NoteColumns.ID, // 笔记ID - NoteColumns.ALERTED_DATE, // 提醒日期 - NoteColumns.BG_COLOR_ID, // 背景颜色ID - NoteColumns.CREATED_DATE, // 创建日期 - NoteColumns.HAS_ATTACHMENT, // 是否有附件 - NoteColumns.MODIFIED_DATE, // 修改日期 - NoteColumns.NOTES_COUNT, // 笔记数量 - NoteColumns.PARENT_ID, // 父ID - NoteColumns.SNIPPET, // 摘要 - NoteColumns.TYPE, // 类型 - NoteColumns.WIDGET_ID, // 小部件ID - NoteColumns.WIDGET_TYPE, // 小部件类型 +package net.micode.notes.ui; + +import android.content.Context; +import android.database.Cursor; +import android.text.TextUtils; + +import net.micode.notes.data.Contact; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.tool.DataUtils; + + +public class NoteItemData { + static final String [] PROJECTION = new String [] { + NoteColumns.ID, + NoteColumns.ALERTED_DATE, + NoteColumns.BG_COLOR_ID, + NoteColumns.CREATED_DATE, + NoteColumns.HAS_ATTACHMENT, + NoteColumns.MODIFIED_DATE, + NoteColumns.NOTES_COUNT, + NoteColumns.PARENT_ID, + NoteColumns.SNIPPET, + NoteColumns.TYPE, + NoteColumns.WIDGET_ID, + NoteColumns.WIDGET_TYPE, }; - - // 各列数据的索引 - private static final int ID_COLUMN = 0; // ID列索引 - private static final int ALERTED_DATE_COLUMN = 1; // 提醒日期列索引 - private static final int BG_COLOR_ID_COLUMN = 2; // 背景颜色ID列索引 - private static final int CREATED_DATE_COLUMN = 3; // 创建日期列索引 - private static final int HAS_ATTACHMENT_COLUMN = 4; // 是否有附件列索引 - private static final int MODIFIED_DATE_COLUMN = 5; // 修改日期列索引 - private static final int NOTES_COUNT_COLUMN = 6; // 笔记数量列索引 - private static final int PARENT_ID_COLUMN = 7; // 父ID列索引 - private static final int SNIPPET_COLUMN = 8; // 摘要列索引 - private static final int TYPE_COLUMN = 9; // 类型列索引 - private static final int WIDGET_ID_COLUMN = 10; // 小部件ID列索引 - private static final int WIDGET_TYPE_COLUMN = 11; // 小部件类型列索引 - - // 笔记的各项数据 - private long mId; // 笔记ID - private long mAlertDate; // 提醒日期 - private int mBgColorId; // 背景颜色ID - private long mCreatedDate; // 创建日期 - private boolean mHasAttachment; // 是否有附件 - private long mModifiedDate; // 修改日期 - private int mNotesCount; // 笔记数量 - private long mParentId; // 父ID - private String mSnippet; // 摘要 - private int mType; // 类型 - private int mWidgetId; // 小部件ID - private int mWidgetType; // 小部件类型 - private String mName; // 联系人名称 - private String mPhoneNumber; // 电话号码 - - // 用于标识笔记在列表中的位置状态 - private boolean mIsLastItem; // 是否为最后一个项目 - private boolean mIsFirstItem; // 是否为第一个项目 - private boolean mIsOnlyOneItem; // 是否为唯一一个项目 - private boolean mIsOneNoteFollowingFolder; // 是否为一个笔记跟随文件夹 - private boolean mIsMultiNotesFollowingFolder; // 是否为多个笔记跟随文件夹 - - /** - * 根据Cursor数据构造一个NoteItemData对象。 - * - * @param context 上下文对象,用于访问应用全局功能。 - * @param cursor 包含笔记数据的Cursor对象。 - */ + + private static final int ID_COLUMN = 0; + private static final int ALERTED_DATE_COLUMN = 1; + private static final int BG_COLOR_ID_COLUMN = 2; + private static final int CREATED_DATE_COLUMN = 3; + private static final int HAS_ATTACHMENT_COLUMN = 4; + private static final int MODIFIED_DATE_COLUMN = 5; + private static final int NOTES_COUNT_COLUMN = 6; + private static final int PARENT_ID_COLUMN = 7; + private static final int SNIPPET_COLUMN = 8; + private static final int TYPE_COLUMN = 9; + private static final int WIDGET_ID_COLUMN = 10; + private static final int WIDGET_TYPE_COLUMN = 11; + + private long mId; + private long mAlertDate; + private int mBgColorId; + private long mCreatedDate; + private boolean mHasAttachment; + private long mModifiedDate; + private int mNotesCount; + private long mParentId; + private String mSnippet; + private int mType; + private int mWidgetId; + private int mWidgetType; + private String mName; + private String mPhoneNumber; + + private boolean mIsLastItem; + private boolean mIsFirstItem; + private boolean mIsOnlyOneItem; + private boolean mIsOneNoteFollowingFolder; + private boolean mIsMultiNotesFollowingFolder; + public NoteItemData(Context context, Cursor cursor) { - // 从Cursor中提取各项数据并赋值 - mId = cursor.getLong(ID_COLUMN); // 获取笔记ID - mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); // 获取提醒日期 - mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); // 获取背景颜色ID - mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); // 获取创建日期 - mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false; // 获取是否有附件 - mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); // 获取修改日期 - mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); // 获取笔记数量 - mParentId = cursor.getLong(PARENT_ID_COLUMN); // 获取父ID - mSnippet = cursor.getString(SNIPPET_COLUMN); // 获取摘要 + mId = cursor.getLong(ID_COLUMN); + mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); + mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); + mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); + mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false; + mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); + mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); + mParentId = cursor.getLong(PARENT_ID_COLUMN); + mSnippet = cursor.getString(SNIPPET_COLUMN); mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace( - NoteEditActivity.TAG_UNCHECKED, ""); // 清理摘要中的特殊标记 - mType = cursor.getInt(TYPE_COLUMN); // 获取类型 - mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); // 获取小部件ID - mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); // 获取小部件类型 - - // 如果是通话记录笔记,尝试获取通话号码和联系人名称 - mPhoneNumber = ""; // 初始化电话号码 - if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { // 判断是否为通话记录笔记 - mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); // 获取电话号码 - if (!TextUtils.isEmpty(mPhoneNumber)) { // 判断电话号码是否为空 - mName = Contact.getContact(context, mPhoneNumber); // 获取联系人名称 - if (mName == null) { // 判断联系人名称是否为空 - mName = mPhoneNumber; // 如果为空,则使用电话号码作为名称 + NoteEditActivity.TAG_UNCHECKED, ""); + mType = cursor.getInt(TYPE_COLUMN); + mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); + mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); + + mPhoneNumber = ""; + if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { + mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); + if (!TextUtils.isEmpty(mPhoneNumber)) { + mName = Contact.getContact(context, mPhoneNumber); + if (mName == null) { + mName = mPhoneNumber; } } } - - // 如果没有获取到联系人名称,则默认为空字符串 - if (mName == null) { // 判断联系人名称是否为空 - mName = ""; // 如果为空,则默认为空字符串 + + if (mName == null) { + mName = ""; } - checkPostion(cursor); // 检查笔记在列表中的位置 - } - - /** - * 根据当前Cursor位置,更新NoteItemData的状态信息(如是否为列表中的最后一个项目等)。 - * - * @param cursor 包含笔记数据的Cursor对象。 - */ + checkPostion(cursor); + } + private void checkPostion(Cursor cursor) { - // 更新位置状态信息 - mIsLastItem = cursor.isLast(); // 判断是否为最后一个项目 - mIsFirstItem = cursor.isFirst(); // 判断是否为第一个项目 - mIsOnlyOneItem = (cursor.getCount() == 1); // 判断是否为唯一一个项目 - mIsMultiNotesFollowingFolder = false; // 初始化多个笔记跟随文件夹状态 - mIsOneNoteFollowingFolder = false; // 初始化一个笔记跟随文件夹状态 - - // 检查当前笔记是否跟随文件夹,并更新相应状态 - if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { // 判断是否为笔记且不是第一个项目 - int position = cursor.getPosition(); // 获取当前位置 - if (cursor.moveToPrevious()) { // 移动到前一个位置 + mIsLastItem = cursor.isLast() ? true : false; + mIsFirstItem = cursor.isFirst() ? true : false; + mIsOnlyOneItem = (cursor.getCount() == 1); + mIsMultiNotesFollowingFolder = false; + mIsOneNoteFollowingFolder = false; + + if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { + int position = cursor.getPosition(); + if (cursor.moveToPrevious()) { if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER - || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { // 判断前一个项目是否为文件夹或系统类型 - if (cursor.getCount() > (position + 1)) { // 判断是否有多于一个项目 - mIsMultiNotesFollowingFolder = true; // 设置多个笔记跟随文件夹状态 + || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { + if (cursor.getCount() > (position + 1)) { + mIsMultiNotesFollowingFolder = true; } else { - mIsOneNoteFollowingFolder = true; // 设置一个笔记跟随文件夹状态 + mIsOneNoteFollowingFolder = true; } } - // 确保Cursor能够回到原来的位置 - if (!cursor.moveToNext()) { // 移动回原来的位置 - throw new IllegalStateException("cursor move to previous but can't move back"); // 抛出异常 + if (!cursor.moveToNext()) { + throw new IllegalStateException("cursor move to previous but can't move back"); } } } } - - // 以下为获取NoteItemData各项属性的方法 - + public boolean isOneFollowingFolder() { - return mIsOneNoteFollowingFolder; // 返回一个笔记跟随文件夹状态 + return mIsOneNoteFollowingFolder; } - + public boolean isMultiFollowingFolder() { - return mIsMultiNotesFollowingFolder; // 返回多个笔记跟随文件夹状态 + return mIsMultiNotesFollowingFolder; } - + public boolean isLast() { - return mIsLastItem; // 返回是否为最后一个项目 + return mIsLastItem; } - + public String getCallName() { - return mName; // 返回联系人名称 + return mName; } - + public boolean isFirst() { - return mIsFirstItem; // 返回是否为第一个项目 + return mIsFirstItem; } - + public boolean isSingle() { - return mIsOnlyOneItem; // 返回是否为唯一一个项目 + return mIsOnlyOneItem; } - + public long getId() { - return mId; // 返回笔记ID + return mId; } - + public long getAlertDate() { - return mAlertDate; // 返回提醒日期 + return mAlertDate; } - + public long getCreatedDate() { - return mCreatedDate; // 返回创建日期 + return mCreatedDate; } - + public boolean hasAttachment() { - return mHasAttachment; // 返回是否有附件 + return mHasAttachment; } - + public long getModifiedDate() { - return mModifiedDate; // 返回修改日期 + return mModifiedDate; } - + public int getBgColorId() { - return mBgColorId; // 返回背景颜色ID + return mBgColorId; } - + public long getParentId() { - return mParentId; // 返回父ID + return mParentId; } - + public int getNotesCount() { - return mNotesCount; // 返回笔记数量 + return mNotesCount; } - - public long getFolderId() { - return mParentId; // 返回文件夹ID + + public long getFolderId () { + return mParentId; } - + public int getType() { - return mType; // 返回类型 + return mType; } - + public int getWidgetType() { - return mWidgetType; // 返回小部件类型 + return mWidgetType; } - + public int getWidgetId() { - return mWidgetId; // 返回小部件ID + return mWidgetId; } - + public String getSnippet() { - return mSnippet; // 返回摘要 + return mSnippet; } - + public boolean hasAlert() { - return (mAlertDate > 0); // 返回是否有提醒 + return (mAlertDate > 0); } - + public boolean isCallRecord() { - return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); // 返回是否为通话记录笔记 - } - - /** - * 从Cursor中获取笔记的类型。 - * - * @param cursor 包含笔记数据的Cursor对象。 - * @return 笔记的类型。 - */ + return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); + } + public static int getNoteType(Cursor cursor) { - return cursor.getInt(TYPE_COLUMN); // 返回笔记类型 + return cursor.getInt(TYPE_COLUMN); } } diff --git a/src/net/micode/notes/ui/NotesListActivity.java b/src/net/micode/notes/ui/NotesListActivity.java index 25bae8d..e843aec 100644 --- a/src/net/micode/notes/ui/NotesListActivity.java +++ b/src/net/micode/notes/ui/NotesListActivity.java @@ -15,7 +15,7 @@ */ package net.micode.notes.ui; - + import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -59,7 +59,7 @@ import android.widget.ListView; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; - + import net.micode.notes.R; import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.NoteColumns; @@ -71,123 +71,84 @@ import net.micode.notes.tool.ResourceParser; import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; import net.micode.notes.widget.NoteWidgetProvider_2x; import net.micode.notes.widget.NoteWidgetProvider_4x; - + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashSet; - + public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { - // 定义文件夹中笔记列表查询的标记 private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; - - // 定义文件夹列表查询的标记 - private static final int FOLDER_LIST_QUERY_TOKEN = 1; - - // 菜单中删除文件夹的选项 + + private static final int FOLDER_LIST_QUERY_TOKEN = 1; + private static final int MENU_FOLDER_DELETE = 0; - - // 菜单中查看文件夹的选项 + private static final int MENU_FOLDER_VIEW = 1; - - // 菜单中更改文件夹名称的选项 + private static final int MENU_FOLDER_CHANGE_NAME = 2; - - // 首次使用应用时,添加介绍信息的偏好设置键 + private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; - - // 列表编辑状态的枚举,包括笔记列表、子文件夹和通话记录文件夹 + private enum ListEditState { NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER - } - - ; - - // 当前编辑状态 + }; + private ListEditState mState; - - // 后台查询处理器 + private BackgroundQueryHandler mBackgroundQueryHandler; - - // 笔记列表的适配器 + private NotesListAdapter mNotesListAdapter; - - // 笔记列表视图 + private ListView mNotesListView; - - // 添加新笔记的按钮 + private Button mAddNewNote; - - // 是否分发事件的标志 + private boolean mDispatch; - - // 触摸点的原始Y坐标 + private int mOriginY; - - // 分发事件时的Y坐标 + private int mDispatchY; - - // 标题栏文本视图 + private TextView mTitleBar; - - // 当前文件夹的ID + private long mCurrentFolderId; - - // 内容解析器 + private ContentResolver mContentResolver; - - // 模式回调接口 + private ModeCallback mModeCallBack; - - // 日志标签 + private static final String TAG = "NotesListActivity"; - - // 笔记列表视图滚动速率 + public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; - - // 聚焦的笔记数据项 + private NoteItemData mFocusNoteDataItem; - - // 普通文件夹选择条件 + private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?"; - - // 根文件夹选择条件 + private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>" + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR (" + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + NoteColumns.NOTES_COUNT + ">0)"; - - // 打开节点请求代码 + private final static int REQUEST_CODE_OPEN_NODE = 102; - // 新建节点请求代码 - private final static int REQUEST_CODE_NEW_NODE = 103; - - /** - * 在活动创建时调用,用于初始化资源和设置应用信息。 - * - * @param savedInstanceState 如果活动之前被销毁,这参数包含之前的状态。如果活动没被销毁之前,这参数是null。 - */ + private final static int REQUEST_CODE_NEW_NODE = 103; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.note_list); initResources(); - - // 用户首次使用时插入介绍信息 + + /** + * Insert an introduction when user firstly use this application + */ setAppInfoFromRawRes(); } - - /** - * 处理从其他活动返回的结果。 - * - * @param requestCode 启动其他活动时传入的请求代码。 - * @param resultCode 其他活动返回的结果代码。 - * @param data 其他活动返回的数据。 - */ + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // 如果返回结果为OK且请求代码为打开节点或新建节点,则刷新列表 if (resultCode == RESULT_OK && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { mNotesListAdapter.changeCursor(null); @@ -195,33 +156,23 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt super.onActivityResult(requestCode, resultCode, data); } } - - - /** - * 从原始资源中设置应用信息。此方法会读取R.raw.introduction中的内容, - * 并且只有当之前未添加介绍信息时,才将读取到的内容保存为一个工作笔记。 - */ + private void setAppInfoFromRawRes() { - // 获取SharedPreferences实例 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - // 检查是否已经添加了介绍信息 if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { StringBuilder sb = new StringBuilder(); InputStream in = null; try { - // 从资源中打开introduction文件 - in = getResources().openRawResource(R.raw.introduction); + in = getResources().openRawResource(R.raw.introduction); if (in != null) { - // 读取文件内容到StringBuilder InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); - char[] buf = new char[1024]; + char [] buf = new char[1024]; int len = 0; while ((len = br.read(buf)) > 0) { sb.append(buf, 0, len); } } else { - // 打印错误日志,如果无法打开文件 Log.e(TAG, "Read introduction file error"); return; } @@ -229,96 +180,66 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt e.printStackTrace(); return; } finally { - // 确保InputStream被关闭 - if (in != null) { + if(in != null) { try { in.close(); } catch (IOException e) { + // TODO Auto-generated catch block e.printStackTrace(); } } } - - // 创建一个新的工作笔记并设置其内容 + WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER, AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE, ResourceParser.RED); note.setWorkingText(sb.toString()); - // 保存工作笔记并标记已添加介绍信息 if (note.saveNote()) { sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); } else { - // 打印错误日志,如果保存工作笔记失败 Log.e(TAG, "Save introduction note error"); return; } } } - - /** - * Activity启动时调用,开始异步查询笔记列表。 - */ + @Override protected void onStart() { super.onStart(); startAsyncNotesListQuery(); } - - /** - * 初始化资源,包括ListView、适配器和其他UI组件。 - */ + private void initResources() { - // 获取ContentResolver实例 mContentResolver = this.getContentResolver(); - // 创建后台查询处理器 mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); mCurrentFolderId = Notes.ID_ROOT_FOLDER; - // 初始化ListView和相关监听器 mNotesListView = (ListView) findViewById(R.id.notes_list); mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), null, false); mNotesListView.setOnItemClickListener(new OnListItemClickListener()); mNotesListView.setOnItemLongClickListener(this); - // 初始化并设置笔记列表适配器 mNotesListAdapter = new NotesListAdapter(this); mNotesListView.setAdapter(mNotesListAdapter); - // 初始化新建笔记按钮并设置点击监听器 mAddNewNote = (Button) findViewById(R.id.btn_new_note); mAddNewNote.setOnClickListener(this); mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); - // 初始化状态变量和触摸相关的变量 mDispatch = false; mDispatchY = 0; mOriginY = 0; - // 初始化标题栏和其他状态变量 mTitleBar = (TextView) findViewById(R.id.tv_title_bar); mState = ListEditState.NOTE_LIST; mModeCallBack = new ModeCallback(); } - - - /** - * 用于处理列表的多选择模式和菜单点击事件的回调类。 - */ + private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { - private DropdownMenu mDropDownMenu; // 下拉菜单 - private ActionMode mActionMode; // 动作模式 - private MenuItem mMoveMenu; // 移动菜单项 - - /** - * 创建动作模式时的回调方法。 - * - * @param mode 动作模式实例。 - * @param menu 菜单实例。 - * @return 如果成功创建动作模式,返回true;否则返回false。 - */ + private DropdownMenu mDropDownMenu; + private ActionMode mActionMode; + private MenuItem mMoveMenu; + public boolean onCreateActionMode(ActionMode mode, Menu menu) { - // 加载菜单项 getMenuInflater().inflate(R.menu.note_list_options, menu); - // 设置删除项的点击监听器 menu.findItem(R.id.delete).setOnMenuItemClickListener(this); mMoveMenu = menu.findItem(R.id.move); - // 根据条件决定是否显示移动菜单项 if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER || DataUtils.getUserFolderCount(mContentResolver) == 0) { mMoveMenu.setVisible(false); @@ -326,40 +247,33 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt mMoveMenu.setVisible(true); mMoveMenu.setOnMenuItemClickListener(this); } - // 初始化动作模式和列表选择模式 mActionMode = mode; mNotesListAdapter.setChoiceMode(true); mNotesListView.setLongClickable(false); mAddNewNote.setVisibility(View.GONE); - - // 设置自定义视图并初始化下拉菜单 + View customView = LayoutInflater.from(NotesListActivity.this).inflate( R.layout.note_list_dropdown_menu, null); mode.setCustomView(customView); mDropDownMenu = new DropdownMenu(NotesListActivity.this, (Button) customView.findViewById(R.id.selection_menu), R.menu.note_list_dropdown); - // 设置下拉菜单项点击监听器 - mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ public boolean onMenuItemClick(MenuItem item) { mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); updateMenu(); return true; } - + }); return true; } - - /** - * 更新动作模式下的菜单项。 - */ + private void updateMenu() { int selectedCount = mNotesListAdapter.getSelectedCount(); - // 更新下拉菜单标题 + // Update dropdown menu String format = getResources().getString(R.string.menu_select_title, selectedCount); mDropDownMenu.setTitle(format); - // 更新“选择全部”菜单项的状态 MenuItem item = mDropDownMenu.findItem(R.id.action_select_all); if (item != null) { if (mNotesListAdapter.isAllSelected()) { @@ -371,97 +285,58 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } } - - /** - * 准备动作模式时的回调方法。 - * - * @param mode 动作模式实例。 - * @param menu 菜单实例。 - * @return 返回false,表示未进行任何操作。 - */ + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // TODO Auto-generated method stub return false; } - - /** - * 点击动作模式中的菜单项时的回调方法。 - * - * @param mode 动作模式实例。 - * @param item 被点击的菜单项。 - * @return 返回false,表示未进行任何操作。 - */ + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // TODO Auto-generated method stub return false; } - - /** - * 销毁动作模式时的回调方法。 - * - * @param mode 动作模式实例。 - */ + public void onDestroyActionMode(ActionMode mode) { - // 还原列表选择模式和设置 mNotesListAdapter.setChoiceMode(false); mNotesListView.setLongClickable(true); mAddNewNote.setVisibility(View.VISIBLE); } - + public void finishActionMode() { mActionMode.finish(); } - - /** - * 处理列表项选择状态变化的回调方法。 - * - * @param mode 动作模式实例。 - * @param position 列表中被改变选择状态的项的位置。 - * @param id 项的ID。 - * @param checked 项的新选择状态。 - */ + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { - // 更新列表项的选择状态并更新菜单 + boolean checked) { mNotesListAdapter.setCheckedItem(position, checked); updateMenu(); } - - /** - * 处理菜单项点击事件的回调方法。 - * - * @param item 被点击的菜单项。 - * @return 如果已处理点击事件,返回true;否则返回false。 - */ + public boolean onMenuItemClick(MenuItem item) { - // 若未选择任何项,则显示提示 if (mNotesListAdapter.getSelectedCount() == 0) { Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none), Toast.LENGTH_SHORT).show(); return true; } - - // 根据菜单项ID执行相应操作 + switch (item.getItemId()) { case R.id.delete: - // 显示删除确认对话框 AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setMessage(getString(R.string.alert_message_delete_notes, - mNotesListAdapter.getSelectedCount())); + mNotesListAdapter.getSelectedCount())); builder.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int which) { - batchDelete(); - } - }); + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + batchDelete(); + } + }); builder.setNegativeButton(android.R.string.cancel, null); builder.show(); break; case R.id.move: - // 启动查询目标文件夹的操作 startQueryDestinationFolders(); break; default: @@ -470,37 +345,33 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } } - - - /** - * 为“新建笔记”按钮添加触摸监听器的内部类,实现点击和拖动事件的处理。 - */ + private class NewNoteOnTouchListener implements OnTouchListener { - - /** - * 处理触摸事件。 - * - * @param v 触摸的视图。 - * @param event 触摸事件。 - * @return 如果事件被处理则返回true,否则返回false。 - */ + public boolean onTouch(View v, MotionEvent event) { - // 根据触摸事件的动作进行不同的处理 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { - // 获取屏幕高度和“新建笔记”视图的高度 Display display = getWindowManager().getDefaultDisplay(); int screenHeight = display.getHeight(); int newNoteViewHeight = mAddNewNote.getHeight(); int start = screenHeight - newNoteViewHeight; int eventY = start + (int) event.getY(); - // 如果当前状态为子文件夹编辑状态,需减去标题栏的高度 + /** + * Minus TitleBar's height + */ if (mState == ListEditState.SUB_FOLDER) { eventY -= mTitleBar.getHeight(); start -= mTitleBar.getHeight(); } - // 当点击到“新建笔记”按钮透明部分时,将事件分发给背后的列表视图 - // 这里使用了一种硬编码的方式处理透明部分的点击,依赖于当前的背景公式 + /** + * HACKME:When click the transparent part of "New Note" button, dispatch + * the event to the list view behind this button. The transparent part of + * "New Note" button could be expressed by formula y=-0.12x+94(Unit:pixel) + * and the line top of the button. The coordinate based on left of the "New + * Note" button. The 94 represents maximum height of the transparent part. + * Notice that, if the background of the button changes, the formula should + * also change. This is very bad, just for the UI designer's strong requirement. + */ if (event.getY() < (event.getX() * (-0.12) + 94)) { View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 - mNotesListView.getFooterViewsCount()); @@ -516,7 +387,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt break; } case MotionEvent.ACTION_MOVE: { - // 如果正在分发触摸事件,则更新事件的位置并继续分发 if (mDispatch) { mDispatchY += (int) event.getY() - mOriginY; event.setLocation(event.getX(), mDispatchY); @@ -525,7 +395,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt break; } default: { - // 当触摸动作结束或取消时,停止分发事件 if (mDispatch) { event.setLocation(event.getX(), mDispatchY); mDispatch = false; @@ -534,56 +403,32 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt break; } } - // 如果事件未被分发,则返回false return false; } - - } - - ; - - - /** - * 异步查询笔记列表。 - * 根据当前文件夹ID选择不同的查询条件,启动一个后台查询处理该查询。 - */ + + }; + private void startAsyncNotesListQuery() { - // 根据当前文件夹ID选择查询条件 String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION : NORMAL_SELECTION; - // 启动查询,排序方式为类型降序,修改日期降序 mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null, - Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[]{ - String.valueOf(mCurrentFolderId) + Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] { + String.valueOf(mCurrentFolderId) }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); } - - /** - * 处理后台查询的类。 - * 继承自AsyncQueryHandler,用于处理异步查询完成后的操作。 - */ + private final class BackgroundQueryHandler extends AsyncQueryHandler { public BackgroundQueryHandler(ContentResolver contentResolver) { super(contentResolver); } - - /** - * 查询完成时的处理逻辑。 - * 根据查询标记的不同,执行不同的操作,如更新笔记列表或显示文件夹列表。 - * - * @param token 查询标记,用于区分不同的查询。 - * @param cookie 查询时传入的附加对象。 - * @param cursor 查询结果的游标。 - */ + @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { switch (token) { case FOLDER_NOTE_LIST_QUERY_TOKEN: - // 更新笔记列表适配器的数据源 mNotesListAdapter.changeCursor(cursor); break; case FOLDER_LIST_QUERY_TOKEN: - // 根据查询结果展示或记录错误 if (cursor != null && cursor.getCount() > 0) { showFolderListMenu(cursor); } else { @@ -591,146 +436,95 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } break; default: - // 对未知标记不做处理 return; } } } - - /** - * 显示文件夹列表的菜单。 - * 使用查询结果构建一个对话框,让用户选择一个文件夹。 - * - * @param cursor 查询结果的游标,包含文件夹信息。 - */ + private void showFolderListMenu(Cursor cursor) { - // 构建文件夹列表选择的对话框 AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(R.string.menu_title_select_folder); final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { - - /** - * 用户选择文件夹时的处理逻辑。 - * 将选中的笔记移动到用户选择的文件夹中,并给出反馈。 - * - * @param dialog 对话框实例。 - * @param which 用户选择的项的索引。 - */ + public void onClick(DialogInterface dialog, int which) { - // 批量移动选中的笔记到目标文件夹 DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which)); - // 显示移动操作的反馈信息 Toast.makeText( NotesListActivity.this, getString(R.string.format_move_notes_to_folder, mNotesListAdapter.getSelectedCount(), adapter.getFolderName(NotesListActivity.this, which)), Toast.LENGTH_SHORT).show(); - // 结束当前的操作模式 mModeCallBack.finishActionMode(); } }); builder.show(); } - - /** - * 创建新的笔记。 - * 启动一个活动用于编辑新笔记或编辑现有笔记。 - */ + private void createNewNote() { - // 构建意图并指定动作为插入或编辑,以及初始文件夹ID Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_INSERT_OR_EDIT); intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId); - // 启动该意图并期待返回结果 this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE); } - - - /** - * 批量删除笔记的函数。根据当前是否处于同步模式,采取不同的删除策略:如果不处于同步模式,则直接删除笔记;如果处于同步模式,则将笔记移动到回收站文件夹。 - * 执行删除操作后,会更新相应的widgets。 - */ + private void batchDelete() { new AsyncTask>() { - // 在后台执行任务,获取选中的widgets并执行删除操作 protected HashSet doInBackground(Void... unused) { - // 获取当前选中的widgets HashSet widgets = mNotesListAdapter.getSelectedWidget(); if (!isSyncMode()) { - // 如果当前不处于同步模式,直接删除笔记 + // if not synced, delete notes directly if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter .getSelectedItemIds())) { - // 删除成功无需额外操作 } else { - // 删除失败,记录错误 Log.e(TAG, "Delete notes error, should not happens"); } } else { - // 如果处于同步模式,将笔记移动到回收站文件夹 + // in sync mode, we'll move the deleted note into the trash + // folder if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) { - // 移动失败,记录错误 Log.e(TAG, "Move notes to trash folder error, should not happens"); } } return widgets; } - - // 删除操作完成后,在UI线程执行后续操作 + @Override protected void onPostExecute(HashSet widgets) { - // 遍历所有受影响的widgets,对有效的widgets进行更新 if (widgets != null) { for (AppWidgetAttribute widget : widgets) { if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) { - // 更新有效的widget updateWidget(widget.widgetId, widget.widgetType); } } } - // 结束动作模式 mModeCallBack.finishActionMode(); } }.execute(); } - - - /** - * 删除指定的文件夹。 - * 如果是在同步模式下,文件夹会被移动到回收站,否则直接删除。 - * 同时,也会更新与该文件夹相关的所有小部件。 - * - * @param folderId 要删除的文件夹ID。 - */ + private void deleteFolder(long folderId) { - // 根据ID判断是否为根文件夹,根文件夹不能被删除 if (folderId == Notes.ID_ROOT_FOLDER) { Log.e(TAG, "Wrong folder id, should not happen " + folderId); return; } - + HashSet ids = new HashSet(); ids.add(folderId); - - // 获取与文件夹相关联的小部件信息 HashSet widgets = DataUtils.getFolderNoteWidget(mContentResolver, folderId); if (!isSyncMode()) { - // 非同步模式下直接删除文件夹 + // if not synced, delete folder directly DataUtils.batchDeleteNotes(mContentResolver, ids); } else { - // 同步模式下将文件夹移动到回收站 + // in sync mode, we'll move the deleted folder into the trash folder DataUtils.batchMoveToFolder(mContentResolver, ids, Notes.ID_TRASH_FOLER); } - - // 更新相关小部件 if (widgets != null) { for (AppWidgetAttribute widget : widgets) { - // 有效的小部件才进行更新 if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) { updateWidget(widget.widgetId, widget.widgetType); @@ -738,40 +532,23 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } } - - /** - * 打开指定的笔记节点进行编辑。 - * - * @param data 包含要打开的笔记节点信息的对象。 - */ + private void openNode(NoteItemData data) { - // 构造Intent并设置动作和额外数据,然后启动Activity Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_VIEW); intent.putExtra(Intent.EXTRA_UID, data.getId()); this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE); } - - /** - * 打开指定的文件夹,并加载其笔记列表。 - * 根据文件夹ID的不同,更新UI状态,包括标题和新增笔记按钮的可见性。 - * - * @param data 包含要打开的文件夹信息的对象。 - */ + private void openFolder(NoteItemData data) { - // 设置当前文件夹ID并启动异步查询 mCurrentFolderId = data.getId(); startAsyncNotesListQuery(); - - // 根据文件夹ID更新UI状态 if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { mState = ListEditState.CALL_RECORD_FOLDER; mAddNewNote.setVisibility(View.GONE); } else { mState = ListEditState.SUB_FOLDER; } - - // 更新标题栏显示 if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { mTitleBar.setText(R.string.call_record_folder_name); } else { @@ -779,15 +556,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } mTitleBar.setVisibility(View.VISIBLE); } - - /** - * 点击事件的处理方法。 - * 目前仅处理新建笔记按钮的点击事件。 - * - * @param v 被点击的视图对象。 - */ + public void onClick(View v) { - // 根据视图ID执行相应的操作 switch (v.getId()) { case R.id.btn_new_note: createNewNote(); @@ -796,140 +566,114 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt break; } } - - - /** - * 显示软键盘。 - */ + private void showSoftInput() { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (inputMethodManager != null) { inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } } - - /** - * 隐藏软键盘。 - * - * @param view 触发隐藏软键盘的视图。 - */ + private void hideSoftInput(View view) { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); } - - /** - * 显示创建或修改文件夹的对话框。 - * - * @param create 如果为true,则为创建文件夹;如果为false,则为修改文件夹。 - */ + private void showCreateOrModifyFolderDialog(final boolean create) { final AlertDialog.Builder builder = new AlertDialog.Builder(this); View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null); final EditText etName = (EditText) view.findViewById(R.id.et_foler_name); - showSoftInput(); // 显示软键盘 - + showSoftInput(); if (!create) { - // 如果是修改文件夹 if (mFocusNoteDataItem != null) { - etName.setText(mFocusNoteDataItem.getSnippet()); // 设置当前文件夹名称 - builder.setTitle(getString(R.string.menu_folder_change_name)); // 设置对话框标题 + etName.setText(mFocusNoteDataItem.getSnippet()); + builder.setTitle(getString(R.string.menu_folder_change_name)); } else { - Log.e(TAG, "The long click data item is null"); // 日志记录,长按的数据项为null + Log.e(TAG, "The long click data item is null"); return; } } else { - // 如果是创建文件夹 - etName.setText(""); // 清空输入框内容 - builder.setTitle(this.getString(R.string.menu_create_folder)); // 设置对话框标题 + etName.setText(""); + builder.setTitle(this.getString(R.string.menu_create_folder)); } - - // 设置对话框的确定和取消按钮 + builder.setPositiveButton(android.R.string.ok, null); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - hideSoftInput(etName); // 点击取消时隐藏软键盘 + hideSoftInput(etName); } }); - - final Dialog dialog = builder.setView(view).show(); // 显示对话框 - final Button positive = (Button) dialog.findViewById(android.R.id.button1); // 获取确定按钮 + + final Dialog dialog = builder.setView(view).show(); + final Button positive = (Button)dialog.findViewById(android.R.id.button1); positive.setOnClickListener(new OnClickListener() { public void onClick(View v) { - hideSoftInput(etName); // 隐藏软键盘 - String name = etName.getText().toString(); // 获取输入的文件夹名称 - if (DataUtils.checkVisibleFolderName(mContentResolver, name)) { // 检查文件夹名称是否已存在 + hideSoftInput(etName); + String name = etName.getText().toString(); + if (DataUtils.checkVisibleFolderName(mContentResolver, name)) { Toast.makeText(NotesListActivity.this, getString(R.string.folder_exist, name), - Toast.LENGTH_LONG).show(); // 显示文件夹已存在的提示 - etName.setSelection(0, etName.length()); // 选中输入框中的所有文本 + Toast.LENGTH_LONG).show(); + etName.setSelection(0, etName.length()); return; } if (!create) { - // 如果是修改文件夹 - if (!TextUtils.isEmpty(name)) { // 验证输入的文件夹名称不为空 + if (!TextUtils.isEmpty(name)) { ContentValues values = new ContentValues(); - values.put(NoteColumns.SNIPPET, name); // 设置新的文件夹名称 - values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); // 设置类型为文件夹 - values.put(NoteColumns.LOCAL_MODIFIED, 1); // 标记为已修改 + values.put(NoteColumns.SNIPPET, name); + values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); + values.put(NoteColumns.LOCAL_MODIFIED, 1); mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID - + "=?", new String[]{ - String.valueOf(mFocusNoteDataItem.getId()) - }); // 更新数据库中的文件夹信息 + + "=?", new String[] { + String.valueOf(mFocusNoteDataItem.getId()) + }); } - } else if (!TextUtils.isEmpty(name)) { // 如果是创建文件夹 + } else if (!TextUtils.isEmpty(name)) { ContentValues values = new ContentValues(); - values.put(NoteColumns.SNIPPET, name); // 设置文件夹名称 - values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); // 设置类型为文件夹 - mContentResolver.insert(Notes.CONTENT_NOTE_URI, values); // 在数据库中插入新的文件夹信息 + values.put(NoteColumns.SNIPPET, name); + values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); + mContentResolver.insert(Notes.CONTENT_NOTE_URI, values); } - dialog.dismiss(); // 关闭对话框 + dialog.dismiss(); } }); - - // 初始状态下,如果输入框为空,则禁用确定按钮 + if (TextUtils.isEmpty(etName.getText())) { positive.setEnabled(false); } - - // 监听输入框文本变化,以动态启用或禁用确定按钮 + /** + * When the name edit text is null, disable the positive button + */ etName.addTextChangedListener(new TextWatcher() { public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // 空实现 + // TODO Auto-generated method stub + } - + public void onTextChanged(CharSequence s, int start, int before, int count) { - if (TextUtils.isEmpty(etName.getText())) { // 当输入框为空时,禁用确定按钮 + if (TextUtils.isEmpty(etName.getText())) { positive.setEnabled(false); - } else { // 当输入框不为空时,启用确定按钮 + } else { positive.setEnabled(true); } } - + public void afterTextChanged(Editable s) { - // 空实现 + // TODO Auto-generated method stub + } }); } - - - /** - * 当用户按下返回键时调用的方法,根据当前状态执行不同的操作。 - * 在子文件夹状态下,返回根文件夹并显示笔记列表; - * 在通话记录文件夹状态下,也返回根文件夹但显示添加新笔记按钮; - * 在笔记列表状态下,执行父类的onBackPressed方法,通常是退出或返回上一级。 - */ + @Override public void onBackPressed() { switch (mState) { case SUB_FOLDER: - // 从子文件夹状态返回到根文件夹的笔记列表状态 mCurrentFolderId = Notes.ID_ROOT_FOLDER; mState = ListEditState.NOTE_LIST; startAsyncNotesListQuery(); mTitleBar.setVisibility(View.GONE); break; case CALL_RECORD_FOLDER: - // 从通话记录文件夹状态返回到根文件夹的笔记列表状态,并显示添加新笔记按钮 mCurrentFolderId = Notes.ID_ROOT_FOLDER; mState = ListEditState.NOTE_LIST; mAddNewNote.setVisibility(View.VISIBLE); @@ -937,25 +681,15 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt startAsyncNotesListQuery(); break; case NOTE_LIST: - // 在笔记列表状态下,执行父类的返回操作 super.onBackPressed(); break; default: - // 对于其他状态,不执行任何操作 break; } } - - /** - * 更新小部件显示。 - * 根据传入的小部件类型,设置对应的Provider并发送更新广播。 - * - * @param appWidgetId 小部件ID - * @param appWidgetType 小部件类型 - */ + private void updateWidget(int appWidgetId, int appWidgetType) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - // 根据小部件类型设置Provider if (appWidgetType == Notes.TYPE_WIDGET_2X) { intent.setClass(this, NoteWidgetProvider_2x.class); } else if (appWidgetType == Notes.TYPE_WIDGET_4X) { @@ -964,19 +698,15 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt Log.e(TAG, "Unspported widget type"); return; } - - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{ - appWidgetId + + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { + appWidgetId }); - + sendBroadcast(intent); setResult(RESULT_OK, intent); } - - /** - * 文件夹列表的上下文菜单创建监听器。 - * 在焦点笔记项不为空时,添加查看、删除和重命名菜单项。 - */ + private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { if (mFocusNoteDataItem != null) { @@ -987,13 +717,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } }; - - /** - * 上下文菜单关闭时的回调方法。 - * 在列表视图中取消上下文菜单的监听器。 - * - * @param menu 被关闭的菜单对象 - */ + @Override public void onContextMenuClosed(Menu menu) { if (mNotesListView != null) { @@ -1001,14 +725,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } super.onContextMenuClosed(menu); } - - - /** - * 当上下文菜单中的项目被选择时调用。 - * - * @param item 被选择的菜单项。 - * @return 如果事件已成功处理,则返回true;否则如果事件未处理,则返回false。 - */ + @Override public boolean onContextItemSelected(MenuItem item) { if (mFocusNoteDataItem == null) { @@ -1017,10 +734,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } switch (item.getItemId()) { case MENU_FOLDER_VIEW: - openFolder(mFocusNoteDataItem); // 打开指定的文件夹 + openFolder(mFocusNoteDataItem); break; case MENU_FOLDER_DELETE: - // 显示删除文件夹的确认对话框 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); @@ -1028,35 +744,28 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - deleteFolder(mFocusNoteDataItem.getId()); // 确认后删除文件夹 + deleteFolder(mFocusNoteDataItem.getId()); } }); builder.setNegativeButton(android.R.string.cancel, null); builder.show(); break; case MENU_FOLDER_CHANGE_NAME: - showCreateOrModifyFolderDialog(false); // 显示修改文件夹名称的对话框 + showCreateOrModifyFolderDialog(false); break; default: break; } - + return true; } - - /** - * 准备选项菜单。 - * - * @param menu 菜单对象。 - * @return 总是返回true。 - */ + @Override public boolean onPrepareOptionsMenu(Menu menu) { - menu.clear(); // 清除之前的菜单项 - // 根据当前状态加载不同的菜单布局 + menu.clear(); if (mState == ListEditState.NOTE_LIST) { getMenuInflater().inflate(R.menu.note_list, menu); - // 设置同步或取消同步菜单项的标题 + // set sync or sync_cancel menu.findItem(R.id.menu_sync).setTitle( GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync); } else if (mState == ListEditState.SUB_FOLDER) { @@ -1068,26 +777,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } return true; } - - /** - * 处理选项菜单项的选择。 - * - * @param item 被选择的菜单项。 - * @return 如果事件已成功处理,则返回true;否则如果事件未处理,则返回false。 - */ + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_new_folder: { - showCreateOrModifyFolderDialog(true); // 显示创建新文件夹的对话框 + showCreateOrModifyFolderDialog(true); break; } case R.id.menu_export_text: { - exportNoteToText(); // 导出笔记为文本 + exportNoteToText(); break; } case R.id.menu_sync: { - // 处理同步菜单项的点击事件 if (isSyncMode()) { if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) { GTaskSyncService.startSync(this); @@ -1100,96 +802,86 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt break; } case R.id.menu_setting: { - startPreferenceActivity(); // 打开设置界面 + startPreferenceActivity(); break; } case R.id.menu_new_note: { - createNewNote(); // 创建新笔记 + createNewNote(); break; } case R.id.menu_search: - onSearchRequested(); // 触发搜索请求 + onSearchRequested(); break; default: break; } return true; } - - /** - * 处理搜索请求。 - * - * @return 总是返回true。 - */ + @Override public boolean onSearchRequested() { startSearch(null, false, null /* appData */, false); return true; } - - - /** - * 将笔记导出为文本文件。 - * 在后台任务中执行导出操作,并根据操作结果展示不同的对话框。 - */ + private void exportNoteToText() { final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this); new AsyncTask() { - + @Override protected Integer doInBackground(Void... unused) { - // 执行导出操作 return backup.exportToText(); } - + @Override protected void onPostExecute(Integer result) { - // 根据导出结果展示不同的对话框 if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) { - showExportFailedDialog(NotesListActivity.this.getString(R.string.failed_sdcard_export), - NotesListActivity.this.getString(R.string.error_sdcard_unmounted)); + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(NotesListActivity.this + .getString(R.string.failed_sdcard_export)); + builder.setMessage(NotesListActivity.this + .getString(R.string.error_sdcard_unmounted)); + builder.setPositiveButton(android.R.string.ok, null); + builder.show(); } else if (result == BackupUtils.STATE_SUCCESS) { - showExportSuccessDialog(NotesListActivity.this.getString(R.string.success_sdcard_export), - backup.getExportedTextFileName(), backup.getExportedTextFileDir()); + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(NotesListActivity.this + .getString(R.string.success_sdcard_export)); + builder.setMessage(NotesListActivity.this.getString( + R.string.format_exported_file_location, backup + .getExportedTextFileName(), backup.getExportedTextFileDir())); + builder.setPositiveButton(android.R.string.ok, null); + builder.show(); } else if (result == BackupUtils.STATE_SYSTEM_ERROR) { - showExportFailedDialog(NotesListActivity.this.getString(R.string.failed_sdcard_export), - NotesListActivity.this.getString(R.string.error_sdcard_export)); + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(NotesListActivity.this + .getString(R.string.failed_sdcard_export)); + builder.setMessage(NotesListActivity.this + .getString(R.string.error_sdcard_export)); + builder.setPositiveButton(android.R.string.ok, null); + builder.show(); } } - + }.execute(); } - - /** - * 检查当前是否为同步模式。 - * - * @return 如果已配置同步账户名则返回true,否则返回false。 - */ + private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } - - /** - * 启动设置活动。 - * 用于打开设置界面。 - */ + private void startPreferenceActivity() { Activity from = getParent() != null ? getParent() : this; Intent intent = new Intent(from, NotesPreferenceActivity.class); from.startActivityIfNeeded(intent, -1); } - - /** - * 列表项点击监听器。 - * 处理列表项的点击事件,根据不同的状态和项类型执行相应的操作。 - */ + private class OnListItemClickListener implements OnItemClickListener { - + public void onItemClick(AdapterView parent, View view, int position, long id) { if (view instanceof NotesListItem) { NoteItemData item = ((NotesListItem) view).getItemData(); if (mNotesListAdapter.isInChoiceMode()) { - // 在选择模式下处理项的点击事件 if (item.getType() == Notes.TYPE_NOTE) { position = position - mNotesListView.getHeaderViewsCount(); mModeCallBack.onItemCheckedStateChanged(null, position, id, @@ -1197,8 +889,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } return; } - - // 根据当前状态处理项的点击事件 + switch (mState) { case NOTE_LIST: if (item.getType() == Notes.TYPE_FOLDER @@ -1223,42 +914,31 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } } - + } - - /** - * 启动查询目标文件夹。 - * 根据当前状态查询并显示文件夹列表。 - */ + private void startQueryDestinationFolders() { String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?"; - selection = (mState == ListEditState.NOTE_LIST) ? selection : - "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; - + selection = (mState == ListEditState.NOTE_LIST) ? selection: + "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; + mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN, null, Notes.CONTENT_NOTE_URI, FoldersListAdapter.PROJECTION, selection, - new String[]{ + new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER), String.valueOf(mCurrentFolderId) }, NoteColumns.MODIFIED_DATE + " DESC"); } - - /** - * 长按列表项时的处理。 - * 根据不同的项类型启动选择模式或显示上下文菜单。 - * - * @return 总是返回false。 - */ + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { if (view instanceof NotesListItem) { mFocusNoteDataItem = ((NotesListItem) view).getItemData(); if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) { - // 长按笔记项时启动选择模式 if (mNotesListView.startActionMode(mModeCallBack) != null) { mModeCallBack.onItemCheckedStateChanged(null, position, id, true); mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -1266,40 +946,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt Log.e(TAG, "startActionMode fails"); } } else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) { - // 长按文件夹项时设置上下文菜单监听器 mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener); } } return false; } - - /** - * 显示导出失败的对话框。 - * - * @param title 对话框标题 - * @param message 对话框消息内容 - */ - private void showExportFailedDialog(String title, String message) { - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(title); - builder.setMessage(message); - builder.setPositiveButton(android.R.string.ok, null); - builder.show(); - } - - /** - * 显示导出成功的对话框。 - * - * @param title 对话框标题 - * @param fileName 导出文件的名称 - * @param fileDir 导出文件的目录 - */ - private void showExportSuccessDialog(String title, String fileName, String fileDir) { - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(title); - builder.setMessage(NotesListActivity.this.getString(R.string.format_exported_file_location, fileName, fileDir)); - builder.setPositiveButton(android.R.string.ok, null); - builder.show(); - } - -} \ No newline at end of file +} diff --git a/src/net/micode/notes/ui/NotesListAdapter.java b/src/net/micode/notes/ui/NotesListAdapter.java index af675f9..51c9cb9 100644 --- a/src/net/micode/notes/ui/NotesListAdapter.java +++ b/src/net/micode/notes/ui/NotesListAdapter.java @@ -14,253 +14,170 @@ * limitations under the License. */ - - -package net.micode.notes.ui; // 定义包名 - -import android.content.Context; // 导入Context类,用于获取上下文 -import android.database.Cursor; // 导入Cursor类,用于数据源游标 -import android.util.Log; // 导入Log类,用于日志输出 -import android.view.View; // 导入View类,用于视图操作 -import android.view.ViewGroup; // 导入ViewGroup类,用于视图组操作 -import android.widget.CursorAdapter; // 导入CursorAdapter类,用于游标适配器 - -import net.micode.notes.data.Notes; // 导入Notes类,用于笔记数据操作 - -import java.util.Collection; // 导入Collection类,用于集合操作 -import java.util.HashMap; // 导入HashMap类,用于哈希映射 -import java.util.HashSet; // 导入HashSet类,用于哈希集合 -import java.util.Iterator; // 导入Iterator类,用于迭代器 - -/** - * 用于管理笔记列表的适配器,继承自CursorAdapter。 - */ -public class NotesListAdapter extends CursorAdapter { // 定义NotesListAdapter类,继承自CursorAdapter - private static final String TAG = "NotesListAdapter"; // 定义日志标签 - private Context mContext; // 上下文对象 - // 用于存储选中项的索引和状态 - private HashMap mSelectedIndex; // 选中项索引和状态的哈希映射 - private int mNotesCount; // 笔记总数 - private boolean mChoiceMode; // 选择模式标志 - - /** - * AppWidget属性容器,用于存储与小部件相关的数据。 - */ - public static class AppWidgetAttribute { // 定义AppWidgetAttribute类 - public int widgetId; // 小部件ID - public int widgetType; // 小部件类型 - } - - /** - * 构造函数。 - * - * @param context 上下文对象 - */ - public NotesListAdapter(Context context) { // 构造函数 - super(context, null); // 调用父类构造函数 - mSelectedIndex = new HashMap(); // 初始化选中项索引和状态的哈希映射 - mContext = context; // 赋值上下文对象 - mNotesCount = 0; // 初始化笔记总数 +package net.micode.notes.ui; + +import android.content.Context; +import android.database.Cursor; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; + +import net.micode.notes.data.Notes; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + + +public class NotesListAdapter extends CursorAdapter { + private static final String TAG = "NotesListAdapter"; + private Context mContext; + private HashMap mSelectedIndex; + private int mNotesCount; + private boolean mChoiceMode; + + public static class AppWidgetAttribute { + public int widgetId; + public int widgetType; + }; + + public NotesListAdapter(Context context) { + super(context, null); + mSelectedIndex = new HashMap(); + mContext = context; + mNotesCount = 0; } - - /** - * 创建新的列表项视图。 - * - * @param context 上下文对象 - * @param cursor 数据游标 - * @param parent 父视图 - * @return 新的列表项视图 - */ + @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { // 重写newView方法 - return new NotesListItem(context); // 返回新的列表项视图 + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return new NotesListItem(context); } - - /** - * 绑定数据到视图。 - * - * @param view 列表项视图 - * @param context 上下文对象 - * @param cursor 数据游标 - */ + @Override - public void bindView(View view, Context context, Cursor cursor) { // 重写bindView方法 - if (view instanceof NotesListItem) { // 判断视图是否为NotesListItem类型 - NoteItemData itemData = new NoteItemData(context, cursor); // 创建NoteItemData对象 + public void bindView(View view, Context context, Cursor cursor) { + if (view instanceof NotesListItem) { + NoteItemData itemData = new NoteItemData(context, cursor); ((NotesListItem) view).bind(context, itemData, mChoiceMode, - isSelectedItem(cursor.getPosition())); // 绑定数据到视图 + isSelectedItem(cursor.getPosition())); } } - - /** - * 设置指定位置的项为选中或未选中状态。 - * - * @param position 项的位置 - * @param checked 选中状态 - */ - public void setCheckedItem(final int position, final boolean checked) { // 设置选中项方法 - mSelectedIndex.put(position, checked); // 更新选中项索引和状态 - notifyDataSetChanged(); // 通知数据集改变 + + public void setCheckedItem(final int position, final boolean checked) { + mSelectedIndex.put(position, checked); + notifyDataSetChanged(); } - - /** - * 获取当前是否处于选择模式。 - * - * @return 选择模式状态 - */ - public boolean isInChoiceMode() { // 获取选择模式方法 - return mChoiceMode; // 返回选择模式状态 + + public boolean isInChoiceMode() { + return mChoiceMode; } - - /** - * 设置选择模式。 - * - * @param mode 选择模式状态 - */ - public void setChoiceMode(boolean mode) { // 设置选择模式方法 - mSelectedIndex.clear(); // 清空选中项索引和状态 - mChoiceMode = mode; // 更新选择模式状态 + + public void setChoiceMode(boolean mode) { + mSelectedIndex.clear(); + mChoiceMode = mode; } - - /** - * 全选或全不选。 - * - * @param checked 选中状态 - */ - public void selectAll(boolean checked) { // 全选或全不选方法 - Cursor cursor = getCursor(); // 获取游标 - for (int i = 0; i < getCount(); i++) { // 遍历所有项 - if (cursor.moveToPosition(i)) { // 移动到指定位置 - if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { // 判断是否为笔记类型 - setCheckedItem(i, checked); // 设置选中状态 + + public void selectAll(boolean checked) { + Cursor cursor = getCursor(); + for (int i = 0; i < getCount(); i++) { + if (cursor.moveToPosition(i)) { + if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { + setCheckedItem(i, checked); } } } } - - /** - * 获取所有选中项的ID集合。 - * - * @return 选中项ID的HashSet - */ - public HashSet getSelectedItemIds() { // 获取选中项ID集合方法 - HashSet itemSet = new HashSet(); // 创建哈希集合 - for (Integer position : mSelectedIndex.keySet()) { // 遍历选中项索引 - if (mSelectedIndex.get(position) == true) { // 判断是否为选中状态 - Long id = getItemId(position); // 获取项ID - if (id == Notes.ID_ROOT_FOLDER) { // 判断是否为根文件夹 - Log.d(TAG, "Wrong item id, should not happen"); // 输出日志 + + public HashSet getSelectedItemIds() { + HashSet itemSet = new HashSet(); + for (Integer position : mSelectedIndex.keySet()) { + if (mSelectedIndex.get(position) == true) { + Long id = getItemId(position); + if (id == Notes.ID_ROOT_FOLDER) { + Log.d(TAG, "Wrong item id, should not happen"); } else { - itemSet.add(id); // 添加到哈希集合 + itemSet.add(id); } } } - - return itemSet; // 返回哈希集合 + + return itemSet; } - - /** - * 获取所有选中小部件的属性集合。 - * - * @return 选中小部件属性的HashSet - */ - public HashSet getSelectedWidget() { // 获取选中小部件属性集合方法 - HashSet itemSet = new HashSet(); // 创建哈希集合 - for (Integer position : mSelectedIndex.keySet()) { // 遍历选中项索引 - if (mSelectedIndex.get(position) == true) { // 判断是否为选中状态 - Cursor c = (Cursor) getItem(position); // 获取游标 - if (c != null) { // 判断游标是否为空 - AppWidgetAttribute widget = new AppWidgetAttribute(); // 创建AppWidgetAttribute对象 - NoteItemData item = new NoteItemData(mContext, c); // 创建NoteItemData对象 - widget.widgetId = item.getWidgetId(); // 获取小部件ID - widget.widgetType = item.getWidgetType(); // 获取小部件类型 - itemSet.add(widget); // 添加到哈希集合 + + public HashSet getSelectedWidget() { + HashSet itemSet = new HashSet(); + for (Integer position : mSelectedIndex.keySet()) { + if (mSelectedIndex.get(position) == true) { + Cursor c = (Cursor) getItem(position); + if (c != null) { + AppWidgetAttribute widget = new AppWidgetAttribute(); + NoteItemData item = new NoteItemData(mContext, c); + widget.widgetId = item.getWidgetId(); + widget.widgetType = item.getWidgetType(); + itemSet.add(widget); + /** + * Don't close cursor here, only the adapter could close it + */ } else { - Log.e(TAG, "Invalid cursor"); // 输出日志 - return null; // 返回空 + Log.e(TAG, "Invalid cursor"); + return null; } } } - return itemSet; // 返回哈希集合 + return itemSet; } - - /** - * 获取选中项的数量。 - * - * @return 选中项数量 - */ - public int getSelectedCount() { // 获取选中项数量方法 - Collection values = mSelectedIndex.values(); // 获取选中项状态集合 - if (null == values) { // 判断集合是否为空 - return 0; // 返回0 + + public int getSelectedCount() { + Collection values = mSelectedIndex.values(); + if (null == values) { + return 0; } - Iterator iter = values.iterator(); // 获取迭代器 - int count = 0; // 初始化计数器 - while (iter.hasNext()) { // 遍历集合 - if (true == iter.next()) { // 判断是否为选中状态 - count++; // 计数器加1 + Iterator iter = values.iterator(); + int count = 0; + while (iter.hasNext()) { + if (true == iter.next()) { + count++; } } - return count; // 返回计数器 + return count; } - - /** - * 判断是否全部选中。 - * - * @return 全部选中的状态 - */ - public boolean isAllSelected() { // 判断是否全部选中方法 - int checkedCount = getSelectedCount(); // 获取选中项数量 - return (checkedCount != 0 && checkedCount == mNotesCount); // 判断是否全部选中 + + public boolean isAllSelected() { + int checkedCount = getSelectedCount(); + return (checkedCount != 0 && checkedCount == mNotesCount); } - - /** - * 检查指定位置的项是否被选中。 - * - * @param position 项的位置 - * @return 选中状态 - */ - public boolean isSelectedItem(final int position) { // 检查选中项方法 - if (null == mSelectedIndex.get(position)) { // 判断是否为空 - return false; // 返回未选中状态 + + public boolean isSelectedItem(final int position) { + if (null == mSelectedIndex.get(position)) { + return false; } - return mSelectedIndex.get(position); // 返回选中状态 + return mSelectedIndex.get(position); } - - /** - * 当内容改变时调用,更新笔记数量。 - */ + @Override - protected void onContentChanged() { // 重写onContentChanged方法 - super.onContentChanged(); // 调用父类方法 - calcNotesCount(); // 计算笔记数量 + protected void onContentChanged() { + super.onContentChanged(); + calcNotesCount(); } - - /** - * 当游标改变时调用,更新笔记数量。 - * - * @param cursor 新的游标 - */ + @Override - public void changeCursor(Cursor cursor) { // 重写changeCursor方法 - super.changeCursor(cursor); // 调用父类方法 - calcNotesCount(); // 计算笔记数量 + public void changeCursor(Cursor cursor) { + super.changeCursor(cursor); + calcNotesCount(); } - - /** - * 计算并更新笔记总数。 - */ - private void calcNotesCount() { // 计算笔记数量方法 - mNotesCount = 0; // 初始化笔记总数 - for (int i = 0; i < getCount(); i++) { // 遍历所有项 - Cursor c = (Cursor) getItem(i); // 获取游标 - if (c != null) { // 判断游标是否为空 - if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { // 判断是否为笔记类型 - mNotesCount++; // 笔记总数加1 + + private void calcNotesCount() { + mNotesCount = 0; + for (int i = 0; i < getCount(); i++) { + Cursor c = (Cursor) getItem(i); + if (c != null) { + if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { + mNotesCount++; } } else { - Log.e(TAG, "Invalid cursor"); // 输出日志 - return; // 返回 + Log.e(TAG, "Invalid cursor"); + return; } } } diff --git a/src/net/micode/notes/ui/NotesListItem.java b/src/net/micode/notes/ui/NotesListItem.java index ba6af95..1221e80 100644 --- a/src/net/micode/notes/ui/NotesListItem.java +++ b/src/net/micode/notes/ui/NotesListItem.java @@ -14,143 +14,109 @@ * limitations under the License. */ - -package net.micode.notes.ui; // 定义包名 - -import android.content.Context; // 导入Context类,用于获取上下文 -import android.text.format.DateUtils; // 导入DateUtils类,用于日期格式化 -import android.view.View; // 导入View类,用于视图操作 -import android.widget.CheckBox; // 导入CheckBox类,用于复选框 -import android.widget.ImageView; // 导入ImageView类,用于图像显示 -import android.widget.LinearLayout; // 导入LinearLayout类,用于线性布局 -import android.widget.TextView; // 导入TextView类,用于文本显示 - -import net.micode.notes.R; // 导入R类,用于资源引用 -import net.micode.notes.data.Notes; // 导入Notes类,用于笔记数据操作 -import net.micode.notes.tool.DataUtils; // 导入DataUtils类,用于数据处理 -import net.micode.notes.tool.ResourceParser.NoteItemBgResources; // 导入NoteItemBgResources类,用于背景资源解析 - -/* - * 该类表示一个笔记列表项,继承自LinearLayout,并包含了显示笔记各种信息的组件。 - * 它用于在UI中展示一个笔记或文件夹的条目。 - */ - -public class NotesListItem extends LinearLayout { // 定义NotesListItem类,继承自LinearLayout - private ImageView mAlert; // 用于显示提醒图标 - private TextView mTitle; // 显示笔记标题 - private TextView mTime; // 显示修改时间 - private TextView mCallName; // 在通话记录笔记中显示通话名称 - private NoteItemData mItemData; // 绑定的笔记数据 - private CheckBox mCheckBox; // 选择框,用于多选模式 - - /* - * 构造函数,初始化视图组件。 - */ - public NotesListItem(Context context) { // 构造函数 - super(context); // 调用父类构造函数 - inflate(context, R.layout.note_item, this); // 填充布局 - // 初始化视图组件 - mAlert = (ImageView) findViewById(R.id.iv_alert_icon); // 初始化提醒图标 - mTitle = (TextView) findViewById(R.id.tv_title); // 初始化标题 - mTime = (TextView) findViewById(R.id.tv_time); // 初始化时间 - mCallName = (TextView) findViewById(R.id.tv_name); // 初始化通话名称 - mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); // 初始化复选框 +package net.micode.notes.ui; + +import android.content.Context; +import android.text.format.DateUtils; +import android.view.View; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.DataUtils; +import net.micode.notes.tool.ResourceParser.NoteItemBgResources; + + +public class NotesListItem extends LinearLayout { + private ImageView mAlert; + private TextView mTitle; + private TextView mTime; + private TextView mCallName; + private NoteItemData mItemData; + private CheckBox mCheckBox; + + public NotesListItem(Context context) { + super(context); + inflate(context, R.layout.note_item, this); + mAlert = (ImageView) findViewById(R.id.iv_alert_icon); + mTitle = (TextView) findViewById(R.id.tv_title); + mTime = (TextView) findViewById(R.id.tv_time); + mCallName = (TextView) findViewById(R.id.tv_name); + mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); } - - /* - * 绑定数据到视图,根据数据设置视图状态。 - * - * @param context 上下文 - * @param data 要绑定的笔记数据 - * @param choiceMode 是否为选择模式 - * @param checked 是否选中 - */ - public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { // 绑定数据方法 - // 根据是否为选择模式和笔记类型,控制复选框的可见性和选中状态 - if (choiceMode && data.getType() == Notes.TYPE_NOTE) { // 判断是否为选择模式且为笔记类型 - mCheckBox.setVisibility(View.VISIBLE); // 显示复选框 - mCheckBox.setChecked(checked); // 设置复选框选中状态 + + public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { + if (choiceMode && data.getType() == Notes.TYPE_NOTE) { + mCheckBox.setVisibility(View.VISIBLE); + mCheckBox.setChecked(checked); } else { - mCheckBox.setVisibility(View.GONE); // 隐藏复选框 + mCheckBox.setVisibility(View.GONE); } - - mItemData = data; // 赋值笔记数据 - // 根据笔记类型和状态,设置标题、提醒图标和背景 - if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { // 判断是否为通话记录文件夹 - // 通话记录文件夹 - mCallName.setVisibility(View.GONE); // 隐藏通话名称 - mAlert.setVisibility(View.VISIBLE); // 显示提醒图标 - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); // 设置标题样式 + + mItemData = data; + if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { + mCallName.setVisibility(View.GONE); + mAlert.setVisibility(View.VISIBLE); + mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); mTitle.setText(context.getString(R.string.call_record_folder_name) - + context.getString(R.string.format_folder_files_count, data.getNotesCount())); // 设置标题文本 - mAlert.setImageResource(R.drawable.call_record); // 设置提醒图标 - } else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { // 判断是否为通话记录笔记 - // 通话记录笔记 - mCallName.setVisibility(View.VISIBLE); // 显示通话名称 - mCallName.setText(data.getCallName()); // 设置通话名称 - mTitle.setTextAppearance(context, R.style.TextAppearanceSecondaryItem); // 设置标题样式 - mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); // 设置标题文本 - if (data.hasAlert()) { // 判断是否有提醒 - mAlert.setImageResource(R.drawable.clock); // 设置提醒图标 - mAlert.setVisibility(View.VISIBLE); // 显示提醒图标 + + context.getString(R.string.format_folder_files_count, data.getNotesCount())); + mAlert.setImageResource(R.drawable.call_record); + } else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { + mCallName.setVisibility(View.VISIBLE); + mCallName.setText(data.getCallName()); + mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem); + mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + if (data.hasAlert()) { + mAlert.setImageResource(R.drawable.clock); + mAlert.setVisibility(View.VISIBLE); } else { - mAlert.setVisibility(View.GONE); // 隐藏提醒图标 + mAlert.setVisibility(View.GONE); } } else { - // 其他类型的笔记或文件夹 - mCallName.setVisibility(View.GONE); // 隐藏通话名称 - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); // 设置标题样式 - - if (data.getType() == Notes.TYPE_FOLDER) { // 判断是否为文件夹 + mCallName.setVisibility(View.GONE); + mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); + + if (data.getType() == Notes.TYPE_FOLDER) { mTitle.setText(data.getSnippet() + context.getString(R.string.format_folder_files_count, - data.getNotesCount())); // 设置标题文本 - mAlert.setVisibility(View.GONE); // 隐藏提醒图标 + data.getNotesCount())); + mAlert.setVisibility(View.GONE); } else { - mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); // 设置标题文本 - if (data.hasAlert()) { // 判断是否有提醒 - mAlert.setImageResource(R.drawable.clock); // 设置提醒图标 - mAlert.setVisibility(View.VISIBLE); // 显示提醒图标 + mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + if (data.hasAlert()) { + mAlert.setImageResource(R.drawable.clock); + mAlert.setVisibility(View.VISIBLE); } else { - mAlert.setVisibility(View.GONE); // 隐藏提醒图标 + mAlert.setVisibility(View.GONE); } } } - // 设置时间显示 - mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); // 设置时间文本 - - // 设置背景资源 - setBackground(data); // 设置背景 + mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); + + setBackground(data); } - - /* - * 根据笔记数据设置列表项的背景资源。 - */ - private void setBackground(NoteItemData data) { // 设置背景方法 - int id = data.getBgColorId(); // 获取背景颜色ID - if (data.getType() == Notes.TYPE_NOTE) { // 判断是否为笔记类型 - // 根据笔记的状态设置不同的背景资源 - if (data.isSingle() || data.isOneFollowingFolder()) { // 判断是否为单个笔记或紧跟文件夹的笔记 - setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); // 设置单个笔记背景 - } else if (data.isLast()) { // 判断是否为最后一个笔记 - setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); // 设置最后一个笔记背景 - } else if (data.isFirst() || data.isMultiFollowingFolder()) { // 判断是否为第一个笔记或多个紧跟文件夹的笔记 - setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); // 设置第一个笔记背景 + + private void setBackground(NoteItemData data) { + int id = data.getBgColorId(); + if (data.getType() == Notes.TYPE_NOTE) { + if (data.isSingle() || data.isOneFollowingFolder()) { + setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); + } else if (data.isLast()) { + setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); + } else if (data.isFirst() || data.isMultiFollowingFolder()) { + setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); } else { - setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); // 设置普通笔记背景 + setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); } } else { - // 文件夹背景资源 - setBackgroundResource(NoteItemBgResources.getFolderBgRes()); // 设置文件夹背景 + setBackgroundResource(NoteItemBgResources.getFolderBgRes()); } } - - /* - * 获取绑定的笔记数据。 - * - * @return 绑定的NoteItemData对象 - */ - public NoteItemData getItemData() { // 获取笔记数据方法 - return mItemData; // 返回笔记数据 + + public NoteItemData getItemData() { + return mItemData; } } diff --git a/src/net/micode/notes/ui/NotesPreferenceActivity.java b/src/net/micode/notes/ui/NotesPreferenceActivity.java index 99fd24f..07c5f7e 100644 --- a/src/net/micode/notes/ui/NotesPreferenceActivity.java +++ b/src/net/micode/notes/ui/NotesPreferenceActivity.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package net.micode.notes.ui; - + import android.accounts.Account; import android.accounts.AccountManager; import android.app.ActionBar; @@ -41,64 +41,59 @@ import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; - + import net.micode.notes.R; import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.gtask.remote.GTaskSyncService; - - + + public class NotesPreferenceActivity extends PreferenceActivity { - // 常量定义部分:主要用于设置和同步相关的偏好设置键 - public static final String PREFERENCE_NAME = "notes_preferences"; // 偏好设置的名称 - public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name"; // 同步账户名称的键 - public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time"; // 上次同步时间的键 - public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear"; // 设置背景颜色的键 - private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; // 同步账户的键 - private static final String AUTHORITIES_FILTER_KEY = "authorities"; // 权限过滤键 - - // 类成员变量定义部分:主要用于账户同步和UI更新 - private PreferenceCategory mAccountCategory; // 账户分类偏好项 - private GTaskReceiver mReceiver; // 接收同步任务的广播接收器 - private Account[] mOriAccounts; // 原始账户数组 - private boolean mHasAddedAccount; // 标记是否已添加新账户 - - /** - * 当设置Activity创建时调用。 - * 主要进行界面初始化和设置账户同步。 - * - * @param icicle 保存Activity状态的Bundle,用于恢复状态。 - */ + public static final String PREFERENCE_NAME = "notes_preferences"; + + public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name"; + + public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time"; + + public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear"; + + private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; + + private static final String AUTHORITIES_FILTER_KEY = "authorities"; + + private PreferenceCategory mAccountCategory; + + private GTaskReceiver mReceiver; + + private Account[] mOriAccounts; + + private boolean mHasAddedAccount; + @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); - - // 设置返回按钮 + + /* using the app icon for navigation */ getActionBar().setDisplayHomeAsUpEnabled(true); - - // 从XML加载偏好设置 + addPreferencesFromResource(R.xml.preferences); mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); mReceiver = new GTaskReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME); - registerReceiver(mReceiver, filter); // 注册广播接收器以监听同步服务 - + registerReceiver(mReceiver, filter); + mOriAccounts = null; - // 添加设置头部视图 View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); getListView().addHeaderView(header, null, true); } - - /** - * 当设置Activity恢复到前台时调用。 - * 主要用于检查并自动设置新添加的账户进行同步。 - */ + @Override protected void onResume() { super.onResume(); - - // 自动设置新添加的账户进行同步 + + // need to set sync account automatically if user has added a new + // account if (mHasAddedAccount) { Account[] accounts = getGoogleAccounts(); if (mOriAccounts != null && accounts.length > mOriAccounts.length) { @@ -111,144 +106,120 @@ public class NotesPreferenceActivity extends PreferenceActivity { } } if (!found) { - setSyncAccount(accountNew.name); // 设置新账户进行同步 + setSyncAccount(accountNew.name); break; } } } } - - // 刷新UI + refreshUI(); } - - - /** - * 当Activity即将被销毁时调用,用于注销广播接收器。 - */ + @Override protected void onDestroy() { if (mReceiver != null) { - unregisterReceiver(mReceiver); // 注销广播接收器,避免内存泄漏 + unregisterReceiver(mReceiver); } super.onDestroy(); } - - /** - * 加载账户偏好设置,展示当前同步账户信息及操作。 - */ + private void loadAccountPreference() { - mAccountCategory.removeAll(); // 清空账户分类下的所有条目 - - // 创建并配置账户偏好项 + mAccountCategory.removeAll(); + Preference accountPref = new Preference(this); - final String defaultAccount = getSyncAccountName(this); // 获取默认同步账户名称 - accountPref.setTitle(getString(R.string.preferences_account_title)); // 设置标题 - accountPref.setSummary(getString(R.string.preferences_account_summary)); // 设置摘要 + final String defaultAccount = getSyncAccountName(this); + accountPref.setTitle(getString(R.string.preferences_account_title)); + accountPref.setSummary(getString(R.string.preferences_account_summary)); accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { - // 处理账户点击事件 if (!GTaskSyncService.isSyncing()) { if (TextUtils.isEmpty(defaultAccount)) { - // 如果尚未设置账户,则展示选择账户对话框 + // the first time to set account showSelectAccountAlertDialog(); } else { - // 如果已经设置账户,则展示更改账户确认对话框 + // if the account has already been set, we need to promp + // user about the risk showChangeAccountConfirmAlertDialog(); } } else { - // 如果正在同步中,则展示无法更改账户的提示 Toast.makeText(NotesPreferenceActivity.this, - R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT) + R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT) .show(); } return true; } }); - - mAccountCategory.addPreference(accountPref); // 将账户偏好项添加到账户分类下 + + mAccountCategory.addPreference(accountPref); } - - /** - * 加载同步按钮,并根据同步状态设置其文本和点击事件。 - */ + private void loadSyncButton() { - Button syncButton = (Button) findViewById(R.id.preference_sync_button); // 获取同步按钮 - TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); // 获取上次同步时间视图 - - // 根据同步状态设置按钮文本和点击事件 + Button syncButton = (Button) findViewById(R.id.preference_sync_button); + TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); + + // set button state if (GTaskSyncService.isSyncing()) { - syncButton.setText(getString(R.string.preferences_button_sync_cancel)); // 设置为取消同步文本 + syncButton.setText(getString(R.string.preferences_button_sync_cancel)); syncButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - GTaskSyncService.cancelSync(NotesPreferenceActivity.this); // 设置点击事件为取消同步 + GTaskSyncService.cancelSync(NotesPreferenceActivity.this); } }); } else { - syncButton.setText(getString(R.string.preferences_button_sync_immediately)); // 设置为立即同步文本 + syncButton.setText(getString(R.string.preferences_button_sync_immediately)); syncButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - GTaskSyncService.startSync(NotesPreferenceActivity.this); // 设置点击事件为开始同步 + GTaskSyncService.startSync(NotesPreferenceActivity.this); } }); } - syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); // 只有在设置了同步账户时才使能同步按钮 - - // 根据同步状态设置上次同步时间的显示 + syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); + + // set last sync time if (GTaskSyncService.isSyncing()) { - lastSyncTimeView.setText(GTaskSyncService.getProgressString()); // 如果正在同步,显示进度信息 - lastSyncTimeView.setVisibility(View.VISIBLE); // 显示上次同步时间视图 + lastSyncTimeView.setText(GTaskSyncService.getProgressString()); + lastSyncTimeView.setVisibility(View.VISIBLE); } else { - long lastSyncTime = getLastSyncTime(this); // 获取上次同步时间 + long lastSyncTime = getLastSyncTime(this); if (lastSyncTime != 0) { lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time, DateFormat.format(getString(R.string.preferences_last_sync_time_format), - lastSyncTime))); // 格式化并显示上次同步时间 - lastSyncTimeView.setVisibility(View.VISIBLE); // 显示上次同步时间视图 + lastSyncTime))); + lastSyncTimeView.setVisibility(View.VISIBLE); } else { - lastSyncTimeView.setVisibility(View.GONE); // 如果未同步过,则隐藏上次同步时间视图 + lastSyncTimeView.setVisibility(View.GONE); } } } - - /** - * 刷新用户界面,加载账户偏好设置和同步按钮。 - */ + private void refreshUI() { - loadAccountPreference(); // 加载账户偏好设置 - loadSyncButton(); // 加载同步按钮 + loadAccountPreference(); + loadSyncButton(); } - - /** - * 显示选择账户的对话框。 - * 该对话框列出了已连接的Google账户,并允许用户选择一个账户用于同步。 - * 如果没有账户,对话框将提供添加账户的选项。 - */ + private void showSelectAccountAlertDialog() { - // 创建对话框构建器并设置自定义标题 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - + View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); titleTextView.setText(getString(R.string.preferences_dialog_select_account_title)); TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips)); - + dialogBuilder.setCustomTitle(titleView); - dialogBuilder.setPositiveButton(null, null); // 移除默认的确定按钮 - - // 获取当前设备上的Google账户 + dialogBuilder.setPositiveButton(null, null); + Account[] accounts = getGoogleAccounts(); - String defAccount = getSyncAccountName(this); // 获取当前同步的账户名称 - - mOriAccounts = accounts; // 保存原始账户列表 - mHasAddedAccount = false; // 标记是否已添加新账户 - + String defAccount = getSyncAccountName(this); + + mOriAccounts = accounts; + mHasAddedAccount = false; + if (accounts.length > 0) { - // 创建账户选项并设置选中项 CharSequence[] items = new CharSequence[accounts.length]; final CharSequence[] itemMapping = items; - int checkedItem = -1; // 记录默认选中的账户 + int checkedItem = -1; int index = 0; for (Account account : accounts) { if (TextUtils.equals(account.name, defAccount)) { @@ -256,7 +227,6 @@ public class NotesPreferenceActivity extends PreferenceActivity { } items[index++] = account.name; } - // 设置单选列表,并为选中的账户执行同步操作 dialogBuilder.setSingleChoiceItems(items, checkedItem, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { @@ -266,34 +236,27 @@ public class NotesPreferenceActivity extends PreferenceActivity { } }); } - - // 添加“添加账户”选项 + View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null); dialogBuilder.setView(addAccountView); - + final AlertDialog dialog = dialogBuilder.show(); - // 点击“添加账户”执行添加账户操作 addAccountView.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mHasAddedAccount = true; Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra(AUTHORITIES_FILTER_KEY, new String[]{ - "gmail-ls" + intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] { + "gmail-ls" }); startActivityForResult(intent, -1); dialog.dismiss(); } }); } - - /** - * 显示更改账户确认对话框。 - * 提供用户更改当前同步账户或取消更改的选择。 - */ + private void showChangeAccountConfirmAlertDialog() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - - // 设置自定义标题,包含当前同步账户名称 + View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); titleTextView.setText(getString(R.string.preferences_dialog_change_account_title, @@ -301,9 +264,8 @@ public class NotesPreferenceActivity extends PreferenceActivity { TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg)); dialogBuilder.setCustomTitle(titleView); - - // 创建菜单项并设置点击事件 - CharSequence[] menuItemArray = new CharSequence[]{ + + CharSequence[] menuItemArray = new CharSequence[] { getString(R.string.preferences_menu_change_account), getString(R.string.preferences_menu_remove_account), getString(R.string.preferences_menu_cancel) @@ -311,10 +273,8 @@ public class NotesPreferenceActivity extends PreferenceActivity { dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == 0) { - // 选择更改账户,显示账户选择对话框 showSelectAccountAlertDialog(); } else if (which == 1) { - // 选择移除账户,执行移除操作并刷新UI removeSyncAccount(); refreshUI(); } @@ -322,41 +282,27 @@ public class NotesPreferenceActivity extends PreferenceActivity { }); dialogBuilder.show(); } - - /** - * 获取设备上的Google账户列表。 - * - * @return Account[] 返回设备上所有类型为“com.google”的账户数组。 - */ + private Account[] getGoogleAccounts() { AccountManager accountManager = AccountManager.get(this); return accountManager.getAccountsByType("com.google"); } - - - /** - * 设置同步账户信息。 - * 如果当前账户与传入账户不一致,则更新SharedPreferences中的账户信息,并清理本地相关的gtask信息。 - * - * @param account 需要设置的账户名 - */ + private void setSyncAccount(String account) { - // 检查当前账户是否与传入账户名一致,不一致则更新账户信息 if (!getSyncAccountName(this).equals(account)) { SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); - // 如果账户名非空,则保存账户名,否则清除账户名 if (account != null) { editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); } else { editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } editor.commit(); - - // 清理上次同步时间 + + // clean up last sync time setLastSyncTime(this, 0); - - // 清理本地相关的gtask信息 + + // clean up local gtask related info new Thread(new Runnable() { public void run() { ContentValues values = new ContentValues(); @@ -365,32 +311,25 @@ public class NotesPreferenceActivity extends PreferenceActivity { getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } }).start(); - - // 显示设置成功的提示信息 + Toast.makeText(NotesPreferenceActivity.this, getString(R.string.preferences_toast_success_set_accout, account), Toast.LENGTH_SHORT).show(); } } - - /** - * 移除同步账户信息。 - * 清除SharedPreferences中的账户信息和上次同步时间,并清理本地相关的gtask信息。 - */ + private void removeSyncAccount() { SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); - // 如果存在账户信息,则移除 if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) { editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); } - // 如果存在上次同步时间信息,则移除 if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) { editor.remove(PREFERENCE_LAST_SYNC_TIME); } editor.commit(); - - // 清理本地相关的gtask信息 + + // clean up local gtask related info new Thread(new Runnable() { public void run() { ContentValues values = new ContentValues(); @@ -400,27 +339,13 @@ public class NotesPreferenceActivity extends PreferenceActivity { } }).start(); } - - /** - * 获取当前同步账户名。 - * 从SharedPreferences中获取存储的账户名,默认为空字符串。 - * - * @param context 上下文 - * @return 同步账户名 - */ + public static String getSyncAccountName(Context context) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } - - /** - * 设置上次同步的时间。 - * 将指定的时间保存到SharedPreferences中。 - * - * @param context 上下文 - * @param time 上次同步的时间戳 - */ + public static void setLastSyncTime(Context context, long time) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); @@ -428,48 +353,30 @@ public class NotesPreferenceActivity extends PreferenceActivity { editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); editor.commit(); } - - /** - * 获取上次同步的时间。 - * 从SharedPreferences中获取上次同步的时间戳,默认为0。 - * - * @param context 上下文 - * @return 上次同步的时间戳 - */ + public static long getLastSyncTime(Context context) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); } - - /** - * 广播接收器类,用于接收gtask同步相关的广播消息,并据此刷新UI。 - */ + private class GTaskReceiver extends BroadcastReceiver { - + @Override public void onReceive(Context context, Intent intent) { refreshUI(); - // 如果广播消息表明正在同步,则更新UI显示的同步状态信息 if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview); syncStatus.setText(intent .getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG)); } - + } } - - /** - * 处理选项菜单项的选择事件。 - * - * @param item 选中的菜单项 - * @return 如果事件已处理,则返回true;否则返回false。 - */ + public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: - // 当选择返回按钮时,启动NotesListActivity并清除当前活动栈顶以上的所有活动 Intent intent = new Intent(this, NotesListActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); diff --git a/src/net/micode/notes/widget/NoteWidgetProvider.java b/src/net/micode/notes/widget/NoteWidgetProvider.java index 6c8ae35..ec6f819 100644 --- a/src/net/micode/notes/widget/NoteWidgetProvider.java +++ b/src/net/micode/notes/widget/NoteWidgetProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -//桌面挂件// + package net.micode.notes.widget; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; diff --git a/src/net/micode/notes/widget/NoteWidgetProvider_2x.java b/src/net/micode/notes/widget/NoteWidgetProvider_2x.java index ce78584..adcb2f7 100644 --- a/src/net/micode/notes/widget/NoteWidgetProvider_2x.java +++ b/src/net/micode/notes/widget/NoteWidgetProvider_2x.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -//二倍大小的桌面挂件// + package net.micode.notes.widget; import android.appwidget.AppWidgetManager; diff --git a/src/net/micode/notes/widget/NoteWidgetProvider_4x.java b/src/net/micode/notes/widget/NoteWidgetProvider_4x.java index 291a05e..c12a02e 100644 --- a/src/net/micode/notes/widget/NoteWidgetProvider_4x.java +++ b/src/net/micode/notes/widget/NoteWidgetProvider_4x.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -//四倍大小的桌面挂件// + package net.micode.notes.widget; import android.appwidget.AppWidgetManager; diff --git a/src/res/color/primary_text_dark.xml b/src/res/color/primary_text_dark.xml deleted file mode 100644 index 7c85459..0000000 --- a/src/res/color/primary_text_dark.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/res/color/secondary_text_dark.xml b/src/res/color/secondary_text_dark.xml deleted file mode 100644 index c1c2384..0000000 --- a/src/res/color/secondary_text_dark.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/res/drawable-hdpi/bg_btn_set_color.png b/src/res/drawable-hdpi/bg_btn_set_color.png deleted file mode 100644 index 5eb5d44..0000000 Binary files a/src/res/drawable-hdpi/bg_btn_set_color.png and /dev/null differ diff --git a/src/res/drawable-hdpi/bg_color_btn_mask.png b/src/res/drawable-hdpi/bg_color_btn_mask.png deleted file mode 100644 index 100db77..0000000 Binary files a/src/res/drawable-hdpi/bg_color_btn_mask.png and /dev/null differ diff --git a/src/res/drawable-hdpi/call_record.png b/src/res/drawable-hdpi/call_record.png deleted file mode 100644 index fb88ca4..0000000 Binary files a/src/res/drawable-hdpi/call_record.png and /dev/null differ diff --git a/src/res/drawable-hdpi/clock.png b/src/res/drawable-hdpi/clock.png deleted file mode 100644 index 5f2ae9a..0000000 Binary files a/src/res/drawable-hdpi/clock.png and /dev/null differ diff --git a/src/res/drawable-hdpi/delete.png b/src/res/drawable-hdpi/delete.png deleted file mode 100644 index 643de3e..0000000 Binary files a/src/res/drawable-hdpi/delete.png and /dev/null differ diff --git a/src/res/drawable-hdpi/dropdown_icon.9.png b/src/res/drawable-hdpi/dropdown_icon.9.png deleted file mode 100644 index 5525025..0000000 Binary files a/src/res/drawable-hdpi/dropdown_icon.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_blue.9.png b/src/res/drawable-hdpi/edit_blue.9.png deleted file mode 100644 index 55a1856..0000000 Binary files a/src/res/drawable-hdpi/edit_blue.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_green.9.png b/src/res/drawable-hdpi/edit_green.9.png deleted file mode 100644 index 2cb2d60..0000000 Binary files a/src/res/drawable-hdpi/edit_green.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_red.9.png b/src/res/drawable-hdpi/edit_red.9.png deleted file mode 100644 index bae944a..0000000 Binary files a/src/res/drawable-hdpi/edit_red.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_title_blue.9.png b/src/res/drawable-hdpi/edit_title_blue.9.png deleted file mode 100644 index 96e6092..0000000 Binary files a/src/res/drawable-hdpi/edit_title_blue.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_title_green.9.png b/src/res/drawable-hdpi/edit_title_green.9.png deleted file mode 100644 index 08d8644..0000000 Binary files a/src/res/drawable-hdpi/edit_title_green.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_title_red.9.png b/src/res/drawable-hdpi/edit_title_red.9.png deleted file mode 100644 index 9c430e5..0000000 Binary files a/src/res/drawable-hdpi/edit_title_red.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_title_white.9.png b/src/res/drawable-hdpi/edit_title_white.9.png deleted file mode 100644 index 19e8d95..0000000 Binary files a/src/res/drawable-hdpi/edit_title_white.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_title_yellow.9.png b/src/res/drawable-hdpi/edit_title_yellow.9.png deleted file mode 100644 index bf8f580..0000000 Binary files a/src/res/drawable-hdpi/edit_title_yellow.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_white.9.png b/src/res/drawable-hdpi/edit_white.9.png deleted file mode 100644 index 918f7a6..0000000 Binary files a/src/res/drawable-hdpi/edit_white.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/edit_yellow.9.png b/src/res/drawable-hdpi/edit_yellow.9.png deleted file mode 100644 index 10cb642..0000000 Binary files a/src/res/drawable-hdpi/edit_yellow.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/font_large.png b/src/res/drawable-hdpi/font_large.png deleted file mode 100644 index 78cf2e6..0000000 Binary files a/src/res/drawable-hdpi/font_large.png and /dev/null differ diff --git a/src/res/drawable-hdpi/font_normal.png b/src/res/drawable-hdpi/font_normal.png deleted file mode 100644 index 9de7ced..0000000 Binary files a/src/res/drawable-hdpi/font_normal.png and /dev/null differ diff --git a/src/res/drawable-hdpi/font_size_selector_bg.9.png b/src/res/drawable-hdpi/font_size_selector_bg.9.png deleted file mode 100644 index be8e64c..0000000 Binary files a/src/res/drawable-hdpi/font_size_selector_bg.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/font_small.png b/src/res/drawable-hdpi/font_small.png deleted file mode 100644 index d3ff104..0000000 Binary files a/src/res/drawable-hdpi/font_small.png and /dev/null differ diff --git a/src/res/drawable-hdpi/font_super.png b/src/res/drawable-hdpi/font_super.png deleted file mode 100644 index 85b13a1..0000000 Binary files a/src/res/drawable-hdpi/font_super.png and /dev/null differ diff --git a/src/res/drawable-hdpi/icon_app.png b/src/res/drawable-hdpi/icon_app.png deleted file mode 100644 index 418aadc..0000000 Binary files a/src/res/drawable-hdpi/icon_app.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_background.png b/src/res/drawable-hdpi/list_background.png deleted file mode 100644 index 087e1f9..0000000 Binary files a/src/res/drawable-hdpi/list_background.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_blue_down.9.png b/src/res/drawable-hdpi/list_blue_down.9.png deleted file mode 100644 index b88eebf..0000000 Binary files a/src/res/drawable-hdpi/list_blue_down.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_blue_middle.9.png b/src/res/drawable-hdpi/list_blue_middle.9.png deleted file mode 100644 index 96b1c8b..0000000 Binary files a/src/res/drawable-hdpi/list_blue_middle.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_blue_single.9.png b/src/res/drawable-hdpi/list_blue_single.9.png deleted file mode 100644 index d7e7206..0000000 Binary files a/src/res/drawable-hdpi/list_blue_single.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_blue_up.9.png b/src/res/drawable-hdpi/list_blue_up.9.png deleted file mode 100644 index 632e88c..0000000 Binary files a/src/res/drawable-hdpi/list_blue_up.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_folder.9.png b/src/res/drawable-hdpi/list_folder.9.png deleted file mode 100644 index 829f61b..0000000 Binary files a/src/res/drawable-hdpi/list_folder.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_footer_bg.9.png b/src/res/drawable-hdpi/list_footer_bg.9.png deleted file mode 100644 index 5325c25..0000000 Binary files a/src/res/drawable-hdpi/list_footer_bg.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_green_down.9.png b/src/res/drawable-hdpi/list_green_down.9.png deleted file mode 100644 index 64a39d9..0000000 Binary files a/src/res/drawable-hdpi/list_green_down.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_green_middle.9.png b/src/res/drawable-hdpi/list_green_middle.9.png deleted file mode 100644 index 897325a..0000000 Binary files a/src/res/drawable-hdpi/list_green_middle.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_green_single.9.png b/src/res/drawable-hdpi/list_green_single.9.png deleted file mode 100644 index c83405f..0000000 Binary files a/src/res/drawable-hdpi/list_green_single.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_green_up.9.png b/src/res/drawable-hdpi/list_green_up.9.png deleted file mode 100644 index 141f9e1..0000000 Binary files a/src/res/drawable-hdpi/list_green_up.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_red_down.9.png b/src/res/drawable-hdpi/list_red_down.9.png deleted file mode 100644 index 4224309..0000000 Binary files a/src/res/drawable-hdpi/list_red_down.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_red_middle.9.png b/src/res/drawable-hdpi/list_red_middle.9.png deleted file mode 100644 index 9988f17..0000000 Binary files a/src/res/drawable-hdpi/list_red_middle.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_red_single.9.png b/src/res/drawable-hdpi/list_red_single.9.png deleted file mode 100644 index 587c348..0000000 Binary files a/src/res/drawable-hdpi/list_red_single.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_red_up.9.png b/src/res/drawable-hdpi/list_red_up.9.png deleted file mode 100644 index 46b4757..0000000 Binary files a/src/res/drawable-hdpi/list_red_up.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_white_down.9.png b/src/res/drawable-hdpi/list_white_down.9.png deleted file mode 100644 index 29f9d8c..0000000 Binary files a/src/res/drawable-hdpi/list_white_down.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_white_middle.9.png b/src/res/drawable-hdpi/list_white_middle.9.png deleted file mode 100644 index 77a4ab4..0000000 Binary files a/src/res/drawable-hdpi/list_white_middle.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_white_single.9.png b/src/res/drawable-hdpi/list_white_single.9.png deleted file mode 100644 index 3e79189..0000000 Binary files a/src/res/drawable-hdpi/list_white_single.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_white_up.9.png b/src/res/drawable-hdpi/list_white_up.9.png deleted file mode 100644 index e23cd5c..0000000 Binary files a/src/res/drawable-hdpi/list_white_up.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_yellow_down.9.png b/src/res/drawable-hdpi/list_yellow_down.9.png deleted file mode 100644 index 31cfc1e..0000000 Binary files a/src/res/drawable-hdpi/list_yellow_down.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_yellow_middle.9.png b/src/res/drawable-hdpi/list_yellow_middle.9.png deleted file mode 100644 index b6549b2..0000000 Binary files a/src/res/drawable-hdpi/list_yellow_middle.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_yellow_single.9.png b/src/res/drawable-hdpi/list_yellow_single.9.png deleted file mode 100644 index 3faf507..0000000 Binary files a/src/res/drawable-hdpi/list_yellow_single.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/list_yellow_up.9.png b/src/res/drawable-hdpi/list_yellow_up.9.png deleted file mode 100644 index 4ae791c..0000000 Binary files a/src/res/drawable-hdpi/list_yellow_up.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/menu_delete.png b/src/res/drawable-hdpi/menu_delete.png deleted file mode 100644 index ccdfc4b..0000000 Binary files a/src/res/drawable-hdpi/menu_delete.png and /dev/null differ diff --git a/src/res/drawable-hdpi/menu_move.png b/src/res/drawable-hdpi/menu_move.png deleted file mode 100644 index 1140b71..0000000 Binary files a/src/res/drawable-hdpi/menu_move.png and /dev/null differ diff --git a/src/res/drawable-hdpi/new_note_normal.png b/src/res/drawable-hdpi/new_note_normal.png deleted file mode 100644 index e24e0d1..0000000 Binary files a/src/res/drawable-hdpi/new_note_normal.png and /dev/null differ diff --git a/src/res/drawable-hdpi/new_note_pressed.png b/src/res/drawable-hdpi/new_note_pressed.png deleted file mode 100644 index c748936..0000000 Binary files a/src/res/drawable-hdpi/new_note_pressed.png and /dev/null differ diff --git a/src/res/drawable-hdpi/note_edit_color_selector_panel.png b/src/res/drawable-hdpi/note_edit_color_selector_panel.png deleted file mode 100644 index fc49552..0000000 Binary files a/src/res/drawable-hdpi/note_edit_color_selector_panel.png and /dev/null differ diff --git a/src/res/drawable-hdpi/notification.png b/src/res/drawable-hdpi/notification.png deleted file mode 100644 index b13ab4a..0000000 Binary files a/src/res/drawable-hdpi/notification.png and /dev/null differ diff --git a/src/res/drawable-hdpi/search_result.png b/src/res/drawable-hdpi/search_result.png deleted file mode 100644 index ff2befd..0000000 Binary files a/src/res/drawable-hdpi/search_result.png and /dev/null differ diff --git a/src/res/drawable-hdpi/selected.png b/src/res/drawable-hdpi/selected.png deleted file mode 100644 index b889bef..0000000 Binary files a/src/res/drawable-hdpi/selected.png and /dev/null differ diff --git a/src/res/drawable-hdpi/title_alert.png b/src/res/drawable-hdpi/title_alert.png deleted file mode 100644 index 544ee9c..0000000 Binary files a/src/res/drawable-hdpi/title_alert.png and /dev/null differ diff --git a/src/res/drawable-hdpi/title_bar_bg.9.png b/src/res/drawable-hdpi/title_bar_bg.9.png deleted file mode 100644 index eb6bff0..0000000 Binary files a/src/res/drawable-hdpi/title_bar_bg.9.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_2x_blue.png b/src/res/drawable-hdpi/widget_2x_blue.png deleted file mode 100644 index a1707f4..0000000 Binary files a/src/res/drawable-hdpi/widget_2x_blue.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_2x_green.png b/src/res/drawable-hdpi/widget_2x_green.png deleted file mode 100644 index f86886c..0000000 Binary files a/src/res/drawable-hdpi/widget_2x_green.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_2x_red.png b/src/res/drawable-hdpi/widget_2x_red.png deleted file mode 100644 index 0e66c29..0000000 Binary files a/src/res/drawable-hdpi/widget_2x_red.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_2x_white.png b/src/res/drawable-hdpi/widget_2x_white.png deleted file mode 100644 index 5f0619a..0000000 Binary files a/src/res/drawable-hdpi/widget_2x_white.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_2x_yellow.png b/src/res/drawable-hdpi/widget_2x_yellow.png deleted file mode 100644 index 12d1c2b..0000000 Binary files a/src/res/drawable-hdpi/widget_2x_yellow.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_4x_blue.png b/src/res/drawable-hdpi/widget_4x_blue.png deleted file mode 100644 index 9183738..0000000 Binary files a/src/res/drawable-hdpi/widget_4x_blue.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_4x_green.png b/src/res/drawable-hdpi/widget_4x_green.png deleted file mode 100644 index fa8b452..0000000 Binary files a/src/res/drawable-hdpi/widget_4x_green.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_4x_red.png b/src/res/drawable-hdpi/widget_4x_red.png deleted file mode 100644 index 62de074..0000000 Binary files a/src/res/drawable-hdpi/widget_4x_red.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_4x_white.png b/src/res/drawable-hdpi/widget_4x_white.png deleted file mode 100644 index a37d67c..0000000 Binary files a/src/res/drawable-hdpi/widget_4x_white.png and /dev/null differ diff --git a/src/res/drawable-hdpi/widget_4x_yellow.png b/src/res/drawable-hdpi/widget_4x_yellow.png deleted file mode 100644 index d7c5fa4..0000000 Binary files a/src/res/drawable-hdpi/widget_4x_yellow.png and /dev/null differ diff --git a/src/res/drawable/new_note.xml b/src/res/drawable/new_note.xml deleted file mode 100644 index 2154ebc..0000000 --- a/src/res/drawable/new_note.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - diff --git a/src/res/layout/account_dialog_title.xml b/src/res/layout/account_dialog_title.xml deleted file mode 100644 index 7717112..0000000 --- a/src/res/layout/account_dialog_title.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/res/layout/add_account_text.xml b/src/res/layout/add_account_text.xml deleted file mode 100644 index c799178..0000000 --- a/src/res/layout/add_account_text.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/res/layout/datetime_picker.xml b/src/res/layout/datetime_picker.xml deleted file mode 100644 index f10d592..0000000 --- a/src/res/layout/datetime_picker.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/res/layout/dialog_edit_text.xml b/src/res/layout/dialog_edit_text.xml deleted file mode 100644 index 361b39a..0000000 --- a/src/res/layout/dialog_edit_text.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/res/layout/folder_list_item.xml b/src/res/layout/folder_list_item.xml deleted file mode 100644 index 77e8148..0000000 --- a/src/res/layout/folder_list_item.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/res/layout/note_edit.xml b/src/res/layout/note_edit.xml deleted file mode 100644 index 10b2aa7..0000000 --- a/src/res/layout/note_edit.xml +++ /dev/null @@ -1,400 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/res/layout/note_edit_list_item.xml b/src/res/layout/note_edit_list_item.xml deleted file mode 100644 index a885f9c..0000000 --- a/src/res/layout/note_edit_list_item.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - diff --git a/src/res/layout/note_item.xml b/src/res/layout/note_item.xml deleted file mode 100644 index d541f6a..0000000 --- a/src/res/layout/note_item.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/res/layout/note_list.xml b/src/res/layout/note_list.xml deleted file mode 100644 index 6b25d38..0000000 --- a/src/res/layout/note_list.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - -