diff --git a/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java b/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java index e3c2eb4..e52ad57 100644 --- a/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java +++ b/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java @@ -7,95 +7,98 @@ * * 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 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; - + +package net.micode.notes.ui; // 定义包名,表示该类文件位于net.micode.notes.ui这个包中 + +import java.util.Calendar; // 导入Java的Calendar类,用于操作日期和时间 + +import net.micode.notes.R; // 导入R资源文件,用于访问应用中的资源 +import net.micode.notes.ui.DateTimePicker; // 导入自定义的日期时间选择器控件 +import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; // 导入日期时间选择器控件的监听器接口 + +import android.app.AlertDialog; // 导入Android的AlertDialog类,用于创建对话框 +import android.content.Context; // 导入Android的Context类,用于访问系统资源 +import android.content.DialogInterface; // 导入Android的DialogInterface类,用于处理对话框中的按钮点击事件 +import android.content.DialogInterface.OnClickListener; // 导入DialogInterface的OnClickListener接口 +import android.text.format.DateFormat; // 导入Android的DateFormat工具类,用于格式化日期和时间 +import android.text.format.DateUtils; // 导入Android的DateUtils工具类,用于处理日期和时间相关的操作 + // 自定义的日期时间选择对话框,继承自AlertDialog并实现了OnClickListener接口 public class DateTimePickerDialog extends AlertDialog implements OnClickListener { - + // 存储当前选择的日期时间 - private Calendar mDate = Calendar.getInstance(); + private Calendar mDate = Calendar.getInstance(); // 创建一个Calendar实例,初始化为当前时间 + // 是否使用24小时制 - private boolean mIs24HourView; + private boolean mIs24HourView; // 布尔变量,用于判断是否使用24小时制显示时间 + // 回调接口,当日期时间设置完成后调用 - private OnDateTimeSetListener mOnDateTimeSetListener; + private OnDateTimeSetListener mOnDateTimeSetListener; // 定义一个回调接口,当用户选择好日期时间后进行回调 + // 日期时间选择器控件 - private DateTimePicker mDateTimePicker; - + private DateTimePicker mDateTimePicker; // 定义一个日期时间选择器控件实例,用于在对话框中选择日期时间 + // 定义日期时间设置完成后的回调接口 public interface OnDateTimeSetListener { - void OnDateTimeSet(AlertDialog dialog, long date); + void OnDateTimeSet(AlertDialog dialog, long date); // 定义回调方法,传入当前对话框和选择的日期时间(long类型) } - + // 构造函数,初始化对话框并设置初始日期时间 public DateTimePickerDialog(Context context, long date) { - super(context); - mDateTimePicker = new DateTimePicker(context); - setView(mDateTimePicker); - mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { - public void onDateTimeChanged(DateTimePicker view, int year, int month, + super(context); // 调用父类AlertDialog的构造函数,传入上下文环境 + 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) { - 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.set(Calendar.YEAR, year); // 更新mDate中的年份为选择的年份 + mDate.set(Calendar.MONTH, month); // 更新mDate中的月份为选择的月份 + mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); // 更新mDate中的日期为选择的日期 + mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); // 更新mDate中的小时为选择的小时 + mDate.set(Calendar.MINUTE, minute); // 更新mDate中的分钟为选择的分钟 + mDate.set(Calendar.SECOND, 0); // 将秒设置为0,忽略秒的选择 + updateTitle(mDate.getTimeInMillis()); // 更新对话框标题,显示当前选择的日期时间 } }); - 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); - set24HourView(DateFormat.is24HourFormat(this.getContext())); - updateTitle(mDate.getTimeInMillis()); + mDate.setTimeInMillis(date); // 将mDate设置为传入的初始日期时间 + mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); // 将日期时间选择器控件的当前日期时间设置为传入的初始日期时间 + setButton(context.getString(R.string.datetime_dialog_ok), this); // 设置确认按钮,按钮文本为资源文件中的"datetime_dialog_ok"定义的文本,点击事件为当前类 + setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); // 设置取消按钮,按钮文本为资源文件中的"datetime_dialog_cancel"定义的文本,点击事件为空 + set24HourView(DateFormat.is24HourFormat(this.getContext())); // 根据系统设置判断是否使用24小时制显示时间 + updateTitle(mDate.getTimeInMillis()); // 更新对话框标题,显示初始选择的日期时间 } - + // 设置是否使用24小时制显示时间 public void set24HourView(boolean is24HourView) { - mIs24HourView = is24HourView; + mIs24HourView = is24HourView; // 更新是否使用24小时制的布尔值 } - + // 设置日期时间选择完成后的回调监听器 public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { - mOnDateTimeSetListener = callBack; + mOnDateTimeSetListener = callBack; // 设置回调监听器为传入的参数 } - + // 更新对话框的标题以显示当前选择的日期时间 private void updateTitle(long date) { int flag = - 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)); + DateUtils.FORMAT_SHOW_YEAR | // 格式化标志,显示年份 + DateUtils.FORMAT_SHOW_DATE | // 格式化标志,显示日期 + DateUtils.FORMAT_SHOW_TIME; // 格式化标志,显示时间 + flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_12HOUR; // 根据是否使用24小时制添加相应的格式化标志 + setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); // 使用DateUtils.formatDateTime方法格式化日期时间,并设置为对话框的标题 } - + // 处理用户点击对话框按钮的事件,如果是确认按钮则调用回调监听器 public void onClick(DialogInterface arg0, int arg1) { - if (mOnDateTimeSetListener != null) { - mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); + if (mOnDateTimeSetListener != null) { // 检查回调监听器是否为空 + mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); // 调用回调监听器的OnDateTimeSet方法,传入当前对话框和选择的日期时间 } } - -} \ No newline at end of file + +} diff --git a/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java b/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java index 3e45406..c2e2ab6 100644 --- a/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java +++ b/Notes-master/src/net/micode/notes/ui/NoteEditActivity.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.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,591 +64,646 @@ 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; - + // 笔记编辑界面的Activity类 public class NoteEditActivity extends Activity implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener { // 用于存储笔记头部视图的ViewHolder类 private class HeadViewHolder { - public TextView tvModified; - - public ImageView ivAlertIcon; - - public TextView tvAlertDate; - - public ImageView ibSetBgColor; - } - + public TextView tvModified; // 显示笔记修改日期的TextView + + public ImageView ivAlertIcon; // 显示提醒图标的ImageView + + public TextView tvAlertDate; // 显示提醒日期的TextView + + public ImageView ibSetBgColor; // 设置背景颜色的按钮 + } + // 背景色选择按钮和颜色ID的映射 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); + sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); // 黄色按钮对应的颜色ID + sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); // 红色按钮对应的颜色ID + sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); // 蓝色按钮对应的颜色ID + sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); // 绿色按钮对应的颜色ID + sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); // 白色按钮对应的颜色ID } - + // 背景色选择后的显示标记和颜色ID的映射 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); + sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); // 黄色选择标记对应的ID + sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select); // 红色选择标记对应的ID + sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); // 蓝色选择标记对应的ID + sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); // 绿色选择标记对应的ID + sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); // 白色选择标记对应的ID } - + // 字体大小选择按钮和字体大小ID的映射 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); + sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); // 大字体按钮对应的字体ID + sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); // 小字体按钮对应的字体ID + sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); // 中字体按钮对应的字体ID + sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); // 超大字体按钮对应的字体ID } - + // 字体大小选择后的显示标记和字体大小ID的映射 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; - - 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; - + sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); // 大字体选择标记对应的ID + sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); // 小字体选择标记对应的ID + sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); // 中字体选择标记对应的ID + sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); // 超大字体选择标记对应的ID + } + + 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; // 共享preferences对象,用于存储用户偏好设置 + 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; // 存储多个NoteEditText的LinearLayout + + private String mUserQuery; // 用户搜索查询的字符串 + private Pattern mPattern; // 用于匹配查询字符串的正则表达式模式 + // 初始化Activity视图 @Override protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - this.setContentView(R.layout.note_edit); - + super.onCreate(savedInstanceState); // 永远调用父类的onCreate方法 + this.setContentView(R.layout.note_edit); // 设置布局文件为note_edit.xml + + // 如果是首次创建且initActivityState失败,则直接关闭Activity if (savedInstanceState == null && !initActivityState(getIntent())) { finish(); return; } - initResources(); + initResources(); // 初始化视图资源 } - + // 当Activity被系统杀死后,恢复其状态 @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); + super.onRestoreInstanceState(savedInstanceState); // 永远调用父类的onRestoreInstanceState方法 + // 如果savedInstanceState不为空且包含Intent.EXTRA_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)); if (!initActivityState(intent)) { - finish(); + finish(); // 如果initActivityState失败,则关闭Activity return; } - Log.d(TAG, "Restoring from killed activity"); + Log.d(TAG, "Restoring from killed activity"); // 记录日志 } } - + // 初始化Activity状态,根据Intent决定加载笔记或创建新笔记 private boolean initActivityState(Intent intent) { - mWorkingNote = null; + mWorkingNote = null; // 初始化笔记对象为null + // 如果Intent动作是ACTION_VIEW,则加载指定笔记 if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { - long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); - mUserQuery = ""; - + long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); // 获取笔记ID + mUserQuery = ""; // 初始化用户查询字符串为空 + + // 如果Intent包含SearchManager.EXTRA_DATA_KEY,则从搜索结果中加载笔记 if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { - noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); - mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); + noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); // 获取笔记ID + mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); // 获取用户查询字符串 } - + + // 检查笔记是否存在 if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { + // 如果笔记不存在,则跳转到笔记列表界面,并显示错误信息 Intent jump = new Intent(this, NotesListActivity.class); startActivity(jump); showToast(R.string.error_note_not_exist); finish(); return false; } else { - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { + mWorkingNote = WorkingNote.load(this, noteId); // 加载指定笔记 + if (mWorkingNote == null) { // 如果加载失败,则显示错误信息并关闭Activity Log.e(TAG, "load note failed with note id" + noteId); finish(); 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())) { - long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); + } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { // 如果Intent动作是ACTION_INSERT_OR_EDIT,则创建新笔记或编辑现有笔记 + long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); // 获取文件夹ID int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID); + AppWidgetManager.INVALID_APPWIDGET_ID); // 获取小部件ID int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, - Notes.TYPE_WIDGET_INVALIDE); + Notes.TYPE_WIDGET_INVALIDE); // 获取小部件类型 int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, - ResourceParser.getDefaultBgId(this)); - - String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); - long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); - if (callDate != 0 && phoneNumber != null) { + ResourceParser.getDefaultBgId(this)); // 获取背景颜色资源ID + + String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); // 获取电话号码(对于通话记录笔记) + long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); // 获取通话日期(对于通话记录笔记) + if (callDate != 0 && phoneNumber != null) { // 如果通话日期和电话号码都存在,则尝试加载通话记录笔记 if (TextUtils.isEmpty(phoneNumber)) { - Log.w(TAG, "The call record number is null"); + Log.w(TAG, "The call record number is null"); // 日志警告 } long noteId = 0; + // 根据电话号码和通话日期查找笔记ID if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(), phoneNumber, callDate)) > 0) { - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { + mWorkingNote = WorkingNote.load(this, noteId); // 加载指定笔记 + if (mWorkingNote == null) { // 如果加载失败,则显示错误信息并关闭Activity Log.e(TAG, "load call note failed with note id" + noteId); finish(); return false; } - } else { + } else { // 如果笔记不存在,则创建新笔记并转换为通话记录笔记 mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, bgResId); mWorkingNote.convertToCallNote(phoneNumber, callDate); } - } else { + } else { // 如果通话日期或电话号码不存在,则创建新笔记 mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, bgResId); } - + + // 设置软键盘输入模式:调整布局大小,显示软键盘 getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - } else { + } else { // 如果Intent动作不支持,则显示错误信息并关闭Activity Log.e(TAG, "Intent not specified action, should not support"); finish(); return false; } - mWorkingNote.setOnSettingStatusChangedListener(this); - return true; + mWorkingNote.setOnSettingStatusChangedListener(this); // 设置笔记配置变化监听器 + return true; // 返回true表示初始化成功 } - + // Activity恢复时初始化笔记显示 @Override protected void onResume() { - super.onResume(); - initNoteScreen(); + super.onResume(); // 永远调用父类的onResume方法 + initNoteScreen(); // 初始化笔记显示界面 } - + // 初始化笔记显示界面,包括背景颜色、字体大小、修改日期等 private void initNoteScreen() { + // 设置编辑框的文本外观为当前选择的字体大小 mNoteEditor.setTextAppearance(this, TextAppearanceResources .getTexAppearanceResource(mFontSizeId)); + // 如果笔记处于检查列表模式,则显示为检查列表,否则高亮显示搜索关键词 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - switchToListMode(mWorkingNote.getContent()); + switchToListMode(mWorkingNote.getContent()); // 切换到列表模式 } else { - mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); - mNoteEditor.setSelection(mNoteEditor.getText().length()); + 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)); - - showAlertHeader(); - } - + + // 设置修改日期文本 + mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(this, // 格式化日期时间 + mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE // 显示日期 + | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME // 显示数字日期、时间 + | DateUtils.FORMAT_SHOW_YEAR)); // 显示年份 + + showAlertHeader(); // 显示或隐藏提醒头部信息 + } + // 显示或隐藏提醒头部信息 private void showAlertHeader() { + // 如果笔记设置了警报 if (mWorkingNote.hasClockAlert()) { - long time = System.currentTimeMillis(); + long time = System.currentTimeMillis(); // 获取当前时间 + // 如果当前时间大于警报时间,则显示警报已过期,否则显示相对时间 if (time > mWorkingNote.getAlertDate()) { mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); } else { - mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( + 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.VISIBLE); // 显示警报日期 + mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); // 显示警报图标 + } else { // 如果笔记未设置警报,则隐藏警报日期和图标 mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); }; } - + // 处理新的Intent,可能需要重新加载笔记或创建新笔记 @Override protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - initActivityState(intent); + super.onNewIntent(intent); // 永远调用父类的onNewIntent方法 + initActivityState(intent); // 初始化Activity状态 } - + // 保存Activity状态,在系统需要恢复Activity时使用 @Override protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); + super.onSaveInstanceState(outState); // 永远调用父类的onSaveInstanceState方法 + // 如果笔记不存在于数据库中,则保存笔记 if (!mWorkingNote.existInDatabase()) { saveNote(); } - outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); - Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); + outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); // 保存笔记ID + Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); // 记录日志 } - + // 处理触摸事件,用于隐藏颜色和字体大小选择面板 @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); + return super.dispatchTouchEvent(ev); // 其他情况,调用父类的方法 } - + // 判断触摸事件是否发生在指定视图内 private boolean inRangeOfView(View view, MotionEvent ev) { int []location = new int[2]; - view.getLocationOnScreen(location); - int x = location[0]; - int y = location[1]; + view.getLocationOnScreen(location); // 获取视图在屏幕上的位置 + int x = location[0]; // 获取视图左上角x坐标 + int y = location[1]; // 获取视图左上角y坐标 + // 判断触摸点是否在视图范围内 if (ev.getX() < x - || ev.getX() > (x + view.getWidth()) + || ev.getX() > (x + view.getWidth()) // 触摸点x坐标小于视图左边界或大于视图右边界 || ev.getY() < y - || ev.getY() > (y + view.getHeight())) { - return false; + || ev.getY() > (y + view.getHeight())) { // 触摸点y坐标小于视图上边界或大于视图下边界 + return false; // 返回false表示触摸点不在视图范围内 } - return true; + return true; // 返回true表示触摸点在视图范围内 } - + // 初始化视图资源 private void initResources() { - mHeadViewPanel = findViewById(R.id.note_title); - mNoteHeaderHolder = new HeadViewHolder(); - mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); - mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); - 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()) { + mHeadViewPanel = findViewById(R.id.note_title); // 获取头部视图面板 + mNoteHeaderHolder = new HeadViewHolder(); // 创建ViewHolder对象 + mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); // 获取修改日期TextView + mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); // 获取警报图标ImageView + mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); // 获取警报日期TextView + 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()) { + + 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); + mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); // 获取默认SharedPreferences对象 + mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE); // 获取用户选择的字体大小ID + // 如果字体大小ID超出范围,则使用默认字体大小 if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; } - mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); + mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); // 获取NoteEditText列表 } - + // 暂停Activity时保存笔记并清理设置状态 @Override protected void onPause() { - super.onPause(); + super.onPause(); // 永远调用父类的onPause方法 + // 保存笔记内容到数据库,如果成功则记录日志 if(saveNote()) { Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); } - clearSettingState(); + clearSettingState(); // 清理设置状态(隐藏颜色和字体大小选择面板) } - + // 更新桌面小部件显示 private void updateWidget() { - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); + Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); // 创建更新小部件的Intent + // 根据小部件类型设置Intent的类 if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { intent.setClass(this, NoteWidgetProvider_2x.class); } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { intent.setClass(this, NoteWidgetProvider_4x.class); } else { - Log.e(TAG, "Unspported widget type"); + Log.e(TAG, "Unspported widget type"); // 日志错误 return; } - - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { + + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { // 添加小部件ID mWorkingNote.getWidgetId() }); - - sendBroadcast(intent); - setResult(RESULT_OK, intent); + + sendBroadcast(intent); // 发送广播更新小部件 + setResult(RESULT_OK, intent); // 设置Activity结果 } - + // 处理视图点击事件,包括颜色和字体大小选择 public void onClick(View v) { - int id = v.getId(); + int id = v.getId(); // 获取点击视图的ID + // 如果点击的是设置背景颜色按钮,则显示背景颜色选择面板 if (id == R.id.btn_set_bg_color) { mNoteBgColorSelector.setVisibility(View.VISIBLE); + // 显示当前选择的背景颜色标记 findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); - } else if (sBgSelectorBtnsMap.containsKey(id)) { + } else if (sBgSelectorBtnsMap.containsKey(id)) { // 如果点击的是背景颜色选择按钮 + // 隐藏之前选择的背景颜色标记 findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.GONE); - mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); - mNoteBgColorSelector.setVisibility(View.GONE); - } else if (sFontSizeBtnsMap.containsKey(id)) { + mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); // 设置新的背景颜色ID + mNoteBgColorSelector.setVisibility(View.GONE); // 隐藏背景颜色选择面板 + } else if (sFontSizeBtnsMap.containsKey(id)) { // 如果点击的是字体大小选择按钮 + // 隐藏之前选择的字体大小标记 findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); - mFontSizeId = sFontSizeBtnsMap.get(id); + mFontSizeId = sFontSizeBtnsMap.get(id); // 设置新的字体大小ID + // 将新的字体大小ID保存到SharedPreferences中 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()); + getWorkingText(); // 获取正在编辑的文本内容 + switchToListMode(mWorkingNote.getContent()); // 切换到列表模式 } else { - mNoteEditor.setTextAppearance(this, + mNoteEditor.setTextAppearance(this, // 设置文本外观 TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); } - mFontSizeSelector.setVisibility(View.GONE); + mFontSizeSelector.setVisibility(View.GONE); // 隐藏字体大小选择面板 } } - + // 处理返回键事件,如果设置面板可见则隐藏,否则保存笔记后返回 @Override public void onBackPressed() { + // 如果设置面板可见,则隐藏并返回 if(clearSettingState()) { return; } - - saveNote(); - super.onBackPressed(); + + saveNote(); // 保存笔记内容到数据库 + super.onBackPressed(); // 调用父类的onBackPressed方法 } - + // 清理设置面板状态 private boolean clearSettingState() { + // 如果背景颜色选择面板可见,则隐藏并返回true if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { mNoteBgColorSelector.setVisibility(View.GONE); return true; - } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { + } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { // 如果字体大小选择面板可见,则隐藏并返回true mFontSizeSelector.setVisibility(View.GONE); return true; } - return false; + return false; // 如果两个面板都不可见,则返回false } - + // 处理笔记背景颜色变化事件 public void onBackgroundColorChanged() { + // 显示当前选择的背景颜色标记 findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); + // 设置编辑框面板的背景颜色 mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); + // 设置头部视图面板的背景颜色 mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); } - + // 准备选项菜单,根据笔记状态动态更新菜单项 @Override public boolean onPrepareOptionsMenu(Menu menu) { - if (isFinishing()) { + if (isFinishing()) { // 如果Activity正在结束,则返回true return true; } - clearSettingState(); - menu.clear(); + clearSettingState(); // 清理设置面板状态 + menu.clear(); // 清空菜单项 + // 根据笔记所在的文件夹ID动态更新菜单项 if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { - getMenuInflater().inflate(R.menu.call_note_edit, menu); + getMenuInflater().inflate(R.menu.call_note_edit, menu); // 加载通话记录笔记编辑菜单 } else { - getMenuInflater().inflate(R.menu.note_edit, menu); + 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); + 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); + menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); // 设置为列表模式 } + // 根据笔记是否设置了警报动态更新菜单项可见性 if (mWorkingNote.hasClockAlert()) { - menu.findItem(R.id.menu_alert).setVisible(false); + menu.findItem(R.id.menu_alert).setVisible(false); // 隐藏设置警报菜单项 } else { - menu.findItem(R.id.menu_delete_remind).setVisible(false); + menu.findItem(R.id.menu_delete_remind).setVisible(false); // 隐藏删除警报菜单项 } - return true; + return true; // 返回true表示菜单项已准备好 } - + // 处理选项菜单项点击事件 @Override public boolean onOptionsItemSelected(MenuItem item) { + // 根据菜单项ID执行相应操作 switch (item.getItemId()) { case R.id.menu_new_note: - createNewNote(); + 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); - builder.setMessage(getString(R.string.alert_message_delete_note)); - builder.setPositiveButton(android.R.string.ok, + AlertDialog.Builder builder = new AlertDialog.Builder(this); // 创建AlertDialog.Builder对象 + builder.setTitle(getString(R.string.alert_title_delete)); // 设置提示标题 + builder.setIcon(android.R.drawable.ic_dialog_alert); // 设置提示图标 + builder.setMessage(getString(R.string.alert_message_delete_note)); // 设置提示信息 + builder.setPositiveButton(android.R.string.ok, // 设置确定按钮 new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - deleteCurrentNote(); - finish(); + deleteCurrentNote(); // 删除当前笔记 + finish(); // 关闭Activity } }); - builder.setNegativeButton(android.R.string.cancel, null); - builder.show(); + builder.setNegativeButton(android.R.string.cancel, null); // 设置取消按钮 + builder.show(); // 显示对话框 break; case R.id.menu_font_size: - mFontSizeSelector.setVisibility(View.VISIBLE); + 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()); + getWorkingText(); // 获取正在编辑的文本内容 + sendTo(this, mWorkingNote.getContent()); // 分享笔记内容 break; case R.id.menu_send_to_desktop: - sendToDesktop(); + sendToDesktop(); // 将笔记添加到桌面 break; case R.id.menu_alert: - setReminder(); + setReminder(); // 设置提醒时间 break; case R.id.menu_delete_remind: - mWorkingNote.setAlertDate(0, false); + mWorkingNote.setAlertDate(0, false); // 删除提醒时间 break; default: - break; + break; // 默认情况,不做任何操作 } - return true; + return true; // 返回true表示菜单项点击事件已处理 } - + // 设置提醒时间 private void setReminder() { + // 创建DateTimePickerDialog对象,设置初始时间为当前时间 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(); + d.show(); // 显示日期时间选择对话框 } - + // 分享笔记内容到支持ACTION_SEND的其他应用 private void sendTo(Context context, String info) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_TEXT, info); - intent.setType("text/plain"); - context.startActivity(intent); + Intent intent = new Intent(Intent.ACTION_SEND); // 创建ACTION_SEND Intent + intent.putExtra(Intent.EXTRA_TEXT, info); // 添加文本内容 + intent.setType("text/plain"); // 设置类型为纯文本 + context.startActivity(intent); // 启动Intent } - + // 创建新笔记,跳转到新笔记编辑界面 private void createNewNote() { - saveNote(); - - 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); - } - + saveNote(); // 保存当前笔记内容 + + finish(); // 关闭当前Activity + Intent intent = new Intent(this, NoteEditActivity.class); // 创建新笔记编辑Activity的Intent + intent.setAction(Intent.ACTION_INSERT_OR_EDIT); // 设置Intent动作为插入或编辑笔记 + intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); // 添加文件夹ID + startActivity(intent); // 启动新笔记编辑Activity + } + // 删除当前笔记 private void deleteCurrentNote() { + // 如果笔记存在于数据库中 if (mWorkingNote.existInDatabase()) { HashSet ids = new HashSet(); - long id = mWorkingNote.getNoteId(); + long id = mWorkingNote.getNoteId(); // 获取笔记ID + // 如果笔记ID不是根文件夹ID,则添加到要删除的ID集合中 if (id != Notes.ID_ROOT_FOLDER) { ids.add(id); } else { - Log.d(TAG, "Wrong note id, should not happen"); + Log.d(TAG, "Wrong note id, should not happen"); // 日志错误 } + // 根据是否处于同步模式决定删除或移动到回收站 if (!isSyncMode()) { - if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { - Log.e(TAG, "Delete Note error"); + 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"); + if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { // 批量移动到回收站 + Log.e(TAG, "Move notes to trash folder error, should not happens"); // 日志错误 } } } - mWorkingNote.markDeleted(true); + mWorkingNote.markDeleted(true); // 标记笔记已删除 } - + // 判断是否处于同步模式 private boolean isSyncMode() { + // 获取同步账户名称,如果非空则返回true,否则返回false return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } - + // 处理时钟提醒变化事件,设置或取消提醒 public void onClockAlertChanged(long date, boolean set) { + // 如果笔记不存在于数据库中,则保存笔记 if (!mWorkingNote.existInDatabase()) { saveNote(); } + // 如果笔记ID大于0 if (mWorkingNote.getNoteId() > 0) { - Intent intent = new Intent(this, AlarmReceiver.class); + Intent intent = new Intent(this, AlarmReceiver.class); // 创建AlarmReceiver Intent + // 添加笔记URI到Intent intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); + // 创建PendingIntent对象 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); - AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); - showAlertHeader(); + AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); // 获取AlarmManager对象 + showAlertHeader(); // 显示或隐藏提醒头部信息 + // 如果设置为取消提醒,则取消Alarm;否则设置新的Alarm if(!set) { alarmManager.cancel(pendingIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); } - } else { + } else { // 如果笔记ID无效,则显示错误信息 Log.e(TAG, "Clock alert setting error"); showToast(R.string.error_note_empty_for_clock); } } - + // 处理小部件变化事件,更新小部件显示 public void onWidgetChanged() { - updateWidget(); + updateWidget(); // 更新小部件显示 } - + // 处理EditText删除事件,调整列表项索引 public void onEditTextDelete(int index, String text) { - int childCount = mEditTextList.getChildCount(); + int childCount = mEditTextList.getChildCount(); // 获取NoteEditText子视图数量 + // 如果只有一个NoteEditText,则不做任何操作 if (childCount == 1) { return; } - + + // 调整删除位置之后的NoteEditText索引 for (int i = index + 1; i < childCount; i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) .setIndex(i - 1); } - - mEditTextList.removeViewAt(index); + + mEditTextList.removeViewAt(index); // 删除指定位置的NoteEditText NoteEditText edit = null; + // 根据删除位置获取新的NoteEditText对象 if(index == 0) { edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( R.id.et_edit_text); @@ -656,200 +711,219 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( R.id.et_edit_text); } - int length = edit.length(); - edit.append(text); - edit.requestFocus(); - edit.setSelection(length); + int length = edit.length(); // 获取NoteEditText的文本长度 + edit.append(text); // 将删除的文本追加到新的NoteEditText对象中 + edit.requestFocus(); // 设置焦点到新的NoteEditText对象 + edit.setSelection(length); // 设置光标位置到追加文本之前 } - + // 处理EditText输入事件,添加新列表项 public void onEditTextEnter(int index, String text) { + // 如果索引超出范围,则记录错误日志 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); - edit.requestFocus(); - edit.setSelection(0); + + View view = getListItem(text, index); // 创建新的NoteEditText视图 + mEditTextList.addView(view, index); // 将新的视图添加到指定位置 + NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); // 获取NoteEditText对象 + edit.requestFocus(); // 设置焦点到新的NoteEditText对象 + edit.setSelection(0); // 设置光标位置到文本开头 + // 调整新添加NoteEditText之后的NoteEditText索引 for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) .setIndex(i); } } - + // 切换到列表模式,根据笔记内容生成列表项 private void switchToListMode(String text) { - mEditTextList.removeAllViews(); - String[] items = text.split("\n"); + mEditTextList.removeAllViews(); // 移除所有NoteEditText视图 + String[] items = text.split("\n"); // 将笔记内容按换行符分割成多个项 int index = 0; + // 遍历每一项,创建并添加NoteEditText视图 for (String item : items) { - if(!TextUtils.isEmpty(item)) { - mEditTextList.addView(getListItem(item, index)); - index++; + if(!TextUtils.isEmpty(item)) { // 如果项不为空 + mEditTextList.addView(getListItem(item, index)); // 添加NoteEditText视图 + index++; // 索引加1 } } - mEditTextList.addView(getListItem("", index)); + mEditTextList.addView(getListItem("", index)); // 添加一个空的NoteEditText视图 + // 设置焦点到新添加的NoteEditText对象 mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); - - mNoteEditor.setVisibility(View.GONE); - mEditTextList.setVisibility(View.VISIBLE); + + mNoteEditor.setVisibility(View.GONE); // 隐藏编辑框 + mEditTextList.setVisibility(View.VISIBLE); // 显示NoteEditText列表 } - + // 获取高亮查询结果,用于显示搜索关键词 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); + SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); // 创建SpannableString对象 + if (!TextUtils.isEmpty(userQuery)) { // 如果用户查询字符串不为空 + mPattern = Pattern.compile(userQuery); // 编译正则表达式模式 + Matcher m = mPattern.matcher(fullText); // 创建Matcher对象 int start = 0; + // 遍历匹配结果,为搜索关键词添加背景颜色标记 while (m.find(start)) { spannable.setSpan( new BackgroundColorSpan(this.getResources().getColor( - R.color.user_query_highlight)), m.start(), m.end(), + R.color.user_query_highlight)), m.start(), m.end(), // 设置背景颜色标记 Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start = m.end(); } } - return spannable; + return spannable; // 返回高亮搜索结果 } - + // 生成一个新的列表项视图 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)); + View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); // 创建NoteEditText视图 + final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); // 获取NoteEditText对象 + edit.setTextAppearance(this, // 设置文本外观 + TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); + CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); // 获取CheckBox对象 + // 设置CheckBox的点击监听器 cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { - edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); // 设置文本划线 } else { - edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); + edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); // 清除文本划线 } } }); - + + // 根据项内容设置CheckBox状态 if (item.startsWith(TAG_CHECKED)) { - cb.setChecked(true); - edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - item = item.substring(TAG_CHECKED.length(), item.length()).trim(); + cb.setChecked(true); // 设置CheckBox为勾选状态 + edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); // 设置文本划线 + item = item.substring(TAG_CHECKED.length(), item.length()).trim(); // 去掉勾选标签 } else if (item.startsWith(TAG_UNCHECKED)) { - cb.setChecked(false); - edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); - item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); + cb.setChecked(false); // 设置CheckBox为未勾选状态 + 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; + + edit.setOnTextViewChangeListener(this); // 设置文本变化监听器 + edit.setIndex(index); // 设置索引 + edit.setText(getHighlightQueryResult(item, mUserQuery)); // 设置文本并高亮搜索关键词 + return view; // 返回生成的NoteEditText视图 } - + // 处理EditText文本变化事件,显示或隐藏复选框 public void onTextChange(int index, boolean hasText) { + // 如果索引超出范围,则记录错误日志 if (index >= mEditTextList.getChildCount()) { Log.e(TAG, "Wrong index, should not happen"); return; } + // 根据文本内容显示或隐藏CheckBox 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); } } - + // 处理笔记模式变化事件,从普通模式切换到列表模式或反之 public void onCheckListModeChanged(int oldMode, int newMode) { + // 如果新模式是检查列表模式,则切换到列表模式 if (newMode == TextNote.MODE_CHECK_LIST) { switchToListMode(mNoteEditor.getText().toString()); - } else { + } else { // 如果新模式不是检查列表模式,则切换到普通模式 + // 如果不是检查列表模式,则从内容中移除检查列表标签 if (!getWorkingText()) { mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", "")); } - mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); - mEditTextList.setVisibility(View.GONE); - mNoteEditor.setVisibility(View.VISIBLE); + mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); // 设置编辑框文本并高亮搜索关键词 + mEditTextList.setVisibility(View.GONE); // 隐藏NoteEditText列表 + mNoteEditor.setVisibility(View.VISIBLE); // 显示编辑框 } } - + // 获取正在编辑的文本内容,根据列表模式添加标签 private boolean getWorkingText() { - boolean hasChecked = false; + boolean hasChecked = false; // 是否有勾选项 + // 如果笔记处于检查列表模式,则从列表项中获取文本内容,并添加标签 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { StringBuilder sb = new StringBuilder(); + // 遍历NoteEditText列表项 for (int i = 0; i < mEditTextList.getChildCount(); i++) { - View view = mEditTextList.getChildAt(i); - NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + View view = mEditTextList.getChildAt(i); // 获取NoteEditText视图 + NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); // 获取NoteEditText对象 + // 如果NoteEditText文本不为空,则根据CheckBox状态添加标签 if (!TextUtils.isEmpty(edit.getText())) { + // 如果CheckBox被勾选,则添加勾选标签,并设置文本划线 if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); hasChecked = true; - } else { + } else { // 如果CheckBox未被勾选,则添加未勾选标签 sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n"); } } } - mWorkingNote.setWorkingText(sb.toString()); - } else { + mWorkingNote.setWorkingText(sb.toString()); // 设置正在编辑的文本内容 + } else { // 如果笔记不是检查列表模式,则直接设置文本内容 mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); } - return hasChecked; + return hasChecked; // 返回是否有勾选项 } - + // 保存笔记内容到数据库 private boolean saveNote() { - getWorkingText(); - boolean saved = mWorkingNote.saveNote(); - if (saved) { + getWorkingText(); // 获取正在编辑的文本内容 + boolean saved = mWorkingNote.saveNote(); // 保存笔记 + if (saved) { // 如果保存成功,则设置Activity结果为RESULT_OK setResult(RESULT_OK); } - return saved; + return saved; // 返回保存结果 } - + // 将笔记快捷方式添加到桌面 private void sendToDesktop() { + // 如果笔记不存在于数据库中,则保存笔记 if (!mWorkingNote.existInDatabase()) { saveNote(); } - + + // 如果笔记ID大于0 if (mWorkingNote.getNoteId() > 0) { - Intent sender = new Intent(); - Intent shortcutIntent = new Intent(this, NoteEditActivity.class); - shortcutIntent.setAction(Intent.ACTION_VIEW); - shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); - sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, + Intent sender = new Intent(); // 创建Intent对象 + Intent shortcutIntent = new Intent(this, NoteEditActivity.class); // 创建快捷方式Intent + shortcutIntent.setAction(Intent.ACTION_VIEW); // 设置Intent动作为ACTION_VIEW + shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); // 添加笔记ID + sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); // 添加快捷方式Intent + sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, // 设置快捷方式名称 makeShortcutIconTitle(mWorkingNote.getContent())); - sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, // 添加快捷方式图标 Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app)); - sender.putExtra("duplicate", true); - sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); - showToast(R.string.info_note_enter_desktop); - sendBroadcast(sender); - } else { + sender.putExtra("duplicate", true); // 允许创建重复快捷方式 + sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); // 设置Intent动作为安装快捷方式 + showToast(R.string.info_note_enter_desktop); // 显示提示信息 + sendBroadcast(sender); // 发送安装快捷方式的广播 + } else { // 如果笔记ID无效,则显示错误信息 Log.e(TAG, "Send to desktop error"); showToast(R.string.error_note_empty_for_send_to_desktop); } } - + // 生成桌面快捷方式的标题,截取笔记内容的一部分作为标题 private String makeShortcutIconTitle(String content) { - content = content.replace(TAG_CHECKED, ""); - content = content.replace(TAG_UNCHECKED, ""); + content = content.replace(TAG_CHECKED, ""); // 移除勾选标签 + content = content.replace(TAG_UNCHECKED, ""); // 移除未勾选标签 + // 如果内容长度大于最大长度,则截取前10个字符作为标题;否则直接使用内容作为标题 return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, SHORTCUT_ICON_TITLE_MAX_LEN) : content; } - + // 显示短Toast消息 private void showToast(int resId) { - showToast(resId, Toast.LENGTH_SHORT); + showToast(resId, Toast.LENGTH_SHORT); // 调用另一个showToast方法,设置Toast显示时间为短时间 } - + // 显示指定持续时间的Toast消息 private void showToast(int resId, int duration) { - Toast.makeText(this, resId, duration).show(); + Toast.makeText(this, resId, duration).show(); // 显示Toast消息 } -} \ No newline at end of file +} diff --git a/Notes-master/src/net/micode/notes/ui/NoteEditText.java b/Notes-master/src/net/micode/notes/ui/NoteEditText.java index d350c57..beaee55 100644 --- a/Notes-master/src/net/micode/notes/ui/NoteEditText.java +++ b/Notes-master/src/net/micode/notes/ui/NoteEditText.java @@ -7,11 +7,9 @@ * * 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; @@ -39,14 +37,15 @@ import java.util.Map; // 自定义的EditText,用于笔记应用中,支持删除、添加文本事件监听 public class NoteEditText extends EditText { - private static final String TAG = "NoteEditText"; - private int mIndex; - private int mSelectionStartBeforeDelete; + 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:" ; + private static final String SCHEME_TEL = "tel:"; // 电话号码URL前缀 + private static final String SCHEME_HTTP = "http:"; // 网络链接URL前缀 + private static final String SCHEME_EMAIL = "mailto:"; // 邮件链接URL前缀 + // URL方案与对应的字符串资源ID的映射 private static final Map sSchemaActionResMap = new HashMap(); static { sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); @@ -55,32 +54,30 @@ public class NoteEditText extends EditText { } /** - * Call by the {@link NoteEditActivity} to delete or add edit text + * 由 {@link NoteEditActivity} 调用,用于删除或添加编辑文本 */ public interface OnTextViewChangeListener { /** - * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens - * and the text is null + * 在 {@link KeyEvent#KEYCODE_DEL} 发生且文本为空时删除当前编辑文本 */ void onEditTextDelete(int index, String text); /** - * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} - * happen + * 在 {@link KeyEvent#KEYCODE_ENTER} 发生时在当前编辑文本后添加新的编辑文本 */ void onEditTextEnter(int index, String text); /** - * Hide or show item option when text change + * 文本变化时隐藏或显示选项 */ void onTextChange(int index, boolean hasText); } - private OnTextViewChangeListener mOnTextViewChangeListener; + private OnTextViewChangeListener mOnTextViewChangeListener; // 文本变化监听器实例 public NoteEditText(Context context) { - super(context, null); - mIndex = 0; + super(context, null); // 调用父类构造函数 + mIndex = 0; // 初始化文本框索引为0 } // 设置当前文本框的索引 @@ -94,11 +91,11 @@ public class NoteEditText extends EditText { } public NoteEditText(Context context, AttributeSet attrs) { - super(context, attrs, android.R.attr.editTextStyle); + super(context, attrs, android.R.attr.editTextStyle); // 调用父类构造函数并设置默认样式 } public NoteEditText(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); + super(context, attrs, defStyle); // 调用父类构造函数并设置自定义样式 // TODO Auto-generated constructor stub } @@ -106,120 +103,120 @@ public class NoteEditText extends EditText { @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); + case MotionEvent.ACTION_DOWN: // 触摸屏幕时 + int x = (int) event.getX(); // 获取触摸点的X坐标 + int y = (int) event.getY(); // 获取触摸点的Y坐标 + x -= getTotalPaddingLeft(); // 减去左内边距 + y -= getTotalPaddingTop(); // 减去上内边距 + x += getScrollX(); // 加上水平滚动位置 + y += getScrollY(); // 加上垂直滚动位置 + + Layout layout = getLayout(); // 获取文本布局信息 + int line = layout.getLineForVertical(y); // 根据Y坐标获取行号 + int off = layout.getOffsetForHorizontal(line, x); // 根据行号和X坐标获取偏移量 + Selection.setSelection(getText(), off); // 更新光标位置 break; } - return super.onTouchEvent(event); + return super.onTouchEvent(event); // 调用父类的触摸事件处理方法 } // 处理按键按下事件,记录删除操作前的光标位置 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { - case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_ENTER: // 按下回车键 if (mOnTextViewChangeListener != null) { - return false; + return false; // 如果设置了监听器,返回false以拦截按键事件 } break; - case KeyEvent.KEYCODE_DEL: - mSelectionStartBeforeDelete = getSelectionStart(); + case KeyEvent.KEYCODE_DEL: // 按下删除键 + mSelectionStartBeforeDelete = getSelectionStart(); // 记录删除操作前的光标位置 break; - default: + default: // 其他按键 break; } - return super.onKeyDown(keyCode, event); + return super.onKeyDown(keyCode, event); // 调用父类的按键按下事件处理方法 } // 处理按键弹起事件,根据按键类型执行相应操作 @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - switch(keyCode) { - case KeyEvent.KEYCODE_DEL: + switch (keyCode) { + case KeyEvent.KEYCODE_DEL: // 弹起删除键 if (mOnTextViewChangeListener != null) { - if (0 == mSelectionStartBeforeDelete && mIndex != 0) { - mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); - return true; + if (0 == mSelectionStartBeforeDelete && mIndex != 0) { // 如果光标在文本开头且不是第一个文本框 + mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); // 通知监听器删除文本框 + return true; // 拦截按键事件 } } else { - Log.d(TAG, "OnTextViewChangeListener was not seted"); + Log.d(TAG, "OnTextViewChangeListener was not seted"); // 如果未设置监听器,记录日志 } break; - case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_ENTER: // 弹起回车键 if (mOnTextViewChangeListener != null) { - int selectionStart = getSelectionStart(); - String text = getText().subSequence(selectionStart, length()).toString(); - setText(getText().subSequence(0, selectionStart)); - mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); + int selectionStart = getSelectionStart(); // 获取光标位置 + String text = getText().subSequence(selectionStart, length()).toString(); // 获取光标后的文本 + setText(getText().subSequence(0, selectionStart)); // 将光标后的文本清空 + mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); // 通知监听器添加新的文本框 } else { - Log.d(TAG, "OnTextViewChangeListener was not seted"); + Log.d(TAG, "OnTextViewChangeListener was not seted"); // 如果未设置监听器,记录日志 } break; - default: + default: // 其他按键 break; } - return super.onKeyUp(keyCode, event); + return super.onKeyUp(keyCode, event); // 调用父类的按键弹起事件处理方法 } // 当EditText焦点发生变化时调用,通知监听器文本是否有内容 @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { if (mOnTextViewChangeListener != null) { - if (!focused && TextUtils.isEmpty(getText())) { - mOnTextViewChangeListener.onTextChange(mIndex, false); + if (!focused && TextUtils.isEmpty(getText())) { // 如果失去焦点且文本为空 + mOnTextViewChangeListener.onTextChange(mIndex, false); // 通知监听器文本内容为空 } else { - mOnTextViewChangeListener.onTextChange(mIndex, true); + mOnTextViewChangeListener.onTextChange(mIndex, true); // 通知监听器文本内容不为空 } } - super.onFocusChanged(focused, direction, previouslyFocusedRect); + super.onFocusChanged(focused, direction, previouslyFocusedRect); // 调用父类的焦点变化处理方法 } // 创建上下文菜单,处理URL点击事件 @Override protected void onCreateContextMenu(ContextMenu menu) { - if (getText() instanceof Spanned) { - int selStart = getSelectionStart(); - int selEnd = getSelectionEnd(); + if (getText() instanceof Spanned) { // 如果文本是Spanned类型 + int selStart = getSelectionStart(); // 获取选择的起始位置 + int selEnd = getSelectionEnd(); // 获取选择的结束位置 - int min = Math.min(selStart, selEnd); - int max = Math.max(selStart, selEnd); + 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) { + final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class); // 获取选择区域内的URLSpan + if (urls.length == 1) { // 如果只有一个URLSpan 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) { // 根据URL前缀匹配对应的资源ID defaultResId = sSchemaActionResMap.get(schema); break; } } - if (defaultResId == 0) { - defaultResId = R.string.note_link_other; + if (defaultResId == 0) { // 如果没有匹配到前缀 + defaultResId = R.string.note_link_other; // 使用默认的资源ID } + // 添加上下文菜单项并设置点击监听器 menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener( new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { - // goto a new intent + // 点击菜单项时,触发URLSpan的点击事件 urls[0].onClick(NoteEditText.this); - return true; + return true; // 拦截点击事件 } }); } } - super.onCreateContextMenu(menu); + super.onCreateContextMenu(menu); // 调用父类的创建上下文菜单方法 } -} \ No newline at end of file +} diff --git a/Notes-master/src/net/micode/notes/ui/NoteItemData.java b/Notes-master/src/net/micode/notes/ui/NoteItemData.java index 632fe29..cde2ecd 100644 --- a/Notes-master/src/net/micode/notes/ui/NoteItemData.java +++ b/Notes-master/src/net/micode/notes/ui/NoteItemData.java @@ -7,11 +7,10 @@ * * 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; @@ -27,22 +26,23 @@ 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, + 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,如果是文件夹下的笔记,则是文件夹ID + NoteColumns.SNIPPET, // 笔记项的摘要信息 + NoteColumns.TYPE, // 笔记项的类型,例如笔记、文件夹等 + NoteColumns.WIDGET_ID, // 与笔记项关联的小部件ID + NoteColumns.WIDGET_TYPE, // 小部件的类型 }; - // 定义了游标中各个列的索引位置 + // 定义了游标中各个列的索引位置,便于后续从游标中获取数据时使用 private static final int ID_COLUMN = 0; private static final int ALERTED_DATE_COLUMN = 1; private static final int BG_COLOR_ID_COLUMN = 2; @@ -57,83 +57,84 @@ public class NoteItemData { 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 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,如果是文件夹下的笔记,则是文件夹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; + private boolean mIsLastItem; // 是否是列表中的最后一个项 + private boolean mIsFirstItem; // 是否是列表中的第一个项 + private boolean mIsOnlyOneItem; // 是否是列表中唯一的项 + private boolean mIsOneNoteFollowingFolder; // 是否是单个笔记跟在一个文件夹后 + private boolean mIsMultiNotesFollowingFolder; // 是否是多个笔记跟在一个文件夹后 // 构造函数,从游标中提取笔记项数据 public NoteItemData(Context context, Cursor cursor) { - 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); - 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; + 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); // 获取笔记项的摘要信息 + 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) { // 如果笔记项的父ID是呼叫记录文件夹的ID + mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); // 通过笔记ID获取对应的呼叫记录的电话号码 + if (!TextUtils.isEmpty(mPhoneNumber)) { // 如果电话号码不为空 + mName = Contact.getContact(context, mPhoneNumber); // 通过电话号码查询联系人信息 + if (mName == null) { // 如果没有找到对应的联系人名称 + mName = mPhoneNumber; // 则将电话号码作为名称 } } } - if (mName == null) { - mName = ""; + if (mName == null) { // 如果联系人名称依然为null + mName = ""; // 初始化为空字符串 } - checkPostion(cursor); + checkPostion(cursor); // 检查笔记项在列表中的位置信息 } // 检查笔记项在列表中的位置信息 private void checkPostion(Cursor cursor) { - mIsLastItem = cursor.isLast() ? true : false; - mIsFirstItem = cursor.isFirst() ? true : false; - mIsOnlyOneItem = (cursor.getCount() == 1); - mIsMultiNotesFollowingFolder = false; - mIsOneNoteFollowingFolder = false; + mIsLastItem = cursor.isLast() ? true : false; // 设置是否是列表中的最后一个项 + mIsFirstItem = cursor.isFirst() ? true : false; // 设置是否是列表中的第一个项 + mIsOnlyOneItem = (cursor.getCount() == 1); // 如果列表中的项数为1,则设置为唯一项 + mIsMultiNotesFollowingFolder = false; // 初始化是否是多个笔记跟在一个文件夹后为false + mIsOneNoteFollowingFolder = false; // 初始化是否是单个笔记跟在一个文件夹后为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) { + int position = cursor.getPosition(); // 获取当前笔记项的位置 + if (cursor.moveToPrevious()) { // 将游标移动到前一行 + // 如果前一行的类型是文件夹或系统类型 + if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { + // 如果列表中的项数大于当前位置加1 if (cursor.getCount() > (position + 1)) { - mIsMultiNotesFollowingFolder = true; + mIsMultiNotesFollowingFolder = true; // 设置为多个笔记跟在一个文件夹后 } else { - mIsOneNoteFollowingFolder = true; + mIsOneNoteFollowingFolder = true; // 设置为单个笔记跟在一个文件夹后 } } - 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"); // 如果移动失败,抛出异常 } } } @@ -141,111 +142,112 @@ public class 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; // 返回是否是列表中唯一项的结果 } // 获取笔记项的ID public long getId() { - return mId; + return mId; // 返回笔记项的ID } // 获取笔记项的提醒日期 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; // 返回笔记项的修改日期 } // 获取笔记项的背景颜色ID public int getBgColorId() { - return mBgColorId; + return mBgColorId; // 返回笔记项的背景颜色ID } // 获取笔记项的父ID public long getParentId() { - return mParentId; + return mParentId; // 返回笔记项的父ID } // 获取笔记项包含的笔记数量 public int getNotesCount() { - return mNotesCount; + return mNotesCount; // 返回笔记项包含的笔记数量 } // 获取笔记项所在的文件夹ID public long getFolderId () { - return mParentId; + return mParentId; // 返回笔记项所在的文件夹ID,与getParentId相同 } // 获取笔记项的类型 public int getType() { - return mType; + return mType; // 返回笔记项的类型 } // 获取笔记项的小部件类型 public int getWidgetType() { - return mWidgetType; + return mWidgetType; // 返回笔记项的小部件类型 } // 获取笔记项的小部件ID public int getWidgetId() { - return mWidgetId; + return mWidgetId; // 返回笔记项的小部件ID } // 获取笔记项的摘要 public String getSnippet() { - return mSnippet; + return mSnippet; // 返回笔记项的摘要 } // 判断该笔记项是否有提醒 public boolean hasAlert() { - return (mAlertDate > 0); + return (mAlertDate > 0); // 如果提醒日期大于0,表示有提醒 } // 判断该笔记项是否是呼叫记录类型 public boolean isCallRecord() { + // 如果父ID是呼叫记录文件夹的ID且电话号码不为空,则是呼叫记录类型 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); // 从游标中获取笔记项的类型 } -} \ No newline at end of file +} diff --git a/Notes-master/src/net/micode/notes/ui/NotesListActivity.java b/Notes-master/src/net/micode/notes/ui/NotesListActivity.java index 5893567..e54f4a3 100644 --- a/Notes-master/src/net/micode/notes/ui/NotesListActivity.java +++ b/Notes-master/src/net/micode/notes/ui/NotesListActivity.java @@ -1,19 +1,3 @@ -/* - * 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.app.Activity; @@ -78,98 +62,104 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashSet; +/** + * 笔记列表展示Activity,主要用于展示用户的笔记列表,新建笔记,批量删除笔记等操作 + */ public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { + // 定义了用于查询笔记列表和文件夹列表的token private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; - private static final int FOLDER_LIST_QUERY_TOKEN = 1; + // 定义了文件夹操作菜单项的id 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"; + // 枚举类,定义了当前Activity的不同状态 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; - - private int mOriginY; - - private int mDispatchY; - - private TextView mTitleBar; + private ListEditState mState; // 当前Activity状态 - private long mCurrentFolderId; + private BackgroundQueryHandler mBackgroundQueryHandler; // 异步查询处理器 + private NotesListAdapter mNotesListAdapter; // 笔记列表适配器,负责展示笔记列表 + private ListView mNotesListView; // 笔记列表视图 + private Button mAddNewNote; // 新建笔记按钮 + private boolean mDispatch; // 是否需要将触摸事件分发给ListView + private int mOriginY; // 触摸开始时的Y坐标 + private int mDispatchY; // 触摸事件需要被分发时的Y坐标 + private TextView mTitleBar; // 标题栏文本视图 + private long mCurrentFolderId; // 当前显示的文件夹ID + private ContentResolver mContentResolver; // 内容解析器,用于操作数据库 + private ModeCallback mModeCallBack; // ActionMode回调,用于处理批量操作菜单 - private ContentResolver mContentResolver; + private static final String TAG = "NotesListActivity"; // 日志标签 - private ModeCallback mModeCallBack; + public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; // 笔记列表滚动速率 - private static final String TAG = "NotesListActivity"; - - public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; - - private NoteItemData mFocusNoteDataItem; + private NoteItemData mFocusNoteDataItem; // 当前选中的笔记项数据 + // 查询笔记列表时使用的SQL选择语句 private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?"; - + + // 查询根文件夹下的笔记列表时使用的SQL选择语句 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; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.note_list); - initResources(); + setContentView(R.layout.note_list); // 设置布局文件 + initResources(); // 初始化资源 /** - * Insert an introduction when user firstly use this application + * 当用户首次使用应用时,插入一个介绍笔记 */ setAppInfoFromRawRes(); } + /** + * 处理Activity返回的结果,如果是新建或打开笔记后的返回结果,则更新笔记列表 + * @param requestCode 请求码 + * @param resultCode 返回结果码 + * @param data 返回的Intent数据 + */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { - mNotesListAdapter.changeCursor(null); + mNotesListAdapter.changeCursor(null); // 更新笔记列表 } else { super.onActivityResult(requestCode, resultCode, data); } } + /** + * 从raw资源文件中读取应用介绍,并保存到本地数据库 + */ private void setAppInfoFromRawRes() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); // 获取偏好设置 + if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { // 如果尚未添加介绍 StringBuilder sb = new StringBuilder(); InputStream in = null; try { - in = getResources().openRawResource(R.raw.introduction); + in = getResources().openRawResource(R.raw.introduction); // 打开raw资源文件 if (in != null) { InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); char [] buf = new char[1024]; int len = 0; - while ((len = br.read(buf)) > 0) { + while ((len = br.read(buf)) > 0) { // 读取文件内容 sb.append(buf, 0, len); } } else { @@ -182,9 +172,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } finally { if(in != null) { try { - in.close(); + in.close(); // 关闭输入流 } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); } } @@ -194,8 +183,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt 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(); + if (note.saveNote()) { // 保存介绍笔记到数据库 + sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); // 更新偏好设置 } else { Log.e(TAG, "Save introduction note error"); return; @@ -206,52 +195,71 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt @Override protected void onStart() { super.onStart(); - startAsyncNotesListQuery(); + startAsyncNotesListQuery(); // 异步查询笔记列表并展示 } + /** + * 初始化资源,主要包括: + * 1. 获取ContentResolver + * 2. 初始化BackgroundQueryHandler + * 3. 设置当前文件夹ID为根文件夹ID + * 4. 查找视图控件并设置监听器 + * 5. 初始化NotesListAdapter并绑定到ListView + * 6. 设置Activity状态为NOTE_LIST + */ private void initResources() { mContentResolver = this.getContentResolver(); mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); mCurrentFolderId = Notes.ID_ROOT_FOLDER; 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); + null, false); // 添加底部视图 + mNotesListView.setOnItemClickListener(new OnListItemClickListener()); // 设置点击监听器 + mNotesListView.setOnItemLongClickListener(this); // 设置长按监听器 mNotesListAdapter = new NotesListAdapter(this); - mNotesListView.setAdapter(mNotesListAdapter); + mNotesListView.setAdapter(mNotesListAdapter); // 设置适配器 mAddNewNote = (Button) findViewById(R.id.btn_new_note); - mAddNewNote.setOnClickListener(this); - mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); + 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(); + mModeCallBack = new ModeCallback(); // 初始化ActionMode回调 } + /** + * ActionMode回调类,用于处理批量操作菜单的创建、显示和点击事件 + */ private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { - private DropdownMenu mDropDownMenu; - private ActionMode mActionMode; - private MenuItem mMoveMenu; + private DropdownMenu mDropDownMenu; // 下拉菜单 + private ActionMode mActionMode; // ActionMode + private MenuItem mMoveMenu; // 移动笔记的菜单项 + /** + * 创建ActionMode并设置菜单 + * @param mode ActionMode对象 + * @param menu 菜单对象 + * @return 返回true,表示ActionMode创建成功 + */ public boolean onCreateActionMode(ActionMode mode, Menu menu) { - getMenuInflater().inflate(R.menu.note_list_options, menu); - menu.findItem(R.id.delete).setOnMenuItemClickListener(this); + 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); + mMoveMenu.setVisible(false); // 如果当前文件夹为通话记录文件夹或无用户文件夹,隐藏移动菜单项 } else { - mMoveMenu.setVisible(true); - mMoveMenu.setOnMenuItemClickListener(this); + mMoveMenu.setVisible(true); // 显示移动菜单项 + mMoveMenu.setOnMenuItemClickListener(this); // 设置移动菜单项的点击监听器 } mActionMode = mode; - mNotesListAdapter.setChoiceMode(true); - mNotesListView.setLongClickable(false); - mAddNewNote.setVisibility(View.GONE); + mNotesListAdapter.setChoiceMode(true); // 设置列表适配器为选择模式 + mNotesListView.setLongClickable(false); // 禁用长按操作 + mAddNewNote.setVisibility(View.GONE); // 隐藏新建笔记按钮 + // 设置自定义ActionMode视图 View customView = LayoutInflater.from(NotesListActivity.this).inflate( R.layout.note_list_dropdown_menu, null); mode.setCustomView(customView); @@ -260,62 +268,112 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt R.menu.note_list_dropdown); mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ public boolean onMenuItemClick(MenuItem item) { - mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); - updateMenu(); + mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); // 全选或全不选 + updateMenu(); // 更新菜单 return true; } - }); return true; } + /** + * 更新菜单,包括下拉菜单的标题和选择项 + */ private void updateMenu() { - int selectedCount = mNotesListAdapter.getSelectedCount(); - // Update dropdown menu + int selectedCount = mNotesListAdapter.getSelectedCount(); // 获取选中的笔记数量 + // 更新下拉菜单标题 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()) { + if (mNotesListAdapter.isAllSelected()) { // 如果所有笔记都被选中 item.setChecked(true); - item.setTitle(R.string.menu_deselect_all); + item.setTitle(R.string.menu_deselect_all); // 更新菜单项标题为取消全选 } else { item.setChecked(false); - item.setTitle(R.string.menu_select_all); + item.setTitle(R.string.menu_select_all); // 更新菜单项标题为全选 } } } public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - // TODO Auto-generated method stub + // 不需要在ActionMode准备时修改菜单,返回false return false; } - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - // TODO Auto-generated method stub + /** + * 处理菜单项点击事件 + * @param mode ActionMode对象 + * @param menu 菜单对象 + * @param item 被点击的菜单项 + * @param rangeStart 被点击的菜单项的起始位置(未使用) + * @param rangeEnd 被点击的菜单项的结束位置(未使用) + * @return 返回true,表示菜单项点击事件处理成功 + */ + public boolean onCreateActionMode(ActionMode mode, Menu menu, int rangeStart, int rangeEnd) { + // 不需要支持多选范围,返回false + return false; + } + + /** + * 处理菜单项点击事件 + * @param mode ActionMode对象 + * @param menu 菜单对象 + * @return 返回true,表示菜单项点击事件处理成功 + */ + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // 不需要在ActionMode准备时修改菜单,返回false return false; } + /** + * 处理菜单项点击事件 + * @param mode ActionMode对象 + * @param item 被点击的菜单项 + * @return 返回true,表示菜单项点击事件处理成功 + */ + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + // 由onMenuItemClick方法处理点击事件 + return onMenuItemClick(item); + } + + /** + * 结束ActionMode + */ public void onDestroyActionMode(ActionMode mode) { - mNotesListAdapter.setChoiceMode(false); - mNotesListView.setLongClickable(true); - mAddNewNote.setVisibility(View.VISIBLE); + mNotesListAdapter.setChoiceMode(false); // 取消列表适配器的选择模式 + mNotesListView.setLongClickable(true); // 启用长按操作 + mAddNewNote.setVisibility(View.VISIBLE); // 显示新建笔记按钮 } + /** + * 结束ActionMode + */ public void finishActionMode() { - mActionMode.finish(); + mActionMode.finish(); // 结束ActionMode } - public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { - mNotesListAdapter.setCheckedItem(position, checked); - updateMenu(); + /** + * 处理单个笔记项被选中或取消选中的事件 + * @param mode ActionMode对象 + * @param position 笔记项的位置 + * @param id 笔记项的ID + * @param checked 是否被选中 + */ + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { + mNotesListAdapter.setCheckedItem(position, checked); // 设置笔记项的选中状态 + updateMenu(); // 更新菜单 } + /** + * 处理菜单项点击事件 + * @param item 被点击的菜单项 + * @return 返回true,表示菜单项点击事件处理成功 + */ public boolean onMenuItemClick(MenuItem item) { - if (mNotesListAdapter.getSelectedCount() == 0) { + if (mNotesListAdapter.getSelectedCount() == 0) { // 如果没有选中的笔记 Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none), - Toast.LENGTH_SHORT).show(); + Toast.LENGTH_SHORT).show(); // 显示提示信息 return true; } @@ -330,14 +388,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - batchDelete(); + batchDelete(); // 批量删除笔记 } }); builder.setNegativeButton(android.R.string.cancel, null); - builder.show(); + builder.show(); // 显示确认对话框 break; case R.id.move: - startQueryDestinationFolders(); + startQueryDestinationFolders(); // 查询目标文件夹 break; default: return false; @@ -346,8 +404,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + /** + * 新建笔记按钮的触摸监听器,用于处理触摸事件 + */ private class NewNoteOnTouchListener implements OnTouchListener { - public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { @@ -355,82 +415,90 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt 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. + * 处理按钮透明部分的触摸事件,将触摸事件分发给底层的ListView + * 透明部分的公式:y=-0.12x+94(单位:像素),基于按钮左边缘的坐标系 + * 94表示透明部分的最大高度 + * 注意:如果按钮背景发生变化,此公式需要相应调整 */ if (event.getY() < (event.getX() * (-0.12) + 94)) { + // 获取ListView最后一个可见项 View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 - mNotesListView.getFooterViewsCount()); if (view != null && view.getBottom() > start && (view.getTop() < (start + 94))) { mOriginY = (int) event.getY(); mDispatchY = eventY; - event.setLocation(event.getX(), mDispatchY); + event.setLocation(event.getX(), mDispatchY); // 设置新的触摸位置 mDispatch = true; - return mNotesListView.dispatchTouchEvent(event); + return mNotesListView.dispatchTouchEvent(event); // 分发触摸事件 } } break; } case MotionEvent.ACTION_MOVE: { if (mDispatch) { - mDispatchY += (int) event.getY() - mOriginY; - event.setLocation(event.getX(), mDispatchY); - return mNotesListView.dispatchTouchEvent(event); + mDispatchY += (int) event.getY() - mOriginY; // 更新触摸位置 + event.setLocation(event.getX(), mDispatchY); // 设置新的触摸位置 + return mNotesListView.dispatchTouchEvent(event); // 分发触摸事件 } break; } default: { if (mDispatch) { - event.setLocation(event.getX(), mDispatchY); + event.setLocation(event.getX(), mDispatchY); // 设置新的触摸位置 mDispatch = false; - return mNotesListView.dispatchTouchEvent(event); + return mNotesListView.dispatchTouchEvent(event); // 分发触摸事件 } break; } } return false; } - }; + /** + * 异步查询笔记列表 + */ private void startAsyncNotesListQuery() { 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) - }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); + }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); // 执行异步查询 } + /** + * BackgroundQueryHandler,用于处理异步查询结果 + */ private final class BackgroundQueryHandler extends AsyncQueryHandler { public BackgroundQueryHandler(ContentResolver contentResolver) { super(contentResolver); } + /** + * 处理查询完成后的结果 + * @param token 查询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); + mNotesListAdapter.changeCursor(cursor); // 更新笔记列表适配器的游标 break; case FOLDER_LIST_QUERY_TOKEN: if (cursor != null && cursor.getCount() > 0) { - showFolderListMenu(cursor); + showFolderListMenu(cursor); // 显示文件夹列表菜单 } else { Log.e(TAG, "Query folder failed"); } @@ -441,12 +509,16 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + /** + * 显示文件夹列表菜单 + * @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() { - + // 处理菜单项点击事件 public void onClick(DialogInterface dialog, int which) { DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which)); @@ -455,34 +527,39 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt getString(R.string.format_move_notes_to_folder, mNotesListAdapter.getSelectedCount(), adapter.getFolderName(NotesListActivity.this, which)), - Toast.LENGTH_SHORT).show(); - mModeCallBack.finishActionMode(); + Toast.LENGTH_SHORT).show(); // 显示提示信息 + mModeCallBack.finishActionMode(); // 结束ActionMode } }); - builder.show(); + builder.show(); // 显示对话框 } + /** + * 创建新笔记 + */ private void createNewNote() { 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); + this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE); // 启动NoteEditActivity并等待返回结果 } + /** + * 批量删除笔记 + */ private void batchDelete() { new AsyncTask>() { protected HashSet doInBackground(Void... unused) { - HashSet widgets = mNotesListAdapter.getSelectedWidget(); + HashSet widgets = mNotesListAdapter.getSelectedWidget(); // 获取选中的笔记关联的Widget属性 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"); @@ -497,15 +574,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt for (AppWidgetAttribute widget : widgets) { if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) { - updateWidget(widget.widgetId, widget.widgetType); + updateWidget(widget.widgetId, widget.widgetType); // 更新Widget } } } - mModeCallBack.finishActionMode(); + mModeCallBack.finishActionMode(); // 结束ActionMode } - }.execute(); + }.execute(); // 执行异步任务 } + /** + * 删除文件夹 + * @param folderId 文件夹ID + */ private void deleteFolder(long folderId) { if (folderId == Notes.ID_ROOT_FOLDER) { Log.e(TAG, "Wrong folder id, should not happen " + folderId); @@ -515,185 +596,214 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt HashSet ids = new HashSet(); ids.add(folderId); HashSet widgets = DataUtils.getFolderNoteWidget(mContentResolver, - folderId); + folderId); // 获取文件夹关联的Widget属性 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); + updateWidget(widget.widgetId, widget.widgetType); // 更新Widget } } } } + /** + * 打开笔记节点 + * @param data 笔记数据 + */ private void openNode(NoteItemData data) { 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); + this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE); // 启动NoteEditActivity并等待返回结果 } + /** + * 打开文件夹 + * @param data 文件夹数据 + */ private void openFolder(NoteItemData data) { - mCurrentFolderId = data.getId(); - startAsyncNotesListQuery(); + mCurrentFolderId = data.getId(); // 更新当前文件夹ID + startAsyncNotesListQuery(); // 异步查询笔记列表 if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mState = ListEditState.CALL_RECORD_FOLDER; - mAddNewNote.setVisibility(View.GONE); + mState = ListEditState.CALL_RECORD_FOLDER; // 设置为通话记录文件夹状态 + mAddNewNote.setVisibility(View.GONE); // 隐藏新建笔记按钮 } else { - mState = ListEditState.SUB_FOLDER; + mState = ListEditState.SUB_FOLDER; // 设置为子文件夹状态 } if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mTitleBar.setText(R.string.call_record_folder_name); + mTitleBar.setText(R.string.call_record_folder_name); // 设置标题栏文本为通话记录文件夹名称 } else { - mTitleBar.setText(data.getSnippet()); + mTitleBar.setText(data.getSnippet()); // 设置标题栏文本为文件夹的摘要 } - mTitleBar.setVisibility(View.VISIBLE); + mTitleBar.setVisibility(View.VISIBLE); // 显示标题栏 } + /** + * 处理View的点击事件 + * @param v 被点击的View + */ public void onClick(View v) { switch (v.getId()) { case R.id.btn_new_note: - createNewNote(); + createNewNote(); // 创建新笔记 break; default: break; } } + /** + * 显示软键盘 + */ private void showSoftInput() { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (inputMethodManager != null) { - inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); // 显示软键盘 } } + /** + * 隐藏软键盘 + * @param view 触发隐藏软键盘的View + */ private void hideSoftInput(View view) { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); // 隐藏软键盘 } + /** + * 显示创建或修改文件夹的对话框 + * @param create 是否为创建文件夹 + */ 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"); return; } } else { etName.setText(""); - builder.setTitle(this.getString(R.string.menu_create_folder)); + 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 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); + hideSoftInput(etName); // 隐藏软键盘 String name = etName.getText().toString(); - if (DataUtils.checkVisibleFolderName(mContentResolver, name)) { + 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)) { 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()) - }); + }); // 更新数据库中的文件夹信息 } } 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); + 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())) { - positive.setEnabled(false); + if (TextUtils.isEmpty(s)) { + positive.setEnabled(false); // 如果文件夹名称为空,则禁用确定按钮 } else { - positive.setEnabled(true); + positive.setEnabled(true); // 如果文件夹名称不为空,则启用确定按钮 } } public void afterTextChanged(Editable s) { - // TODO Auto-generated method stub - + // 不需要处理文本改变后的事件 } }); } + /** + * 处理返回键事件 + */ @Override public void onBackPressed() { switch (mState) { case SUB_FOLDER: - mCurrentFolderId = Notes.ID_ROOT_FOLDER; - mState = ListEditState.NOTE_LIST; - startAsyncNotesListQuery(); - mTitleBar.setVisibility(View.GONE); + 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); - mTitleBar.setVisibility(View.GONE); - startAsyncNotesListQuery(); + mCurrentFolderId = Notes.ID_ROOT_FOLDER; // 返回根文件夹 + mState = ListEditState.NOTE_LIST; // 设置为笔记列表状态 + mAddNewNote.setVisibility(View.VISIBLE); // 显示新建笔记按钮 + mTitleBar.setVisibility(View.GONE); // 隐藏标题栏 + startAsyncNotesListQuery(); // 异步查询笔记列表 break; case NOTE_LIST: - super.onBackPressed(); + super.onBackPressed(); // 调用父类的返回键处理方法 break; default: break; } } + /** + * 更新Widget + * @param appWidgetId Widget的ID + * @param appWidgetType Widget的类型 + */ private void updateWidget(int appWidgetId, int appWidgetType) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); if (appWidgetType == Notes.TYPE_WIDGET_2X) { - intent.setClass(this, NoteWidgetProvider_2x.class); + intent.setClass(this, NoteWidgetProvider_2x.class); // 设置Widget更新的广播接收器 } else if (appWidgetType == Notes.TYPE_WIDGET_4X) { - intent.setClass(this, NoteWidgetProvider_4x.class); + intent.setClass(this, NoteWidgetProvider_4x.class); // 设置Widget更新的广播接收器 } else { Log.e(TAG, "Unspported widget type"); return; @@ -703,17 +813,20 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt appWidgetId }); - sendBroadcast(intent); + sendBroadcast(intent); // 发送广播通知Widget更新内容 setResult(RESULT_OK, intent); } + /** + * 创建文件夹的上下文菜单监听器 + */ private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { if (mFocusNoteDataItem != null) { - menu.setHeaderTitle(mFocusNoteDataItem.getSnippet()); - menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view); - menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete); - menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name); + menu.setHeaderTitle(mFocusNoteDataItem.getSnippet()); // 设置上下文菜单标题为文件夹摘要 + menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view); // 添加查看文件夹选项 + menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete); // 添加删除文件夹选项 + menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name); // 添加修改文件夹名称选项 } } }; @@ -721,11 +834,16 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt @Override public void onContextMenuClosed(Menu menu) { if (mNotesListView != null) { - mNotesListView.setOnCreateContextMenuListener(null); + mNotesListView.setOnCreateContextMenuListener(null); // 清除上下文菜单监听器 } super.onContextMenuClosed(menu); } + /** + * 处理上下文菜单项点击事件 + * @param item 被点击的菜单项 + * @return 返回true,表示事件处理成功 + */ @Override public boolean onContextItemSelected(MenuItem item) { if (mFocusNoteDataItem == null) { @@ -734,7 +852,7 @@ 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); @@ -744,14 +862,14 @@ 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(); + builder.show(); // 显示确认对话框 break; case MENU_FOLDER_CHANGE_NAME: - showCreateOrModifyFolderDialog(false); + showCreateOrModifyFolderDialog(false); // 显示修改文件夹名称对话框 break; default: break; @@ -760,57 +878,67 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt 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 + getMenuInflater().inflate(R.menu.note_list, menu); // 设置笔记列表菜单 + // 设置同步或取消同步菜单项标题 menu.findItem(R.id.menu_sync).setTitle( GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync); } else if (mState == ListEditState.SUB_FOLDER) { - getMenuInflater().inflate(R.menu.sub_folder, menu); + getMenuInflater().inflate(R.menu.sub_folder, menu); // 设置子文件夹菜单 } else if (mState == ListEditState.CALL_RECORD_FOLDER) { - getMenuInflater().inflate(R.menu.call_record_folder, menu); + getMenuInflater().inflate(R.menu.call_record_folder, menu); // 设置通话记录文件夹菜单 } else { Log.e(TAG, "Wrong state:" + mState); } return true; } + /** + * 处理选项菜单项点击事件 + * @param item 被点击的菜单项 + * @return 返回true,表示事件处理成功 + */ @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); + GTaskSyncService.startSync(this); // 开始同步 } else { - GTaskSyncService.cancelSync(this); + GTaskSyncService.cancelSync(this); // 取消同步 } } else { - startPreferenceActivity(); + startPreferenceActivity(); // 启动偏好设置Activity } break; } case R.id.menu_setting: { - startPreferenceActivity(); + startPreferenceActivity(); // 启动偏好设置Activity break; } case R.id.menu_new_note: { - createNewNote(); + createNewNote(); // 创建新笔记 break; } case R.id.menu_search: - onSearchRequested(); + onSearchRequested(); // 处理搜索请求 break; default: break; @@ -818,19 +946,25 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } + /** + * 处理搜索请求 + * @return 返回true,表示搜索请求处理成功 + */ @Override public boolean onSearchRequested() { - startSearch(null, false, null /* appData */, false); + 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(); + return backup.exportToText(); // 执行导出操作 } @Override @@ -838,54 +972,63 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) { AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(NotesListActivity.this - .getString(R.string.failed_sdcard_export)); + .getString(R.string.failed_sdcard_export)); // 设置对话框标题为导出失败 builder.setMessage(NotesListActivity.this - .getString(R.string.error_sdcard_unmounted)); + .getString(R.string.error_sdcard_unmounted)); // 设置对话框消息为SD卡未挂载 builder.setPositiveButton(android.R.string.ok, null); - builder.show(); + builder.show(); // 显示对话框 } else if (result == BackupUtils.STATE_SUCCESS) { AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(NotesListActivity.this - .getString(R.string.success_sdcard_export)); + .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(); + builder.show(); // 显示对话框 } else if (result == BackupUtils.STATE_SYSTEM_ERROR) { AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(NotesListActivity.this - .getString(R.string.failed_sdcard_export)); + .getString(R.string.failed_sdcard_export)); // 设置对话框标题为导出失败 builder.setMessage(NotesListActivity.this - .getString(R.string.error_sdcard_export)); + .getString(R.string.error_sdcard_export)); // 设置对话框消息为系统错误 builder.setPositiveButton(android.R.string.ok, null); - builder.show(); + builder.show(); // 显示对话框 } } - }.execute(); + }.execute(); // 执行异步任务 } + /** + * 判断是否处于同步模式 + * @return 返回true,表示处于同步模式;否则返回false + */ private boolean isSyncMode() { - return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; + return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; // 通过偏好设置判断是否设置了同步账户 } + /** + * 启动偏好设置Activity + */ private void startPreferenceActivity() { Activity from = getParent() != null ? getParent() : this; Intent intent = new Intent(from, NotesPreferenceActivity.class); - from.startActivityIfNeeded(intent, -1); + from.startActivityIfNeeded(intent, -1); // 启动偏好设置Activity } + /** + * 笔记列表项点击监听器 + */ 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(); + NoteItemData item = ((NotesListItem) view).getItemData(); // 获取笔记项数据 if (mNotesListAdapter.isInChoiceMode()) { if (item.getType() == Notes.TYPE_NOTE) { - position = position - mNotesListView.getHeaderViewsCount(); + position = position - mNotesListView.getHeaderViewsCount(); // 调整位置索引 mModeCallBack.onItemCheckedStateChanged(null, position, id, - !mNotesListAdapter.isSelectedItem(position)); + !mNotesListAdapter.isSelectedItem(position)); // 处理笔记项选中或取消选中 } return; } @@ -894,9 +1037,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt case NOTE_LIST: if (item.getType() == Notes.TYPE_FOLDER || item.getType() == Notes.TYPE_SYSTEM) { - openFolder(item); + openFolder(item); // 打开文件夹 } else if (item.getType() == Notes.TYPE_NOTE) { - openNode(item); + openNode(item); // 打开笔记 } else { Log.e(TAG, "Wrong note type in NOTE_LIST"); } @@ -904,7 +1047,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt case SUB_FOLDER: case CALL_RECORD_FOLDER: if (item.getType() == Notes.TYPE_NOTE) { - openNode(item); + openNode(item); // 打开笔记 } else { Log.e(TAG, "Wrong note type in SUB_FOLDER"); } @@ -914,9 +1057,11 @@ 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: @@ -928,27 +1073,35 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt FoldersListAdapter.PROJECTION, selection, new String[] { - String.valueOf(Notes.TYPE_FOLDER), - String.valueOf(Notes.ID_TRASH_FOLER), - String.valueOf(mCurrentFolderId) + String.valueOf(Notes.TYPE_FOLDER), // 文件夹类型 + String.valueOf(Notes.ID_TRASH_FOLER), // 废纸篓文件夹ID + String.valueOf(mCurrentFolderId) // 当前文件夹ID }, - NoteColumns.MODIFIED_DATE + " DESC"); + NoteColumns.MODIFIED_DATE + " DESC"); // 按修改日期降序排序 } + /** + * 处理笔记项长按事件 + * @param parent 父视图 + * @param view 被长按的视图 + * @param position 被长按的笔记项的位置 + * @param id 被长按的笔记项的ID + * @return 返回true,表示事件处理成功 + */ public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { if (view instanceof NotesListItem) { - mFocusNoteDataItem = ((NotesListItem) view).getItemData(); + 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); + if (mNotesListView.startActionMode(mModeCallBack) != null) { // 启动ActionMode + mModeCallBack.onItemCheckedStateChanged(null, position, id, true); // 选中笔记项 + mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); // 提供长按反馈 } else { Log.e(TAG, "startActionMode fails"); } } else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) { - mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener); + mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener); // 设置上下文菜单监听器 } } return false; } -} \ No newline at end of file +} diff --git a/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java b/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java index fc77697..66148aa 100644 --- a/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java +++ b/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java @@ -1,200 +1,193 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权 (c) 2010-2011, MiCode开源社区 (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. + * 根据Apache许可证2.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; - + // 自定义的CursorAdapter,用于显示笔记列表 public class NotesListAdapter extends CursorAdapter { private static final String TAG = "NotesListAdapter"; - private Context mContext; - private HashMap mSelectedIndex; - private int mNotesCount; - private boolean mChoiceMode; - + private Context mContext; // 上下文环境 + private HashMap mSelectedIndex; // 记录选中的笔记位置 + private int mNotesCount; // 笔记总数 + private boolean mChoiceMode; // 是否处于多选模式 + // 用于存储小部件属性的内部类 public static class AppWidgetAttribute { - public int widgetId; - public int widgetType; + public int widgetId; // 小部件ID + public int widgetType; // 小部件类型 }; - + // 构造函数,初始化上下文和选择索引 public NotesListAdapter(Context context) { - super(context, null); - mSelectedIndex = new HashMap(); - mContext = context; - mNotesCount = 0; + super(context, null); // 调用父类构造函数,不立即绑定任何游标 + mSelectedIndex = new HashMap(); // 初始化选择索引 + mContext = context; // 初始化上下文 + mNotesCount = 0; // 初始化笔记数量为0 } - + // 创建新的视图项 @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return new NotesListItem(context); + return new NotesListItem(context); // 创建一个新的NotesListItem视图 } - + // 绑定数据到视图项 @Override 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())); + if (view instanceof NotesListItem) { // 检查视图是否为NotesListItem类型 + NoteItemData itemData = new NoteItemData(context, cursor); // 创建NoteItemData对象,用于封装笔记数据 + ((NotesListItem) view).bind(context, itemData, mChoiceMode, // 调用NotesListItem的bind方法,绑定数据 + isSelectedItem(cursor.getPosition())); // 传递当前项是否被选中的信息 } } - + // 设置指定位置的项是否被选中,并通知数据集发生变化 public void setCheckedItem(final int position, final boolean checked) { - mSelectedIndex.put(position, checked); - notifyDataSetChanged(); + mSelectedIndex.put(position, checked); // 更新选中状态 + notifyDataSetChanged(); // 通知数据集发生变化,刷新UI } - + // 检查当前是否处于多选模式 public boolean isInChoiceMode() { - return mChoiceMode; + return mChoiceMode; // 返回当前的多选模式状态 } - + // 设置多选模式,清空选择索引 public void setChoiceMode(boolean mode) { - mSelectedIndex.clear(); - mChoiceMode = mode; + mSelectedIndex.clear(); // 清空选择索引 + mChoiceMode = mode; // 更新多选模式状态 } - + // 全选或全不选所有笔记 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); + 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集合 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"); + HashSet itemSet = new HashSet(); // 初始化选中笔记ID集合 + for (Integer position : mSelectedIndex.keySet()) { // 遍历所有选中的位置 + if (mSelectedIndex.get(position) == true) { // 检查位置是否被选中 + Long id = getItemId(position); // 获取笔记ID + if (id == Notes.ID_ROOT_FOLDER) { // 检查是否为根文件夹ID(错误情况) + Log.d(TAG, "Wrong item id, should not happen"); // 记录日志 } else { - itemSet.add(id); + itemSet.add(id); // 将笔记ID添加到集合 } } } - - return itemSet; + return itemSet; // 返回选中笔记ID集合 } - + // 获取所有选中的小部件属性集合 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); + 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); // 创建NoteItemData对象,用于封装笔记数据 + widget.widgetId = item.getWidgetId(); // 设置小部件ID + 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; // 返回null } } } - return itemSet; + return itemSet; // 返回选中小部件属性集合 } - + // 获取选中的笔记数量 public int getSelectedCount() { - Collection values = mSelectedIndex.values(); + Collection values = mSelectedIndex.values(); // 获取所有选中状态值 if (null == values) { - return 0; + return 0; // 如果选中状态值为空,返回0 } - Iterator iter = values.iterator(); - int count = 0; + Iterator iter = values.iterator(); // 创建迭代器 + int count = 0; // 初始化计数器 while (iter.hasNext()) { - if (true == iter.next()) { - count++; + if (true == iter.next()) { // 检查是否为选中状态 + count++; // 计数器加一 } } - return count; + return count; // 返回选中的笔记数量 } - + // 检查是否所有笔记都被选中 public boolean isAllSelected() { - int checkedCount = getSelectedCount(); - return (checkedCount != 0 && checkedCount == mNotesCount); + int checkedCount = getSelectedCount(); // 获取选中的笔记数量 + return (checkedCount != 0 && checkedCount == mNotesCount); // 检查选中的笔记数量是否等于笔记总数 } - + // 检查指定位置的项是否被选中 public boolean isSelectedItem(final int position) { - if (null == mSelectedIndex.get(position)) { - return false; + if (null == mSelectedIndex.get(position)) { // 检查指定位置是否被选中 + return false; // 如果没有被选中,返回false } - return mSelectedIndex.get(position); + return mSelectedIndex.get(position); // 返回选中状态 } - + // 当数据内容发生变化时,更新笔记数量 @Override protected void onContentChanged() { - super.onContentChanged(); - calcNotesCount(); + super.onContentChanged(); // 调用父类方法 + calcNotesCount(); // 计算笔记数量 } - + // 更改Cursor时,更新笔记数量 @Override public void changeCursor(Cursor cursor) { - super.changeCursor(cursor); - calcNotesCount(); + 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++; + mNotesCount = 0; // 初始化笔记数量为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; // 返回 } } } -} \ No newline at end of file +} diff --git a/Notes-master/src/net/micode/notes/ui/NotesListItem.java b/Notes-master/src/net/micode/notes/ui/NotesListItem.java index 1546bbe..09f0ebd 100644 --- a/Notes-master/src/net/micode/notes/ui/NotesListItem.java +++ b/Notes-master/src/net/micode/notes/ui/NotesListItem.java @@ -31,80 +31,101 @@ import net.micode.notes.tool.ResourceParser.NoteItemBgResources; // NotesListItem 类继承自 LinearLayout,用于表示笔记列表中的一个项 public class NotesListItem extends LinearLayout { - private ImageView mAlert; - private TextView mTitle; - private TextView mTime; - private TextView mCallName; - private NoteItemData mItemData; - private CheckBox mCheckBox; + private ImageView mAlert; // 用于显示笔记的提醒图标 + private TextView mTitle; // 用于显示笔记的标题 + private TextView mTime; // 用于显示笔记的修改时间 + private TextView mCallName; // 用于显示与笔记相关的联系人姓名 + private NoteItemData mItemData; // 存储当前笔记项的数据 + private CheckBox mCheckBox; // 用于选择笔记项的复选框 // 构造函数,初始化 NotesListItem 的视图组件 public NotesListItem(Context context) { super(context); + // 从资源文件中加载布局文件 R.layout.note_item 到当前 NotesListItem 中 inflate(context, R.layout.note_item, this); + // 查找布局文件中的 ImageView 组件,并赋值给 mAlert mAlert = (ImageView) findViewById(R.id.iv_alert_icon); + // 查找布局文件中的 TextView 组件,并赋值给 mTitle mTitle = (TextView) findViewById(R.id.tv_title); + // 查找布局文件中的 TextView 组件,并赋值给 mTime mTime = (TextView) findViewById(R.id.tv_time); + // 查找布局文件中的 TextView 组件,并赋值给 mCallName mCallName = (TextView) findViewById(R.id.tv_name); + // 查找布局文件中的 CheckBox 组件,并赋值给 mCheckBox mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); } // 绑定数据到 NotesListItem 的视图组件,并设置选择模式和选中状态 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); + mCheckBox.setChecked(checked); // 设置复选框的选中状态 } else { - mCheckBox.setVisibility(View.GONE); + mCheckBox.setVisibility(View.GONE); // 否则隐藏复选框 } - mItemData = data; + mItemData = data; // 存储当前绑定的数据 + // 如果当前笔记项的 ID 是通话记录文件夹的 ID if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mCallName.setVisibility(View.GONE); - mAlert.setVisibility(View.VISIBLE); - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); + mCallName.setVisibility(View.GONE); // 隐藏联系人姓名 TextView + mAlert.setVisibility(View.VISIBLE); // 显示提醒图标 ImageView + mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); // 设置标题 TextView 的文本样式 + // 设置标题 TextView 的文本内容为通话记录文件夹名称及其中包含的笔记数量 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); + mAlert.setImageResource(R.drawable.call_record); // 设置提醒图标 ImageView 的图片资源为通话记录图标 + } + // 如果当前笔记项的父目录 ID 是通话记录文件夹的 ID + else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { + mCallName.setVisibility(View.VISIBLE); // 显示联系人姓名 TextView + mCallName.setText(data.getCallName()); // 设置联系人姓名 TextView 的文本内容 + mTitle.setTextAppearance(context, R.style.TextAppearanceSecondaryItem); // 设置标题 TextView 的文本样式 + // 设置标题 TextView 的文本内容为笔记内容的摘要 mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + // 如果笔记项有提醒,则显示提醒图标 ImageView if (data.hasAlert()) { - mAlert.setImageResource(R.drawable.clock); + mAlert.setImageResource(R.drawable.clock); // 设置提醒图标 ImageView 的图片资源为时钟图标 mAlert.setVisibility(View.VISIBLE); } else { - mAlert.setVisibility(View.GONE); + mAlert.setVisibility(View.GONE); // 否则隐藏提醒图标 ImageView } - } else { - mCallName.setVisibility(View.GONE); - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); + } + // 如果当前笔记项既不是通话记录文件夹也不是其子项 + else { + mCallName.setVisibility(View.GONE); // 隐藏联系人姓名 TextView + mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); // 设置标题 TextView 的文本样式 + // 如果笔记项类型为文件夹 if (data.getType() == Notes.TYPE_FOLDER) { - mTitle.setText(data.getSnippet() + mTitle.setText(data.getSnippet() // 设置标题 TextView 的文本内容为文件夹名称 + context.getString(R.string.format_folder_files_count, - data.getNotesCount())); - mAlert.setVisibility(View.GONE); + data.getNotesCount())); // 并追加其中包含的笔记数量 + mAlert.setVisibility(View.GONE); // 隐藏提醒图标 ImageView } else { + // 设置标题 TextView 的文本内容为笔记内容的摘要 mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + // 如果笔记项有提醒,则显示提醒图标 ImageView if (data.hasAlert()) { - mAlert.setImageResource(R.drawable.clock); + mAlert.setImageResource(R.drawable.clock); // 设置提醒图标 ImageView 的图片资源为时钟图标 mAlert.setVisibility(View.VISIBLE); } else { - mAlert.setVisibility(View.GONE); + mAlert.setVisibility(View.GONE); // 否则隐藏提醒图标 ImageView } } } + // 设置时间 TextView 的文本内容为笔记的相对修改时间(如“3 小时前”) mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); - setBackground(data); + setBackground(data); // 根据笔记项的数据设置背景资源 } // 根据数据设置 NotesListItem 的背景资源 private void setBackground(NoteItemData data) { - int id = data.getBgColorId(); + int id = data.getBgColorId(); // 获取笔记项的背景颜色 ID + // 如果笔记项类型为普通笔记 if (data.getType() == Notes.TYPE_NOTE) { + // 根据笔记项的位置状态设置不同的背景资源 if (data.isSingle() || data.isOneFollowingFolder()) { setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); } else if (data.isLast()) { @@ -112,15 +133,16 @@ public class NotesListItem extends LinearLayout { } else if (data.isFirst() || data.isMultiFollowingFolder()) { setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); } else { - setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); + setBackgroundResource(NoteItemBgResources.getNoteBgMiddleRes(id)); } } else { + // 如果笔记项类型为文件夹,则设置文件夹的背景资源 setBackgroundResource(NoteItemBgResources.getFolderBgRes()); } } // 获取绑定到此 NotesListItem 的数据 public NoteItemData getItemData() { - return mItemData; + return mItemData; // 返回存储的当前笔记项数据 } -} \ No newline at end of file +} diff --git a/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java b/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java index 48125be..43b301b 100644 --- a/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java +++ b/Notes-master/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,59 +41,74 @@ 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; - + // 设置界面活动类,继承自PreferenceActivity 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"; - + + // 定义偏好设置中同步账户键(用于UI显示) private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; - + + // 定义过滤器键,用于添加账户设置 private static final String AUTHORITIES_FILTER_KEY = "authorities"; - + + // 定义账户类别,在UI中用于显示账户相关的偏好设置 private PreferenceCategory mAccountCategory; - + + // 定义一个GTaskReceiver实例,用于接收同步状态更新的广播 private GTaskReceiver mReceiver; - + + // 存储原始的Google账户列表 private Account[] mOriAccounts; - + + // 标记用户是否添加了新账户 private boolean mHasAddedAccount; - + // 创建活动时初始化界面 @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); - - /* 使用应用图标进行导航 */ + + // 设置ActionBar的返回按钮,以便用户可以通过点击应用图标返回上一级活动 getActionBar().setDisplayHomeAsUpEnabled(true); - + + // 从指定的XML资源文件加载偏好设置 addPreferencesFromResource(R.xml.preferences); + // 找到XML中定义的账户类别PreferenceCategory,并赋值给mAccountCategory mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); + // 创建GTaskReceiver实例,并注册广播接收器,用于接收同步服务的状态广播 mReceiver = new GTaskReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME); registerReceiver(mReceiver, filter); - + + // 初始化账户列表,目前为空,将在其他方法中进行填充 mOriAccounts = null; + // 创建并添加自定义的头部视图到设置界面,该视图通常用于显示额外的信息或操作 View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); getListView().addHeaderView(header, null, true); } - + // 恢复活动时刷新界面 @Override protected void onResume() { super.onResume(); - + // 如果用户添加了新账户,自动设置同步账户 if (mHasAddedAccount) { Account[] accounts = getGoogleAccounts(); @@ -113,10 +128,11 @@ public class NotesPreferenceActivity extends PreferenceActivity { } } } - + + // 刷新用户界面,包括账户偏好设置和同步按钮 refreshUI(); } - + // 销毁活动时注销广播接收器 @Override protected void onDestroy() { @@ -125,26 +141,36 @@ public class NotesPreferenceActivity extends PreferenceActivity { } super.onDestroy(); } - + // 加载账户偏好设置 private void loadAccountPreference() { + // 清空账户类别中的所有偏好设置项 mAccountCategory.removeAll(); - + + // 创建一个新的Preference实例,用于显示账户偏好设置 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)); + + // 设置偏好设置项的点击监听器 accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override public boolean onPreferenceClick(Preference preference) { + // 如果当前没有正在进行的同步操作 if (!GTaskSyncService.isSyncing()) { + // 如果同步账户名称为空,表示第一次设置账户 if (TextUtils.isEmpty(defaultAccount)) { - // 第一次设置账户 showSelectAccountAlertDialog(); } else { // 如果账户已经设置,提示用户切换账户的风险 showChangeAccountConfirmAlertDialog(); } } else { + // 如果正在同步,显示提示信息,告知用户无法在同步过程中更改账户 Toast.makeText(NotesPreferenceActivity.this, R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT) .show(); @@ -152,38 +178,49 @@ public class NotesPreferenceActivity extends PreferenceActivity { return true; } }); - + + // 将账户偏好设置项添加到账户类别中 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); - - // 设置按钮状态 + + // 根据同步服务的状态设置按钮的文本和点击事件 if (GTaskSyncService.isSyncing()) { + // 如果正在同步,设置按钮文本为取消同步,并添加点击事件以取消同步 syncButton.setText(getString(R.string.preferences_button_sync_cancel)); syncButton.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { GTaskSyncService.cancelSync(NotesPreferenceActivity.this); } }); } else { + // 如果没有同步,设置按钮文本为立即同步,并添加点击事件以开始同步 syncButton.setText(getString(R.string.preferences_button_sync_immediately)); syncButton.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { GTaskSyncService.startSync(NotesPreferenceActivity.this); } }); } + + // 根据同步账户名称是否为空设置按钮是否可用 syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); - - // 设置上次同步时间 + + // 根据同步服务的状态设置上次同步时间的显示 if (GTaskSyncService.isSyncing()) { + // 如果正在同步,显示同步进度信息 lastSyncTimeView.setText(GTaskSyncService.getProgressString()); lastSyncTimeView.setVisibility(View.VISIBLE); } else { + // 如果没有同步,显示上次同步的时间,如果没有同步过则不显示 long lastSyncTime = getLastSyncTime(this); if (lastSyncTime != 0) { lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time, @@ -195,58 +232,83 @@ public class NotesPreferenceActivity extends PreferenceActivity { } } } - + // 刷新用户界面 private void refreshUI() { + // 加载账户偏好设置 loadAccountPreference(); + // 加载同步按钮 loadSyncButton(); } - + // 显示选择账户的对话框 private void showSelectAccountAlertDialog() { + // 创建一个AlertDialog.Builder实例 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账户列表 Account[] accounts = getGoogleAccounts(); + // 获取当前设置的同步账户名称 String defAccount = getSyncAccountName(this); - + + // 保存原始账户列表 mOriAccounts = accounts; + // 重置标记,表示用户尚未添加新账户 mHasAddedAccount = false; - + if (accounts.length > 0) { + // 创建一个CharSequence数组来存储账户名称 CharSequence[] items = new CharSequence[accounts.length]; + // 由于items是CharSequence数组,需要一个final引用以便在内部类中使用 final CharSequence[] itemMapping = items; int checkedItem = -1; int index = 0; + + // 遍历账户列表,将账户名称存储到items数组中,并标记默认账户 for (Account account : accounts) { if (TextUtils.equals(account.name, defAccount)) { checkedItem = index; } items[index++] = account.name; } + + // 设置对话框为单选列表,包含所有的Google账户 dialogBuilder.setSingleChoiceItems(items, checkedItem, new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) { + // 用户选择账户后,设置同步账户并刷新UI setSyncAccount(itemMapping[which].toString()); dialog.dismiss(); refreshUI(); } }); } - + + // 加载添加账户的文本视图布局 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() { + @Override public void onClick(View v) { mHasAddedAccount = true; Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); @@ -258,145 +320,194 @@ public class NotesPreferenceActivity extends PreferenceActivity { } }); } - + // 显示更改账户确认对话框 private void showChangeAccountConfirmAlertDialog() { + // 创建一个AlertDialog.Builder实例 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, getSyncAccountName(this))); 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数组来存储对话框中的菜单项 CharSequence[] menuItemArray = new CharSequence[] { getString(R.string.preferences_menu_change_account), getString(R.string.preferences_menu_remove_account), getString(R.string.preferences_menu_cancel) }; + + // 设置对话框的菜单项 dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) { + // 根据用户选择的菜单项执行相应的操作 if (which == 0) { + // 如果用户选择更改账户,显示选择账户对话框 showSelectAccountAlertDialog(); } else if (which == 1) { + // 如果用户选择移除账户,移除同步账户并刷新UI removeSyncAccount(); refreshUI(); } } }); + + // 显示对话框 dialogBuilder.show(); } - + // 获取Google账户列表 private Account[] getGoogleAccounts() { + // 获取AccountManager实例 AccountManager accountManager = AccountManager.get(this); + // 返回所有类型为"com.google"的账户 return accountManager.getAccountsByType("com.google"); } - + // 设置同步账户 private void setSyncAccount(String account) { + // 如果当前设置的同步账户名称与新的账户名称不同 if (!getSyncAccountName(this).equals(account)) { + // 获取SharedPreferences实例 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(); - + // 清除上次同步时间 setLastSyncTime(this, 0); - + // 清除本地Gtask相关信息 new Thread(new Runnable() { + @Override public void run() { ContentValues values = new ContentValues(); + // 将Gtask ID和SYNC ID设置为空和0 values.put(NoteColumns.GTASK_ID, ""); values.put(NoteColumns.SYNC_ID, 0); + // 更新本地Notes数据库中的相关字段 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(); } } - + // 移除同步账户 private void removeSyncAccount() { + // 获取SharedPreferences实例 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相关信息 new Thread(new Runnable() { + @Override public void run() { ContentValues values = new ContentValues(); + // 将Gtask ID和SYNC ID设置为空和0 values.put(NoteColumns.GTASK_ID, ""); values.put(NoteColumns.SYNC_ID, 0); + // 更新本地Notes数据库中的相关字段 getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } }).start(); } - + // 获取同步账户名称 public static String getSyncAccountName(Context context) { + // 获取SharedPreferences实例 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); + // 返回存储的同步账户名称,如果未设置则返回空字符串 return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } - + // 设置上次同步时间 public static void setLastSyncTime(Context context, long time) { + // 获取SharedPreferences实例 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); + + // 将上次同步时间存储到偏好设置中 editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); + // 提交偏好设置更改 editor.commit(); } - + // 获取上次同步时间 public static long getLastSyncTime(Context context) { + // 获取SharedPreferences实例 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); + // 返回存储的上次同步时间,如果未设置则返回0 return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); } - + // 广播接收器,用于接收同步状态更新 private class GTaskReceiver extends BroadcastReceiver { - + // 接收到广播时执行的操作 @Override public void onReceive(Context context, Intent intent) { + // 刷新用户界面,包括账户偏好设置和同步按钮 refreshUI(); + + // 如果广播中包含同步正在进行的标志 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)); } - } } - + // 选项菜单项点击事件处理 + @Override 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); return true; default: + // 对于其他选项,返回false表示不处理 return false; } } -} \ No newline at end of file +} diff --git a/代码注释统计.txt b/代码注释统计.txt index 58c1dd9..b40d6c8 100644 --- a/代码注释统计.txt +++ b/代码注释统计.txt @@ -1,7 +1,7 @@ 张晋菡: -ui中14段代码 +ui中后11段代码 程星桦: - +ui中前3段代码 张鹏展: gtask中exception和remote中共6段代码 tool中4段代码