diff --git a/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/main/java/net/micode/notes/ui/NoteEditActivity.java index 494bad6..c6762bf 100644 --- a/src/main/java/net/micode/notes/ui/NoteEditActivity.java +++ b/src/main/java/net/micode/notes/ui/NoteEditActivity.java @@ -655,10 +655,12 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); mNoteBgColorSelector.setVisibility(View.GONE); } else if (sFontSizeBtnsMap.containsKey(id)) { + //检查字体大小选择器按钮是否被点击。隐藏当前选择的字体大小,设置新的大小,并显示新的选择 findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); mFontSizeId = sFontSizeBtnsMap.get(id); mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); + //处理基于检查表模式或常规模式的字体大小更改 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { getWorkingText(); switchToListMode(mWorkingNote.getContent()); @@ -666,31 +668,44 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli mNoteEditor.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); } + //隐藏字体大小选择器 mFontSizeSelector.setVisibility(View.GONE); } } + /** + *覆盖onBackPressed方法,在完成活动之前处理特定的动作。*/ @Override public void onBackPressed() { + //在完成活动之前检查并清除任何设置状态 if (clearSettingState()) { return; } - + //保存当前笔记并调用父类方法 saveNote(); super.onBackPressed(); } - + /** + * 通过隐藏背景颜色或字体大小选择器(如果可见)清除设置状态。 + * 返回True如果任何设置状态被清除,否则返回false。*/ private boolean clearSettingState() { + //如果背景颜色选择器可见,检查并隐藏 if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { mNoteBgColorSelector.setVisibility(View.GONE); return true; } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { + //如果可见,检查并隐藏字体大小选择器 mFontSizeSelector.setVisibility(View.GONE); return true; } + //如果未清除设置状态,则返回false return false; } - + /*** + * 此方法负责处理便笺背景颜色的更改。 + * 它找到与工作笔记的背景颜色 ID 对应的视图,并将其可见性设置为 VISIBLE。 + * 它将笔记编辑器面板的背景资源和头视图面板分别设置为工作笔记的背景颜色和标题背景资源 ID。 + */ public void onBackgroundColorChanged() { findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); @@ -698,13 +713,18 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); } + /** + * 在显示选项菜单之前调用此方法。*/ @Override public boolean onPrepareOptionsMenu(Menu menu) { + //检查活动是否结束,如果是,返回true if (isFinishing()) { return true; } + //清除设置状态并从菜单中删除所有项目 clearSettingState(); menu.clear(); + //根据工作笔记的文件夹ID膨胀适当的菜单 if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { getMenuInflater().inflate(R.menu.call_note_edit, menu); } else { @@ -715,11 +735,13 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli } else if (mWorkingNote.getTopId() == 0) { menu.findItem(R.id.menu_cancel_top).setVisible(false); } + //检查工作笔记的checkListMode,并相应地设置菜单项的标题 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode); } else { menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); } + //检查工作笔记是否有时钟提醒,并相应地设置菜单项的可见性 if (mWorkingNote.hasClockAlert()) { menu.findItem(R.id.menu_alert).setVisible(false); } else { @@ -728,9 +750,14 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli return true; } + /** + * 这是adnriod小米便签生命周期的一部分。当用户在选择菜单选择一个像的时候调用*/ @Override public boolean onOptionsItemSelected(MenuItem item) { + //获取选中菜单项的ID int itemId = item.getItemId(); + //检查哪个菜单项被选中 + //如果选择了“New Note”,则创建新笔记 if (itemId == R.id.menu_new_note) { createNewNote(); } else if (itemId == R.id.menu_revoke) { @@ -740,6 +767,7 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli } else if (itemId == R.id.menu_cancel_top) { mWorkingNote.setTop((mWorkingNote.getTopId()) == 0 ? "1" : "0"); } else if (itemId == 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); @@ -754,19 +782,25 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli builder.setNegativeButton(android.R.string.cancel, null); builder.show(); } else if (itemId == R.id.menu_font_size) { + //如果选择了“字体大小”,显示字体大小选择器 mFontSizeSelector.setVisibility(View.VISIBLE); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); } else if (itemId == R.id.menu_list_mode) { + //如果选择“列表模式”,可以在检查表模式和常规模式之间切换 mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ? TextNote.MODE_CHECK_LIST : 0); } else if (itemId == R.id.menu_share) { + //如果选择“分享”,检索笔记内容并发送 getWorkingText(); sendTo(this, mWorkingNote.getContent()); } else if (itemId == R.id.menu_send_to_desktop) { + //如果选择“发送到桌面”,则将笔记发送到桌面 sendToDesktop(); } else if (itemId == R.id.menu_alert) { + //选择“设置提醒”,设置提醒 setReminder(); } else if (itemId == R.id.menu_delete_remind) { + //如果选择“删除提醒”,则删除该笔记的提醒 mWorkingNote.setAlertDate(0, false); } else if (itemId == R.id.menu_font_select) { showSingleAlertDiglog(); @@ -788,13 +822,21 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli return true; } + /** + *这个函数通过启动DateTimePickerDialog来设置当前工作笔记的提醒。 + *对话框允许用户选择提醒的日期和时间。 + *一旦用户选择了日期和时间,就会设置工作笔记的提醒日期。*/ private void setReminder() { + //创建一个新的DateTimePickerDialog实例,将当前系统时间作为默认时间。 DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis()); + //设置监听器从DateTimePickerDialog中捕获选定的日期和时间。 d.setOnDateTimeSetListener(new OnDateTimeSetListener() { public void OnDateTimeSet(AlertDialog dialog, long date) { + //设置工作笔记的提醒日期与所选日期并启用提醒。 mWorkingNote.setAlertDate(date, true); } }); + //向用户显示DateTimePickerDialog。 d.show(); } @@ -802,25 +844,49 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli * Share note to apps that support {@link Intent#ACTION_SEND} action * and {@text/plain} type */ + /** + *此功能允许用户共享提供的文本信息(注内容) + *到其他可以处理ACTION_SEND意图的MIME类型为“text/plain”的应用程序。 + * @param context 调用函数的上下文。 + * @param info 需要共享的文本信息(注内容)。 + */ private void sendTo(Context context, String info) { + ///创建一个带有ACTION_SEND动作的Intent来共享数据。 Intent intent = new Intent(Intent.ACTION_SEND); + //添加文本信息(注内容)作为一个额外的意图。 intent.putExtra(Intent.EXTRA_TEXT, info); + //设置intent的MIME类型为"text/plain"来指定要发送的数据类型。 intent.setType("text/plain"); + //以共享数据为目的启动activity context.startActivity(intent); } + /** + *这个函数通过启动一个新的NoteEditActivity来创建一个新的笔记。 + *在开始新活动之前,它会保存任何当前编辑的笔记,以确保安全。 + *在插入或编辑模式下,根据意图设置的动作开始新的笔记。*/ private void createNewNote() { // Firstly, save current editing notes saveNote(); // For safety, start a new NoteEditActivity finish(); + //创建一个新的意图来启动NoteEditActivity来插入或编辑注释。 Intent intent = new Intent(this, NoteEditActivity.class); + //设置插入或编辑注释的意图动作。 intent.setAction(Intent.ACTION_INSERT_OR_EDIT); + //将当前工作笔记的文件夹ID作为额外参数传递给新活动。 intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); + //启动NoteEditActivity,创建一个新的注释。 startActivity(intent); } + /** + *此方法负责删除当前工作笔记。 + *如果该笔记在数据库中存在,则判断该笔记是否处于同步模式。 + *如果不在同步模式,它要么删除笔记或移动到垃圾文件夹。 + *如果在同步模式下,它会将笔记移动到垃圾文件夹。 + *最后,将工作笔记标记为已删除。*/ private void deleteCurrentNote() { if (mWorkingNote.existInDatabase()) { HashSet ids = new HashSet(); @@ -843,6 +909,10 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli mWorkingNote.markDeleted(true); } + /** + *这个方法检查应用程序是否处于同步模式。 + *它通过在首选项中检查同步帐户名称的长度来实现。 + *如果应用程序处于同步模式,则返回True,否则返回false。*/ private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } @@ -866,7 +936,13 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli } } - + /** + *这个方法被触发时,时钟警报为一个笔记被改变。 + *它首先检查工作笔记是否存在于数据库中。如果没有,则保存该注释。 + *然后,它创建一个由告警触发的意图,设置一个PendingIntent,然后 + *管理AlarmManager处理调度或取消告警。 + * @param date 告警产生的日期。 + * @param set 布尔值,表示设置或取消告警。*/ public void onClockAlertChanged(long date, boolean set) { /** * User could set clock to an unsaved note, so before setting the @@ -875,12 +951,18 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli if (!mWorkingNote.existInDatabase()) { saveNote(); } + //检查笔记是否有一个有效的ID。 if (mWorkingNote.getNoteId() > 0) { + //创建一个由告警触发的意图。 Intent intent = new Intent(this, AlarmReceiver.class); intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); + //为广播创建PendingIntent PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); + //获取AlarmManager服务 AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); + //显示一个警告头(假设它是一个UI操作) showAlertHeader(); + //检查是否取消或设置告警。 if (!set) { alarmManager.cancel(pendingIntent); } else { @@ -896,34 +978,44 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli showToast(R.string.error_note_empty_for_clock); } } - + /**这个方法在小部件被改变时被调用。 + *它更新小部件以反映底层数据的任何更改。*/ public void onWidgetChanged() { updateWidget(); } public void onEditTextDelete(int index, String text) { + // 获取 mEditTextList 中子视图的数量 int childCount = mEditTextList.getChildCount(); + // 如果容器中只有一个子视图,直接返回,避免操作这个唯一的子视图 if (childCount == 1) { return; } - + // 对容器中从 index + 1 到末尾的子视图进行操作 for (int i = index + 1; i < childCount; i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) .setIndex(i - 1); } - + // 从容器中删除索引为 index 的子视图 mEditTextList.removeViewAt(index); + // 找到需要修改的 NoteEditText 对象 NoteEditText edit = null; if (index == 0) { + // 如果删除的是第一个子视图,获取容器中的第一个子视图的 NoteEditText 对象 edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( R.id.et_edit_text); } else { + // 否则获取索引为 index - 1 的子视图的 NoteEditText 对象 edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( R.id.et_edit_text); } + // 获取当前文本长度 int length = edit.length(); + // 在找到的 NoteEditText 对象的末尾追加传入的文本 edit.append(text); + // 请求焦点 edit.requestFocus(); + // 将光标设置在追加文本后的位置(即之前文本的长度) edit.setSelection(length); } @@ -931,44 +1023,73 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli /** * Should not happen, check for debug */ + // 检查传入的索引是否超出 mEditTextList 中子视图的范围,如果超出则打印错误日志 if (index > mEditTextList.getChildCount()) { Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); } - + // 根据传入的文本和索引获取一个新的视图 View view = getListItem(text, index); + // 将新创建的视图插入到 mEditTextList 容器的指定位置 index mEditTextList.addView(view, index); + // 获取新插入的视图中的 NoteEditText 对象 NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + // 请求焦点 edit.requestFocus(); + // 将光标设置在编辑框的开头位置 edit.setSelection(0); + // 对 mEditTextList 中从 index + 1 到末尾的子视图进行操作 for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) .setIndex(i); } } + /** + * 切换到列表模式的方法,根据传入的文本生成列表视图。 + * @param text 要显示的文本,其中每行作为一个列表项。 + */ private void switchToListMode(String text) { + // 移除列表视图中的所有子视图 mEditTextList.removeAllViews(); + // 将传入的文本按换行符分割成数组 String[] items = text.split("\n"); + // 初始化索引 int index = 0; + // 遍历文本数组,生成列表项并添加到列表视图中 for (String item : items) { if (!TextUtils.isEmpty(item)) { mEditTextList.addView(getListItem(item, index)); index++; } } + // 添加一个空的列表项作为新的可编辑项 mEditTextList.addView(getListItem("", index)); + // 获取新添加的可编辑项中的编辑框,并请求焦点 mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); - + // 隐藏笔记编辑器视图 mNoteEditor.setVisibility(View.GONE); + // 显示列表视图 mEditTextList.setVisibility(View.VISIBLE); } + /** + * 获取带有查询结果高亮的 Spannable 对象。 + * @param fullText 完整的文本内容。 + * @param userQuery 用户的查询字符串。 + * @return 包含高亮效果的 Spannable 对象。 + */ private Spannable getHighlightQueryResult(String fullText, String userQuery) { + // 创建一个 SpannableString 对象,用于处理富文本 SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); + // 检查用户查询字符串是否非空 if (!TextUtils.isEmpty(userQuery)) { + // 使用正则表达式创建匹配用户查询的 Pattern 对象 mPattern = Pattern.compile(userQuery); + // 使用 Pattern 对象在完整文本中查找匹配项 Matcher m = mPattern.matcher(fullText); + // 初始化起始位置 int start = 0; + // 遍历匹配项并添加背景色高亮效果 while (m.find(start)) { spannable.setSpan( new BackgroundColorSpan(this.getResources().getColor( @@ -977,14 +1098,21 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli start = m.end(); } } + // 返回包含高亮效果的 Spannable 对象 return spannable; } - + /** + * 方法用于创建具有可编辑文本字段和复选框的自定义列表项视图。 + * 它还包括处理复选框更改和调整相关文本外观的逻辑。*/ private View getListItem(String item, int index) { + // 从布局文件中实例化列表项视图 View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); + // 查找NoteEditText并根据资源ID设置其文本外观 final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); + // 查找视图中的复选框 CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); + // 设置复选框更改监听器以切换相关文本的删除线 cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { @@ -995,6 +1123,7 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli } }); + // 检查项目中是否包含特定标签,并相应地调整复选框和文本 if (item.startsWith(TAG_CHECKED)) { cb.setChecked(true); edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); @@ -1004,18 +1133,24 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); } - + // 设置NoteEditText的监听器和属性 edit.setOnTextViewChangeListener(this); edit.setIndex(index); edit.setText(getHighlightQueryResult(item, mUserQuery)); + // 返回定制的列表项视图 return view; } + /** + * 回调方法 ,通过显示或隐藏基于文本存在的相关复选框 + * 对可编辑文本字段中的文本更改作出反应。*/ public void onTextChange(int index, boolean hasText) { + // 检查提供的索引是否在父布局中子视图的范围内 if (index >= mEditTextList.getChildCount()) { Log.e(TAG, "Wrong index, should not happen"); return; } + // 根据相关文本是否存在,显示或隐藏复选框 if (hasText) { mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); } else { @@ -1023,28 +1158,46 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli } } + /** + * 处理检查列表模式变化的方法。当检查列表模式从旧模式变为新模式时调用。 + * @param oldMode 之前的模式 + * @param newMode 新的模式 + */ public void onCheckListModeChanged(int oldMode, int newMode) { + // 如果新模式为检查列表模式 if (newMode == TextNote.MODE_CHECK_LIST) { + // 切换到列表模式并将当前编辑器文本传递给切换方法 switchToListMode(mNoteEditor.getText().toString()); } else { + // 如果不是检查列表模式 if (!getWorkingText()) { + // 如果没有获取工作文本成功,则将工作笔记的工作文本设置为替换未选中标签后的内容 mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", "")); } + // 将笔记编辑器文本设置为高亮查询结果 mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); + // 隐藏编辑文本列表,显示笔记编辑器 mEditTextList.setVisibility(View.GONE); mNoteEditor.setVisibility(View.VISIBLE); } } - + /** + * 获取工作文本的方法,用于在不同模式下保存当前编辑的文本。 + * @return 如果有已选中的项目,则返回true,否则返回false + */ private boolean getWorkingText() { boolean hasChecked = false; + // 如果工作笔记处于检查列表模式 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { StringBuilder sb = new StringBuilder(); + // 遍历编辑文本列表的所有子项 for (int i = 0; i < mEditTextList.getChildCount(); i++) { View view = mEditTextList.getChildAt(i); NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + // 如果编辑文本非空 if (!TextUtils.isEmpty(edit.getText())) { + // 检查复选框是否被选中,根据情况添加已选中或未选中标签 if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); hasChecked = true; @@ -1053,16 +1206,19 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli } } } + // 将构建的文本设置为工作笔记的工作文本 mWorkingNote.setWorkingText(sb.toString()); } else { + // 如果不是检查列表模式,直接将笔记编辑器的文本设置为工作文本 mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); } + // 返回是否有已选中的项目 return hasChecked; } private boolean saveNote() { - getWorkingText(); - boolean saved = mWorkingNote.saveNote(); + getWorkingText();// 获取正在编辑的文本内容 + boolean saved = mWorkingNote.saveNote();// 保存当前笔记 if (saved) { /** * There are two modes from List view to edit view, open one note, @@ -1073,9 +1229,13 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli */ setResult(RESULT_OK); } - return saved; + return saved;// 返回保存状态 } + /**将当前编辑的笔记发送到桌面,前提是该笔记已存在于数据库中。 + *如果存在,它会尝试创建一个桌面快捷方式,并显示相关提示消息。 + * 如果笔记不存在或内容为空,会记录错误并提醒用户。 + */ private void sendToDesktop() { /** * Before send message to home, we should make sure that current @@ -1111,6 +1271,9 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli } } + /**生成快捷方式图标的标题。 + * 它会移除特定标记后,根据设定的最大长度返回缩短后的标题。 + */ private String makeShortcutIconTitle(String content) { content = content.replace(TAG_CHECKED, ""); content = content.replace(TAG_UNCHECKED, ""); @@ -1118,6 +1281,9 @@ public class NoteEditActivity<关闭> extends AppCompatActivity implements OnCli SHORTCUT_ICON_TITLE_MAX_LEN) : content; } + /**用于显示 Toast(提示消息)。 + * 第一个函数显示短暂时长的消息,而第二个函数则允许指定显示时长。 + */ private void showToast(int resId) { showToast(resId, Toast.LENGTH_SHORT); } diff --git a/src/main/java/net/micode/notes/ui/NotesListAdapter.java b/src/main/java/net/micode/notes/ui/NotesListAdapter.java index 51c9cb9..2660fca 100644 --- a/src/main/java/net/micode/notes/ui/NotesListAdapter.java +++ b/src/main/java/net/micode/notes/ui/NotesListAdapter.java @@ -30,56 +30,88 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; - +/* + * 功能:直译为便签表连接器,继承了CursorAdapter,它为cursor和ListView提供了连接的桥梁。 + * 所以NotesListAdapter实现的是鼠标和编辑便签链接的桥梁 + */ public class NotesListAdapter extends CursorAdapter { private static final String TAG = "NotesListAdapter"; private Context mContext; private HashMap mSelectedIndex; - private int mNotesCount; - private boolean mChoiceMode; + private int mNotesCount;//便签数量 + private boolean mChoiceMode;//选择模式标记 + /* + * 桌面widget的属性,包括编号和类型 + */ public static class AppWidgetAttribute { public int widgetId; public int widgetType; }; + /* + * 函数功能:初始化便签链接器 + * 函数实现:根据传进来的内容设置相关变量 + */ public NotesListAdapter(Context context) { - super(context, null); - mSelectedIndex = new HashMap(); - mContext = context; - mNotesCount = 0; + super(context, null);//调用父类的构造方法,并传入context和null作为参数 + mSelectedIndex = new HashMap();// 初始化一个HashMap,用于跟踪每个便签项是否被选中 + mContext = context;// 存储上下文引用,通常用于后续的操作,比如访问资源 + mNotesCount = 0;//初始化便签的数量为0 } + /* + * 函数功能:新建一个视图来存储光标所指向的数据 + * 函数实现:使用兄弟类NotesListItem新建一个项目选项 + */ @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return new NotesListItem(context); + return new NotesListItem(context);//NoteListItem就是下一个类 } + /* + * 函数功能:将已经存在的视图和鼠标指向的数据进行捆绑 + * 函数实现:如下注释 + */ @Override public void bindView(View view, Context context, Cursor cursor) { - if (view instanceof NotesListItem) { + if (view instanceof NotesListItem) { //如果view是NotesListItem的一个实例 NoteItemData itemData = new NoteItemData(context, cursor); ((NotesListItem) view).bind(context, itemData, mChoiceMode, isSelectedItem(cursor.getPosition())); + //则新建一个项目选项并且用bind跟将view和鼠标,内容,便签数据捆绑在一起 } } + /* + * 函数功能:设置勾选框 + * 函数实现:如下注释 + */ public void setCheckedItem(final int position, final boolean checked) { - mSelectedIndex.put(position, checked); - notifyDataSetChanged(); + mSelectedIndex.put(position, checked);//根据定位和是否勾选设置下标 + notifyDataSetChanged();//在修改后刷新activity } - + /* + * 函数功能:判断单选按钮是否勾选 + */ public boolean isInChoiceMode() { return mChoiceMode; } - + /* + * 函数功能:设置单项选项框 + * 函数实现:重置下标并且根据参数mode设置选项 + */ public void setChoiceMode(boolean mode) { mSelectedIndex.clear(); mChoiceMode = mode; } + /* + * 函数功能:选择全部选项 + * 函数实现:如下注释 + */ public void selectAll(boolean checked) { - Cursor cursor = getCursor(); + Cursor cursor = getCursor();//获取光标位置 for (int i = 0; i < getCount(); i++) { if (cursor.moveToPosition(i)) { if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { @@ -87,30 +119,39 @@ public class NotesListAdapter extends CursorAdapter { } } } + //遍历所有光标可用的位置在判断为便签类型之后勾选单项框 } - + /* + * 函数功能:建立选择项的下标列表 + * 函数实现:如下注释 + */ public HashSet getSelectedItemIds() { - HashSet itemSet = new HashSet(); + HashSet itemSet = new HashSet();//建立hash表 for (Integer position : mSelectedIndex.keySet()) { - if (mSelectedIndex.get(position) == true) { + //遍历所有的关键 + if (mSelectedIndex.get(position) == true) {//若光标位置可用 Long id = getItemId(position); - if (id == Notes.ID_ROOT_FOLDER) { + if (id == Notes.ID_ROOT_FOLDER) { //原文件不需要添加 Log.d(TAG, "Wrong item id, should not happen"); } else { - itemSet.add(id); + itemSet.add(id);//将id该下标加入到选项集合中 } } } return itemSet; } - + /* + * 函数功能:建立桌面Widget的选项表 + * 函数实现:如下注释 + */ public HashSet getSelectedWidget() { - HashSet itemSet = new HashSet(); - for (Integer position : mSelectedIndex.keySet()) { - if (mSelectedIndex.get(position) == true) { + HashSet itemSet = new HashSet();//建立hash表 + for (Integer position : mSelectedIndex.keySet()) {//遍历所有关键 + if (mSelectedIndex.get(position) == true) {//若光标位置可用 Cursor c = (Cursor) getItem(position); if (c != null) { + //光标位置可用的话就建立新的Widget属性并编辑下标和类型,最后添加到选项集中 AppWidgetAttribute widget = new AppWidgetAttribute(); NoteItemData item = new NoteItemData(mContext, c); widget.widgetId = item.getWidgetId(); @@ -127,58 +168,80 @@ public class NotesListAdapter extends CursorAdapter { } return itemSet; } - + /* + * 函数功能:获取选项个数 + * 函数实现:如下注释 + */ public int getSelectedCount() { Collection values = mSelectedIndex.values(); + //获取选项下标的值 if (null == values) { return 0; } Iterator iter = values.iterator(); - int count = 0; + int count = 0; //初始化叠加器 while (iter.hasNext()) { - if (true == iter.next()) { + if (true == iter.next()) {//如果value的值为真,计数器+1 count++; } } return count; } - + /* + * 函数功能:判断是否全部选中 + * 函数实现:如下注释 + */ public boolean isAllSelected() { int checkedCount = getSelectedCount(); return (checkedCount != 0 && checkedCount == mNotesCount); + //获取选项数看是否等于便签的个数 } - + /* + * 函数功能:判断是否为选项表 + * 函数实现:通过传递的下标来确定 + */ public boolean isSelectedItem(final int position) { if (null == mSelectedIndex.get(position)) { return false; } return mSelectedIndex.get(position); } - + /* + * 函数功能:在activity内容发生局部变动的时候回调该函数计算便签的数量 + * 函数实现:如下注释 + */ @Override protected void onContentChanged() { super.onContentChanged(); + //执行基类函数 calcNotesCount(); } - + /* + * 函数功能:在activity光标发生局部变动的时候回调该函数计算便签的数量 + */ @Override public void changeCursor(Cursor cursor) { - super.changeCursor(cursor); + super.changeCursor(cursor);//执行基类函数 calcNotesCount(); } - + /* + * 函数功能:计算便签数量 + * + */ private void calcNotesCount() { mNotesCount = 0; for (int i = 0; i < getCount(); i++) { + //获取总数同时遍历 Cursor c = (Cursor) getItem(i); if (c != null) { if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { - mNotesCount++; + mNotesCount++;//若该位置不为空并且文本类型为便签就+1 } } else { Log.e(TAG, "Invalid cursor"); return; } + //否则报错 } } } diff --git a/src/main/java/net/micode/notes/ui/NotesListItem.java b/src/main/java/net/micode/notes/ui/NotesListItem.java index 2746619..455c12e 100644 --- a/src/main/java/net/micode/notes/ui/NotesListItem.java +++ b/src/main/java/net/micode/notes/ui/NotesListItem.java @@ -29,37 +29,55 @@ import net.micode.notes.data.Notes; import net.micode.notes.tool.DataUtils; import net.micode.notes.tool.ResourceParser.NoteItemBgResources; - +//创建便签列表项目选项 public class NotesListItem extends LinearLayout { - private ImageView mAlert; - private TextView mTitle; - private TextView mTime; + private ImageView mAlert;//闹钟图片 + private TextView mTitle;//标题 + private TextView mTime;//时间 private TextView mCallName; - private NoteItemData mItemData; - private CheckBox mCheckBox; + private NoteItemData mItemData;//标签数据 + private CheckBox mCheckBox;//打钩框 private ImageView mTop; + /*初始化基本信息*/ + /* + * 类构造函数:用于创建 NotesListItem 实例,并初始化布局和组件 + */ public NotesListItem(Context context) { - super(context); + super(context);// 调用父类构造函数,初始化父类部分 + // 从 XML 布局文件中扩张视图到这个对象中 inflate(context, R.layout.note_item, this); - mAlert = (ImageView) findViewById(R.id.iv_alert_icon); - mTitle = (TextView) findViewById(R.id.tv_title); - mTime = (TextView) findViewById(R.id.tv_time); - mCallName = (TextView) findViewById(R.id.tv_name); - mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); + // 找到 XML 布局文件中定义的各个组件,并将它们绑定到相应的成员变量 + mAlert = (ImageView) findViewById(R.id.iv_alert_icon);// 便签项中的提醒图标 + mTitle = (TextView) findViewById(R.id.tv_title); // 便签项中的标题文字 + mTime = (TextView) findViewById(R.id.tv_time); // 便签项中的时间文字 + mCallName = (TextView) findViewById(R.id.tv_name); // 便签项中的名字文字 + mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); // 便签项中的复选框 mTop = (ImageView) findViewById(R.id.iv_top_icon); } + ///根据data的属性对各个控件的属性的控制,主要是可见性Visibility,内容setText,格式setTextAppearance + + /** + * 函数功能:绑定数据到 NotesListItem 视图,更新显示的内容和样式 + * @param context 上下文环境,用于访问资源 + * @param data 要绑定的 NoteItemData 数据实例 + * @param choiceMode 是否处于选择模式 + * @param checked 该项目是否被勾选 + */ public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { + // 根据是否处于选择模式和便签类型来显示或隐藏复选框 if (choiceMode && data.getType() == Notes.TYPE_NOTE) { mCheckBox.setVisibility(View.VISIBLE); mCheckBox.setChecked(checked); } else { mCheckBox.setVisibility(View.GONE); } - + // 更新列表项数据对象 mItemData = data; + // 设置控件属性,基于数据项的id和parentId,视图表现有三种情况 if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { + // 配置为呼叫记录文件夹视图 mCallName.setVisibility(View.GONE); mAlert.setVisibility(View.VISIBLE); mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); @@ -67,10 +85,12 @@ public class NotesListItem extends LinearLayout { + context.getString(R.string.format_folder_files_count, data.getNotesCount())); mAlert.setImageResource(R.drawable.call_record); } else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { + // 配置为呼叫记录子项视图 mCallName.setVisibility(View.VISIBLE); mCallName.setText(data.getCallName()); mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem); mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + // 闹钟图标的显示与否取决于是否设置了闹钟提醒 if (data.hasAlert()) { mAlert.setImageResource(R.drawable.clock); mAlert.setVisibility(View.VISIBLE); @@ -78,9 +98,10 @@ public class NotesListItem extends LinearLayout { mAlert.setVisibility(View.GONE); } } else { + // 配置为一般便签项视图 mCallName.setVisibility(View.GONE); mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); - + // 如果是文件夹类型,显示包含数量信息的标题;否则,显示便签的摘要 if (data.getType() == Notes.TYPE_FOLDER) { mTitle.setText(data.getSnippet() + context.getString(R.string.format_folder_files_count, @@ -102,26 +123,32 @@ public class NotesListItem extends LinearLayout { mTop.setVisibility((View.GONE)); } } + // 设置修改时间文本 mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); + // 根据数据更新背景,此处setBackground方法未给出,假设它根据 NoteItemData 来设置视图背景 setBackground(data); } - + //根据data的文件属性来设置背景 private void setBackground(NoteItemData data) { int id = data.getBgColorId(); + //若是note型文件,则4种情况,对于4种不同情况的背景来源 if (data.getType() == Notes.TYPE_NOTE) { + //单个数据并且只有一个子文件夹 if (data.isSingle() || data.isOneFollowingFolder()) { setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); - } else if (data.isLast()) { + } else if (data.isLast()) {//是最后一个数据 setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); } else if (data.isFirst() || data.isMultiFollowingFolder()) { + //是一个数据并有多个子文件夹 setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); } else { setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); } } else { + //若不是note直接调用文件夹的背景来源 setBackgroundResource(NoteItemBgResources.getFolderBgRes()); } }