diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 28431d4..0000000 --- a/.gitignore +++ /dev/null @@ -1,116 +0,0 @@ -/src/Notes/app/build -###Android### -# Built application files -*.apk -*.ap_ - -# Files for the ART/Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -/src/Notes/app/bin/ -/src/Notes/app/gen/ -/src/Notes/app/out/ - -# Gradle files -/src/Notes/app/.gradle/ -/src/Notes/app/build/ - -# Local configuration file (sdk path, etc) -/src/Notes/app/local.properties - -# Proguard folder generated by Eclipse -/src/Notes/app/proguard/ - -# Log Files -*.log - -# Crashlytics plugin (for Android Studio and IntelliJ) -/src/Notes/app/com_crashlytics_export_strings.xml -/src/Notes/app/crashlytics.properties -/src/Notes/app/crashlytics-build.properties -/src/Notes/app/fabric.properties - -# Android Studio Navigation editor temp files -/src/Notes/app/.navigation/ - -# Android Studio captures folder -captures/ - -# Keystore files -*.jks - -# External native build folder generated in Android Studio 2.2 and later -.externalNativeBuild - -###macOS### -*.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -###Linux### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -###Windows### -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk -###IntelliJ### -*.iml -*.ipr -*.iws -/src/Notes/app/.idea/ -/src/Notes/app/libs/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 69b28af..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 4757b3d..2989e2d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# Notes +# 小米便签 diff --git a/doc/小米便签开源代码的泛读报告.docx b/doc/小米便签开源代码的泛读报告.docx index 2a5d451..c33be62 100644 Binary files a/doc/小米便签开源代码的泛读报告.docx and b/doc/小米便签开源代码的泛读报告.docx differ diff --git a/readme.md b/readme.md deleted file mode 100644 index 4757b3d..0000000 --- a/readme.md +++ /dev/null @@ -1,2 +0,0 @@ -# Notes - diff --git a/src/Notes/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/src/Notes/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 954fdfe..927f3d8 100644 Binary files a/src/Notes/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/src/Notes/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/src/Notes/.gradle/buildOutputCleanup/cache.properties b/src/Notes/.gradle/buildOutputCleanup/cache.properties index 299c01e..0eba958 100644 --- a/src/Notes/.gradle/buildOutputCleanup/cache.properties +++ b/src/Notes/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Sun Apr 02 08:57:27 CST 2023 -gradle.version=7.5 +#Sun Apr 23 18:04:59 CST 2023 +gradle.version=8.0 diff --git a/src/Notes/.gradle/buildOutputCleanup/outputFiles.bin b/src/Notes/.gradle/buildOutputCleanup/outputFiles.bin index 1d2c594..5e353d5 100644 Binary files a/src/Notes/.gradle/buildOutputCleanup/outputFiles.bin and b/src/Notes/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/src/Notes/.gradle/file-system.probe b/src/Notes/.gradle/file-system.probe index efea422..9cc85ce 100644 Binary files a/src/Notes/.gradle/file-system.probe and b/src/Notes/.gradle/file-system.probe differ diff --git a/src/Notes/app/build.gradle b/src/Notes/app/build.gradle index ae0b4c4..1e45ad2 100644 --- a/src/Notes/app/build.gradle +++ b/src/Notes/app/build.gradle @@ -17,4 +17,5 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' } } + namespace 'net.micode.notes' } diff --git a/src/Notes/app/src/main/AndroidManifest.xml b/src/Notes/app/src/main/AndroidManifest.xml index 41511bc..96920fb 100644 --- a/src/Notes/app/src/main/AndroidManifest.xml +++ b/src/Notes/app/src/main/AndroidManifest.xml @@ -17,11 +17,11 @@ + android:versionName="0.1"> - @@ -37,19 +37,19 @@ + android:label="@string/app_name"> - - + + + android:windowSoftInputMode="adjustPan"> @@ -60,14 +60,16 @@ + android:theme="@style/NoteTheme"> - + @@ -75,6 +77,7 @@ + @@ -93,14 +96,14 @@ + android:exported="false" + android:multiprocess="true" /> + android:exported="true" + android:label="@string/app_widget2x2"> @@ -112,11 +115,27 @@ android:resource="@xml/widget_2x_info" /> + + + + + + + + + + + + android:exported="true" + android:label="@string/app_widget4x4"> @@ -130,7 +149,8 @@ - @@ -139,26 +159,22 @@ - + android:process=":remote"> - + android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"> - + android:theme="@android:style/Theme.Holo.Light"> - + android:exported="false"> = HOURS_IN_HALF_DAY; inflate(context, R.layout.datetime_picker, this); +// 首先调用了父类 ViewGroup 的构造函数 super(context) 来初始化 DateTimePicker 实例。然后,代码使用 Calendar.getInstance() 获取一个 Calendar 对象,该对象表示当前日期和时间。变量 mIsAm 被初始化为当前小时数是否大于等于 12,以确定当前用户选择的是 AM 还是 PM。 mDateSpinner = (NumberPicker) findViewById(R.id.date); mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL); mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL); mDateSpinner.setOnValueChangedListener(mOnDateChangedListener); +// 获取了布局文件中 ID 为 date 的 NumberPicker 控件,并将其赋值给 mDateSpinner 变量。然后,使用 setMinValue() 和 setMaxValue() 方法将 mDateSpinner 的最小值和最大值分别设置为 DATE_SPINNER_MIN_VAL 和 DATE_SPINNER_MAX_VAL。使用 setOnValueChangedListener() 方法将 mDateSpinner 的值更改监听器设置为 mOnDateChangedListener。这意味着当 mDateSpinner 的值更改时,将会调用 mOnDateChangedListener 中的方法来处理这个事件。 mHourSpinner = (NumberPicker) findViewById(R.id.hour); mHourSpinner.setOnValueChangedListener(mOnHourChangedListener); @@ -190,13 +205,18 @@ public class DateTimePicker extends FrameLayout { mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL); mMinuteSpinner.setOnLongPressUpdateInterval(100); mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener); +// 获取了布局文件中 ID 为 hour 和 minute 的 NumberPicker 控件,并将它们分别赋值给 mHourSpinner 和 mMinuteSpinner 变量。然后,使用 setOnValueChangedListener() 方法将 mHourSpinner 和 mMinuteSpinner 控件的值更改监听器分别设置为 mOnHourChangedListener 和 mOnMinuteChangedListener。 +// 接下来,使用 setMinValue() 和 setMaxValue() 方法将 mMinuteSpinner 的最小值和最大值分别设置为 MINUT_SPINNER_MIN_VAL 和 MINUT_SPINNER_MAX_VAL,以限制分钟选择器的范围。 +// 最后,使用 setOnLongPressUpdateInterval() 方法将 mMinuteSpinner 的长按更新间隔设置为 100 毫秒。这意味着当用户长按 mMinuteSpinner 中的增加或减少按钮时,它将以每 100 毫秒的速度连续增加或减少 mMinuteSpinner 的值。 +// 通过设置 NumberPicker 的值更改监听器和其他属性,代码实现了一个可以选择小时和分钟的控件,并将它们分别绑定到 mHourSpinner 和 mMinuteSpinner 变量上,以便在之后的操作中使用。 - String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); + String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();//获取了当前设备的日期格式符号,并使用 getAmPmStrings() 方法从中获取 AM/PM 格式符号的字符串数组,并将其赋值给 stringsForAmPm 变量。 mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm); mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL); mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL); - mAmPmSpinner.setDisplayedValues(stringsForAmPm); - mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); +// 获取了布局文件中 ID 为 amPm 的 NumberPicker 控件,并将其赋值给 mAmPmSpinner 变量。使用 setMinValue() 和 setMaxValue() 方法将 mAmPmSpinner 的最小值和最大值分别设置为 AMPM_SPINNER_MIN_VAL 和 AMPM_SPINNER_MAX_VAL,以限制 AM/PM 选择器的范围。 + mAmPmSpinner.setDisplayedValues(stringsForAmPm);//使用 setDisplayedValues() 方法将 stringsForAmPm 数组设置为 mAmPmSpinner 的显示值。这意味着 AM/PM 选择器将显示 stringsForAmPm 数组中的字符串,而不是默认的数字值。 + mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);//使用 setOnValueChangedListener() 方法将 mAmPmSpinner 的值更改监听器设置为 mOnAmPmChangedListener。这意味着当用户更改 AM/PM 选择器的值时,将调用 mOnAmPmChangedListener 中的方法来处理这个事件。 // update controls to initial state updateDateControl(); @@ -204,6 +224,7 @@ public class DateTimePicker extends FrameLayout { updateAmPmControl(); set24HourView(is24HourView); +// 代码调用了 updateDateControl()、updateHourControl() 和 updateAmPmControl() 方法,以便将控件显示为当前日期和时间的值。然后,代码调用了 set24HourView() 方法将选择器的时间格式设置为 24 小时制或 12 小时制。 // set to current time setCurrentDate(date); @@ -212,6 +233,7 @@ public class DateTimePicker extends FrameLayout { // set the content descriptions mInitialising = false; +// 调用了 setCurrentDate() 方法将选择器的日期和时间设置为指定的日期和时间,调用 setEnabled() 方法将选择器的可用状态设置为指定的值,并将 mInitialising 标志设置为 false,以便通知选择器已完成初始化。 } @Override @@ -219,13 +241,17 @@ public class DateTimePicker extends FrameLayout { if (mIsEnabled == enabled) { return; } +// 当调用 setEnabled() 方法时,如果传入的参数 enabled 与当前的 mIsEnabled 变量的值相同,说明选择器的可用状态没有发生变化,直接返回即可。 super.setEnabled(enabled); mDateSpinner.setEnabled(enabled); mMinuteSpinner.setEnabled(enabled); mHourSpinner.setEnabled(enabled); mAmPmSpinner.setEnabled(enabled); mIsEnabled = enabled; +// 代码首先调用父类的 setEnabled() 方法,将整个时间选择器的可用状态设置为传入的参数 enabled。然后,分别调用 mDateSpinner、mMinuteSpinner、mHourSpinner 和 mAmPmSpinner 的 setEnabled() 方法,将它们的可用状态也设置为传入的参数 enabled。 +//最后,将 mIsEnabled 变量的值设置为传入的参数 enabled,以便在下一次调用 setEnabled() 方法时使用。 } +// 重写 setEnabled() 方法,代码实现了一个可以同时设置整个时间选择器的可用状态的功能。 @Override public boolean isEnabled() { @@ -428,11 +454,14 @@ public class DateTimePicker extends FrameLayout { } mIs24HourView = is24HourView; mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE); +// 当传入的参数 is24HourView 与当前的 mIs24HourView 变量的值相同时,方法直接返回。否则,将 mIs24HourView 变量的值设置为传入的参数 is24HourView,表示时间选择器的显示格式已经更改。 int hour = getCurrentHourOfDay(); updateHourControl(); setCurrentHour(hour); updateAmPmControl(); +// 获取当前的小时数并调用 updateHourControl() 方法更新小时选择器,以保持小时选择器的一致性。接着,使用 setCurrentHour() 方法将当前的小时数设置回时间选择器,并调用 updateAmPmControl() 方法更新 AM/PM 选择器。 } +//通过设置 AM/PM 选择器的可见性和更新时间选择器的小时控件和 AM/PM 控件,代码实现了一个可以切换时间选择器显示格式的功能。 private void updateDateControl() { Calendar cal = Calendar.getInstance(); @@ -447,6 +476,8 @@ public class DateTimePicker extends FrameLayout { mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); mDateSpinner.invalidate(); } +// 用于更新日期选择器的显示值。它首先获取当前日期并将其设置为日历实例 cal 的时间。然后,cal 被设置为一周的第一天,以确保日期选择器显示一周的日期。 +//接下来,使用 setDisplayedValues() 方法将日期选择器的显示值设置为 null,以便重新生成新的日期显示值。然后,使用循环从 cal 中获取每一天的日期,并将其格式化为 MM.dd EEEE 的格式,并将其存储在一个字符串数组中。最后,使用 setDisplayedValues() 方法将新的日期显示值设置为 mDateSpinner,并将当前选择的日期值设置为一周的中间值,以保持日期选择器的一致性。 private void updateAmPmControl() { if (mIs24HourView) { @@ -457,6 +488,7 @@ public class DateTimePicker extends FrameLayout { mAmPmSpinner.setVisibility(View.VISIBLE); } } +// 用于更新 AM/PM 选择器的显示值。如果时间选择器为 24 小时格式,则将 AM/PM 选择器隐藏;否则,根据当前是否为 AM,将 AM/PM 选择器的值设置为 Calendar.AM 或 Calendar.PM,并将其可见性设置为 View.VISIBLE。 private void updateHourControl() { if (mIs24HourView) { @@ -467,6 +499,7 @@ public class DateTimePicker extends FrameLayout { mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); } } +// 用于更新小时选择器的显示值。如果时间选择器为 24 小时格式,则将小时选择器的最小值和最大值分别设置为 HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW 和 HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW;否则,将小时选择器的最小值和最大值分别设置为 HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW 和 HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW。 /** * Set the callback that indicates the 'Set' button has been pressed. diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java b/src/Notes/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java index 2c47ba4..a7c67ce 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java @@ -39,6 +39,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener public interface OnDateTimeSetListener { void OnDateTimeSet(AlertDialog dialog, long date); } +// 实现了一个 OnDateTimeSetListener 接口,该接口定义了一个 OnDateTimeSet() 方法,用于在用户选择日期时间后通知调用者。 public DateTimePickerDialog(Context context, long date) { super(context); @@ -55,6 +56,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener updateTitle(mDate.getTimeInMillis()); } }); +// 包含了一个 DateTimePicker 控件,用于让用户选择日期和时间。通过 mDateTimePicker.setOnDateTimeChangedListener() 方法,当用户选择日期和时间时,将更新 mDate 的值,并使用 updateTitle() 方法更新对话框的标题。 mDate.setTimeInMillis(date); mDate.set(Calendar.SECOND, 0); mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); @@ -67,6 +69,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener public void set24HourView(boolean is24HourView) { mIs24HourView = is24HourView; } +//set24HourView() 方法,用于设置日期时间选择器是否为 24 小时格式。默认情况下,该值将由系统的设置决定。 public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { mOnDateTimeSetListener = callBack; @@ -86,5 +89,6 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); } } +// 重写了 onClick() 方法,以便在用户点击“确定”按钮后,将用户选择的日期时间作为参数传递到 OnDateTimeSet() 方法中,从而通知调用者。 } \ No newline at end of file diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/DropdownMenu.java b/src/Notes/app/src/main/java/net/micode/notes/ui/DropdownMenu.java index 613dc74..44cca84 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/DropdownMenu.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/DropdownMenu.java @@ -31,6 +31,7 @@ public class DropdownMenu { private Button mButton; private PopupMenu mPopupMenu; private Menu mMenu; +// 一个 Button 控件,用于显示菜单的标题,以及一个 PopupMenu 对象,用于显示菜单项。在构造函数中,该类接受一个菜单资源 ID,并使用 mPopupMenu.getMenuInflater().inflate() 方法从 XML 资源中加载菜单项,然后将菜单项添加到 mMenu 对象中。 public DropdownMenu(Context context, Button button, int menuId) { mButton = button; @@ -43,19 +44,22 @@ public class DropdownMenu { mPopupMenu.show(); } }); +// 重写了 setOnClickListener() 方法,以便在用户点击 Button 控件时显示下拉菜单。 } +// 在 Button 控件上注册一个单击事件监听器,并在该监听器中实现下拉菜单的显示逻辑。 public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { if (mPopupMenu != null) { mPopupMenu.setOnMenuItemClickListener(listener); } } +// setOnDropdownMenuItemClickListener() 方法,用于设置菜单项的点击监听器。通过这个方法,应用程序可以在用户选择菜单项时执行相应的操作。 public MenuItem findItem(int id) { return mMenu.findItem(id); - } + }//findItem() 方法用于查找指定 ID 的菜单项 public void setTitle(CharSequence title) { mButton.setText(title); - } + }//用于设置菜单的标题。 } diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java b/src/Notes/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java index 96b77da..71a4f49 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java @@ -47,6 +47,7 @@ public class FoldersListAdapter extends CursorAdapter { public View newView(Context context, Cursor cursor, ViewGroup parent) { return new FolderListItem(context); } +// 用于创建新的视图,该方法返回一个新的 FolderListItem 对象,它是一个自定义的 LinearLayout,用于显示文件夹列表项的布局。 @Override public void bindView(View view, Context context, Cursor cursor) { @@ -56,12 +57,14 @@ public class FoldersListAdapter extends CursorAdapter { ((FolderListItem) view).bind(folderName); } } +// 用于绑定视图和数据,该方法会将数据从 Cursor 对象中读取出来,并将其绑定到 FolderListItem 视图中。 public String getFolderName(Context context, int position) { Cursor cursor = (Cursor) getItem(position); return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); } +// 获取文件夹列表中某个位置的文件夹名称。 private class FolderListItem extends LinearLayout { private TextView mName; @@ -76,5 +79,7 @@ public class FoldersListAdapter extends CursorAdapter { mName.setText(name); } } +// FolderListItem 类是一个自定义的 LinearLayout,用于显示文件夹列表项的布局。它包含一个 TextView 控件,用于显示文件夹名称。 } +//这段代码是一个自定义的 CursorAdapter 类 FoldersListAdapter,用于在 Android 应用程序中显示一个文件夹列表。 diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java index 387c03a..83139d1 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java @@ -84,8 +84,10 @@ public class NoteEditActivity extends Activity implements OnClickListener, public ImageView ibSetBgColor; } +// HeadViewHolder类定义了一组视图,用于在列表或网格中显示信息。这些视图包括一个TextView用于显示修改信息,一个ImageView用于显示警报图标,另一个TextView用于显示警报日期,还有一个ImageView用于选择背景颜色。 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); @@ -95,6 +97,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } 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); @@ -102,8 +105,10 @@ public class NoteEditActivity extends Activity implements OnClickListener, sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); } +// sBgSelectorBtnsMap是一个HashMap,将用于选择背景颜色的ImageView视图的资源ID映射到整数值,这些整数值在ResourceParser类中定义。同样,sBgSelectorSelectionMap将整数值映射到所选ImageView视图的资源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); @@ -112,12 +117,14 @@ public class NoteEditActivity extends Activity implements OnClickListener, } 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); } +// sFontSizeBtnsMap将用于选择字体大小的LinearLayout视图的资源ID映射到整数值,而sFontSelectorSelectionMap将整数值映射到所选ImageView视图的资源ID。 private static final String TAG = "NoteEditActivity"; @@ -185,10 +192,14 @@ public class NoteEditActivity extends Activity implements OnClickListener, * If the user specified the {@link Intent#ACTION_VIEW} but not provided with id, * then jump to the NotesListActivity */ - mWorkingNote = null; +// 果用户指定了 Intent.ACTION_VIEW 动作但没有提供ID,则跳转到 NotesListActivity + mWorkingNote = null;//在方法中,首先将mWorkingNote设置为null。然后,根据传入的Intent的动作(action)进行选择。 if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { +// Intent中获取笔记ID long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); + // 将用户查询字符串设置为空 mUserQuery = ""; + // 如果Intent包含了搜索结果的额外数据,则从额外数据中获取笔记ID,并将用户查询字符串设置为搜索管理器中的用户查询字符串 /** * Starting from the searched result @@ -198,6 +209,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); } + // 如果笔记在笔记数据库中不存在,则跳转到 NotesListActivity 并显示错误信息的Toast,最后结束 Activity 并返回 false if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { Intent jump = new Intent(this, NotesListActivity.class); startActivity(jump); @@ -205,6 +217,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, finish(); return false; } else { + // 加载笔记 mWorkingNote = WorkingNote.load(this, noteId); if (mWorkingNote == null) { Log.e(TAG, "load note failed with note id" + noteId); @@ -212,11 +225,12 @@ public class NoteEditActivity extends Activity implements OnClickListener, return false; } } +// 如果该Intent的动作(action)为Intent.ACTION_VIEW,则从该Intent中获取笔记的ID(noteId)。如果该Intent还包含了一个搜索结果(Search)的额外数据(extra data key),则将noteId从额外数据中获取,并将用户查询字符串(mUserQuery)设置为搜索管理器中的用户查询字符串(SearchManager.USER_QUERY)。如果noteId在笔记数据库中不存在,则将Activity转到NotesListActivity,并显示一个错误信息的Toast,最后结束Activity并返回false。如果noteId在笔记数据库中存在,则加载该笔记的工作副本(mWorkingNote),如果加载失败,则结束Activity并返回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())) { - // New note + } else if (TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { + // New note 如果用户指定了 Intent.ACTION_INSERT_OR_EDIT 动作,则获取笔记ID,如果笔记ID存在,则加载笔记,否则,创建一个新的笔记 long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); @@ -270,20 +284,26 @@ public class NoteEditActivity extends Activity implements OnClickListener, } private void initNoteScreen() { + // 使用mFontSizeId设置笔记编辑器的文本外观。 mNoteEditor.setTextAppearance(this, TextAppearanceResources .getTexAppearanceResource(mFontSizeId)); + // 如果mWorkingNote的CheckListMode为TextNote.MODE_CHECK_LIST,则将编辑器转换为列表模式。 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { switchToListMode(mWorkingNote.getContent()); } else { + // 如果mWorkingNote的CheckListMode不是TextNote.MODE_CHECK_LIST,则在编辑器中显示笔记内容,并使用mUserQuery高亮显示查询结果。 mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); mNoteEditor.setSelection(mNoteEditor.getText().length()); } + // 隐藏背景选择器中所有不在sBgSelectorSelectionMap中的ID的视图。 for (Integer id : sBgSelectorSelectionMap.keySet()) { findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE); } + // 设置mHeadViewPanel和mNoteEditorPanel的背景颜色为mWorkingNote的标题背景ID和背景颜色ID。 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 @@ -297,6 +317,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } private void showAlertHeader() { + // 如果mWorkingNote具有闹钟提醒,则检查当前时间是否超过提醒时间,如果超过,则在标题栏中显示“note_alert_expired”文本;否则,在标题栏中显示相对时间。 if (mWorkingNote.hasClockAlert()) { long time = System.currentTimeMillis(); if (time > mWorkingNote.getAlertDate()) { @@ -305,12 +326,15 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); } + // 将标题栏中的提醒日期文本和提醒图标设置为可见。 mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); } else { + // 如果mWorkingNote没有闹钟提醒,则将标题栏中的提醒日期文本和提醒图标设置为不可见。 mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); - }; + } + ; } @Override @@ -322,7 +346,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - /** + /* * For new note without note id, we should firstly save it to * generate a id. If the editing note is not worth saving, there * is no id which is equivalent to create new note @@ -336,31 +360,36 @@ public class NoteEditActivity extends Activity implements OnClickListener, @Override public boolean dispatchTouchEvent(MotionEvent ev) { + // 如果笔记背景颜色选择器可见,并且触摸事件不在笔记背景颜色选择器范围内,则隐藏笔记背景颜色选择器并返回true。 if (mNoteBgColorSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mNoteBgColorSelector, ev)) { mNoteBgColorSelector.setVisibility(View.GONE); return true; } + // 如果字体大小选择器可见,并且触摸事件不在字体大小选择器范围内,则隐藏字体大小选择器并返回true。 if (mFontSizeSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mFontSizeSelector, ev)) { mFontSizeSelector.setVisibility(View.GONE); return true; } + // 返回父类的dispatchTouchEvent方法。 return super.dispatchTouchEvent(ev); } private boolean inRangeOfView(View view, MotionEvent ev) { - int []location = new int[2]; + // 获取视图在屏幕上的位置。 + int[] location = new int[2]; view.getLocationOnScreen(location); int x = location[0]; int y = location[1]; + // 如果触摸事件的x坐标小于视图的x坐标、大于视图的宽度和x坐标之和、y坐标小于视图的y坐标、或大于视图的高度和y坐标之和,则返回false,否则返回true。 if (ev.getX() < x || ev.getX() > (x + view.getWidth()) || ev.getY() < y || ev.getY() > (y + view.getHeight())) { - return false; - } + return false; + } return true; } @@ -384,15 +413,16 @@ public class NoteEditActivity extends Activity implements OnClickListener, 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); - /** + /* * HACKME: Fix bug of store the resource id in shared preference. * The id may larger than the length of resources, in this case, * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} */ - if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { + if (mFontSizeId >= TextAppearanceResources.getResourcesSize()) { mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; } mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); @@ -401,39 +431,40 @@ public class NoteEditActivity extends Activity implements OnClickListener, @Override protected void onPause() { super.onPause(); - if(saveNote()) { + if (saveNote()) { Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); } clearSettingState(); - } + }//onPause()方法在活动即将暂停时被调用。如果有任何更改,它会保存当前笔记,并清除任何设置状态。 private void updateWidget() { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { intent.setClass(this, NoteWidgetProvider_2x.class); - } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { - intent.setClass(this, NoteWidgetProvider_4x.class); } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_3X) { intent.setClass(this, NoteWidgetProvider_3x.class); + } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { + intent.setClass(this, NoteWidgetProvider_4x.class); } else { Log.e(TAG, "Unsupported widget type"); return; } - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { - mWorkingNote.getWidgetId() + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{ + mWorkingNote.getWidgetId() }); sendBroadcast(intent); setResult(RESULT_OK, intent); - } + }//updateWidget()方法更新与当前笔记相关联的小部件。它创建一个意图,并根据笔记的小部件类型设置相应的小部件提供程序类。然后它发送一个广播,带有小部件ID以更新小部件。 + public void onClick(View v) { int id = v.getId(); if (id == R.id.btn_set_bg_color) { mNoteBgColorSelector.setVisibility(View.VISIBLE); findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.VISIBLE); + -View.VISIBLE); } else if (sBgSelectorBtnsMap.containsKey(id)) { findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.GONE); @@ -453,17 +484,17 @@ public class NoteEditActivity extends Activity implements OnClickListener, } mFontSizeSelector.setVisibility(View.GONE); } - } + }//onClick()方法处理UI中各种按钮的点击事件。当单击相应的按钮时,它会显示颜色选择器或字体大小选择器。它还根据所选选项更新笔记的字体大小或背景颜色。 @Override public void onBackPressed() { - if(clearSettingState()) { + if (clearSettingState()) { return; } saveNote(); super.onBackPressed(); - } + }//onBackPressed()方法在按下返回按钮时被调用。它检查当前是否有任何设置状态处于活动状态,并清除它。然后它保存当前笔记并调用超类实现。 private boolean clearSettingState() { if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { @@ -474,14 +505,14 @@ public class NoteEditActivity extends Activity implements OnClickListener, return true; } return false; - } + }//clearSettingState()方法检查当前是否有任何设置状态处于活动状态,并清除它。 public void onBackgroundColorChanged() { findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); - } + }//onBackgroundColorChanged()方法在选择新的背景颜色时被调用。它更新笔记的背景颜色,并更新颜色选择器的颜色。 @Override public boolean onPrepareOptionsMenu(Menu menu) { @@ -506,7 +537,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, menu.findItem(R.id.menu_delete_remind).setVisible(false); } return true; - } + }//onFontSizeChanged()方法在选择新的字体大小时被调用。它更新笔记的字体大小,并更新字体大小选择器的值。 @Override public boolean onOptionsItemSelected(MenuItem item) { @@ -560,7 +591,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, 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(); @@ -575,7 +606,8 @@ public class NoteEditActivity extends Activity implements OnClickListener, intent.putExtra(Intent.EXTRA_TEXT, info); intent.setType("text/plain"); context.startActivity(intent); - } + }//sendTo(Context context, String info)方法创建一个新的意图,并使用Intent.EXTRA_TEXT将信息作为文本传递。它的目的是启动共享对话框,让用户分享笔记的内容。 + private void createNewNote() { // Firstly, save current editing notes @@ -587,7 +619,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, intent.setAction(Intent.ACTION_INSERT_OR_EDIT); intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); startActivity(intent); - } + }//createNewNote()方法保存当前正在编辑的笔记,然后启动一个新的NoteEditActivity以创建一个新的笔记。通过设置Intent.ACTION_INSERT_OR_EDIT和Notes.INTENT_EXTRA_FOLDER_ID,该方法指示NoteEditActivity启动以插入或编辑笔记,并指定所选文件夹的ID。 private void deleteCurrentNote() { if (mWorkingNote.existInDatabase()) { @@ -609,11 +641,11 @@ public class NoteEditActivity extends Activity implements OnClickListener, } } mWorkingNote.markDeleted(true); - } + }//deleteCurrentNote()方法删除当前笔记。如果该笔记已存储在数据库中,则将其从数据库中删除。如果应用程序处于同步模式下,则将其移动到垃圾文件夹中,而不是永久删除。无论是删除还是移动,该方法都会将当前笔记标记为已删除。 private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; - } + }//isSyncMode()方法检查应用程序是否处于同步模式。如果已经选择了同步帐户,则返回true。否则,返回false。 public void onClockAlertChanged(long date, boolean set) { /** @@ -629,7 +661,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); showAlertHeader(); - if(!set) { + if (!set) { alarmManager.cancel(pendingIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); @@ -648,6 +680,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, public void onWidgetChanged() { updateWidget(); } +// onWidgetChanged()方法会在小部件更改时被调用。它会调用updateWidget()方法来更新小部件。 public void onEditTextDelete(int index, String text) { int childCount = mEditTextList.getChildCount(); @@ -662,7 +695,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, mEditTextList.removeViewAt(index); NoteEditText edit = null; - if(index == 0) { + if (index == 0) { edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( R.id.et_edit_text); } else { @@ -674,12 +707,13 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit.requestFocus(); edit.setSelection(length); } +// onEditTextDelete(int index, String text)方法会在删除NoteEditText视图时被调用。该方法首先检查是否只有一个NoteEditText视图存在,如果是则直接返回。然后,该方法会将所有后续视图的索引递减1。接下来,该方法会删除指定索引处的NoteEditText视图,并将其文本追加到前一个视图的文本中,以便将文本合并到一个视图中。最后,该方法将焦点设置在前一个视图中,并将光标移动到文本末尾。 public void onEditTextEnter(int index, String text) { /** * Should not happen, check for debug */ - if(index > mEditTextList.getChildCount()) { + if (index > mEditTextList.getChildCount()) { Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); } @@ -699,7 +733,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, String[] items = text.split("\n"); int index = 0; for (String item : items) { - if(!TextUtils.isEmpty(item)) { + if (!TextUtils.isEmpty(item)) { mEditTextList.addView(getListItem(item, index)); index++; } @@ -710,6 +744,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteEditor.setVisibility(View.GONE); mEditTextList.setVisibility(View.VISIBLE); } +// switchToListMode(String text)方法用于切换到清单模式。该方法首先清除所有视图,然后将文本根据换行符分隔为多个条目,并将每个条目添加到mEditTextList中。同时,该方法会添加一个新的空条目,以便用户可以在列表末尾添加新的条目。最后,该方法会将焦点设置在最后一个条目上,并将编辑器视图隐藏,将列表视图显示。 private Spannable getHighlightQueryResult(String fullText, String userQuery) { SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); @@ -727,6 +762,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return spannable; } +// getHighlightQueryResult(String fullText, String userQuery)方法用于标记在搜索查询中匹配的文本。该方法将返回一个Spannable对象,其中查询匹配的文本会被高亮显示。 private View getListItem(String item, int index) { View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); @@ -758,18 +794,20 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit.setText(getHighlightQueryResult(item, mUserQuery)); return view; } +// getListItem(String item, int index)方法用于获取一个清单视图。该方法将从R.layout.note_edit_list_item文件中充气视图。在充气视图之后,该方法会将文本添加到NoteEditText视图中,并将复选框设置为选中或未选中状态。如果条目已选中,则文本将具有删除线。最后,该方法将返回该视图。 public void onTextChange(int index, boolean hasText) { if (index >= mEditTextList.getChildCount()) { Log.e(TAG, "Wrong index, should not happen"); return; } - if(hasText) { + if (hasText) { mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); } else { mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE); } } +// onTextChange(int index, boolean hasText)方法用于在清单视图中标记是否有文本。如果hasText为true,则将显示复选框;否则,将隐藏复选框。 public void onCheckListModeChanged(int oldMode, int newMode) { if (newMode == TextNote.MODE_CHECK_LIST) { @@ -784,6 +822,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteEditor.setVisibility(View.VISIBLE); } } +// onCheckListModeChanged(int oldMode, int newMode)方法用于在清单模式和文本编辑模式之间切换。如果新模式为清单模式,则将文本转换为清单视图;否则,将清单视图转换为文本编辑视图。 private boolean getWorkingText() { boolean hasChecked = false; @@ -807,6 +846,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return hasChecked; } +// getWorkingText()方法用于获取当前工作文本。如果当前模式为清单模式,则将所有条目合并为一个字符串,并添加检查框状态。否则,将返回当前编辑器文本。 private boolean saveNote() { getWorkingText(); diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditText.java b/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditText.java index 2afe2a8..a4179e7 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditText.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/NoteEditText.java @@ -84,11 +84,11 @@ public class NoteEditText extends EditText { public void setIndex(int index) { mIndex = index; - } + }//用于设置控件在父容器中的位置索引 public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { mOnTextViewChangeListener = listener; - } + }//用于设置文本变化的监听器 public NoteEditText(Context context, AttributeSet attrs) { super(context, attrs, android.R.attr.editTextStyle); @@ -116,7 +116,7 @@ public class NoteEditText extends EditText { int off = layout.getOffsetForHorizontal(line, x); Selection.setSelection(getText(), off); break; - } + }//实现了点击控件后,将光标移动到点击位置的功能 return super.onTouchEvent(event); } @@ -166,6 +166,7 @@ public class NoteEditText extends EditText { } return super.onKeyUp(keyCode, event); } +// onKeyDown和onKeyUp方法实现了按下和松开键盘按键时的响应。 @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { @@ -177,7 +178,7 @@ public class NoteEditText extends EditText { } } super.onFocusChanged(focused, direction, previouslyFocusedRect); - } + }//控件获得或失去焦点时触发,将焦点状态通知给监听器。 @Override protected void onCreateContextMenu(ContextMenu menu) { @@ -214,4 +215,5 @@ public class NoteEditText extends EditText { } super.onCreateContextMenu(menu); } +// 创建上下文菜单,当用户长按控件中的链接时,根据链接的协议类型创建不同的菜单项,点击菜单项后跳转到相应的链接。 } diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListActivity.java b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListActivity.java index c00449e..d059a71 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListActivity.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListActivity.java @@ -82,7 +82,7 @@ import java.util.HashSet; public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; - private static final int FOLDER_LIST_QUERY_TOKEN = 1; + private static final int FOLDER_LIST_QUERY_TOKEN = 1; private static final int MENU_FOLDER_DELETE = 0; @@ -94,7 +94,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt private enum ListEditState { NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER - }; + } + + ; private ListEditState mState; @@ -134,7 +136,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt + NoteColumns.NOTES_COUNT + ">0)"; private final static int REQUEST_CODE_OPEN_NODE = 102; - private final static int REQUEST_CODE_NEW_NODE = 103; + private final static int REQUEST_CODE_NEW_NODE = 103; @Override protected void onCreate(Bundle savedInstanceState) { @@ -142,7 +144,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt setContentView(R.layout.note_list); initResources(); - /* + /** * Insert an introduction when user firstly use this application */ setAppInfoFromRawRes(); @@ -157,18 +159,20 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt super.onActivityResult(requestCode, resultCode, data); } } +// 这个方法重写了Activity类的onActivityResult()方法。当startActivityForResult()启动的活动结束时,它会被调用。它检查结果是否为RESULT_OK并且请求了REQUEST_CODE_OPEN_NODE或REQUEST_CODE_NEW_NODE。如果是,则通过调用changeCursor(null)更新笔记列表适配器。否则,它调用超类实现的onActivityResult()方法。 private void setAppInfoFromRawRes() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { + // 从raw资源中读取介绍文件 StringBuilder sb = new StringBuilder(); InputStream in = null; try { - in = getResources().openRawResource(R.raw.introduction); + in = getResources().openRawResource(R.raw.introduction); if (in != null) { InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); - char [] buf = new char[1024]; + char[] buf = new char[1024]; int len = 0; while ((len = br.read(buf)) > 0) { sb.append(buf, 0, len); @@ -181,7 +185,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt e.printStackTrace(); return; } finally { - if(in != null) { + if (in != null) { try { in.close(); } catch (IOException e) { @@ -203,6 +207,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } } +// 这个方法从一个原始的资源文件中读取介绍文件,并将其内容添加到应用程序的SharedPreferences中。如果介绍文件尚未被添加到SharedPreferences中,它将被添加,并设置一个标志表示文件已被添加。在此之后,每次启动应用程序时,它将不再读取介绍文件。 @Override protected void onStart() { @@ -259,7 +264,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt mDropDownMenu = new DropdownMenu(NotesListActivity.this, (Button) customView.findViewById(R.id.selection_menu), R.menu.note_list_dropdown); - mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ + mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); updateMenu(); @@ -269,6 +274,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }); return true; } +// 这是Activity的onCreate()方法,它在创建活动时被调用。它设置了视图并调用了setAppInfoFromRawRes()和initNoteListView()方法以初始化应用程序。 private void updateMenu() { int selectedCount = mNotesListAdapter.getSelectedCount(); @@ -285,33 +291,33 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt item.setTitle(R.string.menu_select_all); } } - } + }//更新下拉菜单中的选项。该方法首先获取当前选中的笔记数量,然后格式化菜单标题,更新下拉菜单的标题,并更新菜单项的状态。 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // TODO Auto-generated method stub return false; - } + }//准备操作模式。该方法在操作模式即将被启动时调用,并返回一个布尔值,指示是否应该启动操作模式。 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // TODO Auto-generated method stub return false; - } + }//处理操作模式中的菜单项点击事件。该方法在用户点击操作模式中的菜单项时调用,并返回一个布尔值,指示是否已经处理了该事件。 public void onDestroyActionMode(ActionMode mode) { mNotesListAdapter.setChoiceMode(false); mNotesListView.setLongClickable(true); mAddNewNote.setVisibility(View.VISIBLE); - } + }//销毁操作模式。该方法在操作模式被销毁时调用,并将列表适配器的选择模式设置为false,将列表项的长按功能重新启用,并显示添加新笔记的按钮。 public void finishActionMode() { mActionMode.finish(); - } + }//结束操作模式。该方法结束操作模式。 public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { + boolean checked) { mNotesListAdapter.setCheckedItem(position, checked); updateMenu(); - } + }//当用户选中或取消选中一个列表项时调用。该方法更新适配器中对应列表项的选中状态,并调用updateMenu()方法更新下拉菜单中的选项。 public boolean onMenuItemClick(MenuItem item) { if (mNotesListAdapter.getSelectedCount() == 0) { @@ -326,14 +332,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setMessage(getString(R.string.alert_message_delete_notes, - mNotesListAdapter.getSelectedCount())); + mNotesListAdapter.getSelectedCount())); builder.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int which) { - batchDelete(); - } - }); + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + batchDelete(); + } + }); builder.setNegativeButton(android.R.string.cancel, null); builder.show(); break; @@ -345,6 +351,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } return true; } +// 处理下拉菜单中的菜单项点击事件。该方法在用户点击下拉菜单中的菜单项时调用,并根据菜单项的ID执行相应的操作。如果成功处理了菜单项,则返回true,否则返回false。如果没有选中任何笔记,则显示一个Toast提示用户需要先选择笔记。如果选择了“删除”菜单项,则弹出一个对话框,询问用户是否确定要删除所选笔记。如果选择了“移动”菜单项,则启动查询目标文件夹的操作。 } private class NewNoteOnTouchListener implements OnTouchListener { @@ -407,32 +414,40 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt 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) + Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[]{ + String.valueOf(mCurrentFolderId) }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); } + // 后台查询处理程序,继承自AsyncQueryHandler private final class BackgroundQueryHandler extends AsyncQueryHandler { public BackgroundQueryHandler(ContentResolver contentResolver) { super(contentResolver); } +// 构造函数,调用父类AsyncQueryHandler的构造函数 + // 查询完成后的回调函数,根据token值进行不同的处理 @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { switch (token) { case FOLDER_NOTE_LIST_QUERY_TOKEN: + // 更新列表Adapter的Cursor mNotesListAdapter.changeCursor(cursor); break; case FOLDER_LIST_QUERY_TOKEN: if (cursor != null && cursor.getCount() > 0) { + // 显示文件夹列表菜单 showFolderListMenu(cursor); } else { + // 查询文件夹失败,输出错误信息 Log.e(TAG, "Query folder failed"); } break; @@ -442,35 +457,48 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + // 显示文件夹列表菜单 private void showFolderListMenu(Cursor cursor) { + // 创建AlertDialog.Builder AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(R.string.menu_title_select_folder); + // 创建文件夹列表的Adapter final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor); + // 设置Adapter和点击事件 builder.setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { + // 批量移动选中的笔记到指定文件夹 DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which)); + // 显示移动笔记的提示信息 Toast.makeText( NotesListActivity.this, getString(R.string.format_move_notes_to_folder, mNotesListAdapter.getSelectedCount(), adapter.getFolderName(NotesListActivity.this, which)), Toast.LENGTH_SHORT).show(); + // 结束ActionMode mModeCallBack.finishActionMode(); } }); + // 显示AlertDialog builder.show(); } + // 创建新笔记 private void createNewNote() { + // 创建Intent,跳转到NoteEditActivity Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_INSERT_OR_EDIT); intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId); + // 启动ActivityForResult this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE); } + // 批量删除选中的笔记 private void batchDelete() { + // 创建异步任务 new AsyncTask>() { protected HashSet doInBackground(Void... unused) { HashSet widgets = mNotesListAdapter.getSelectedWidget(); @@ -534,47 +562,52 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + // 打开笔记详情页 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); + intent.putExtra(Intent.EXTRA_UID, data.getId());// 将笔记的id作为参数传递给NoteEditActivity + this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);// 启动NoteEditActivity,并等待返回结果 } + // 打开文件夹 private void openFolder(NoteItemData data) { - mCurrentFolderId = data.getId(); - startAsyncNotesListQuery(); - if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mState = ListEditState.CALL_RECORD_FOLDER; - mAddNewNote.setVisibility(View.GONE); + mCurrentFolderId = data.getId();// 将当前文件夹的id保存到成员变量mCurrentFolderId + startAsyncNotesListQuery();// 异步查询当前文件夹下的笔记列表 + if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {// 如果打开的是CallRecord文件夹 + mState = ListEditState.CALL_RECORD_FOLDER;// 设置状态为CALL_RECORD_FOLDER + mAddNewNote.setVisibility(View.GONE);// 隐藏新建笔记按钮 } else { - mState = ListEditState.SUB_FOLDER; + mState = ListEditState.SUB_FOLDER;// 设置状态为SUB_FOLDER } - if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mTitleBar.setText(R.string.call_record_folder_name); + if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {// 如果打开的是CallRecord文件夹 + 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); // 显示标题栏 } + // 按钮点击事件 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); // 显示软键盘 } } + // 隐藏软键盘 private void hideSoftInput(View view) { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); @@ -606,7 +639,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }); final Dialog dialog = builder.setView(view).show(); - final Button positive = (Button)dialog.findViewById(android.R.id.button1); + final Button positive = (Button) dialog.findViewById(android.R.id.button1); positive.setOnClickListener(new OnClickListener() { public void onClick(View v) { hideSoftInput(etName); @@ -624,8 +657,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); values.put(NoteColumns.LOCAL_MODIFIED, 1); mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID - + "=?", new String[] { - String.valueOf(mFocusNoteDataItem.getId()) + + "=?", new String[]{ + String.valueOf(mFocusNoteDataItem.getId()) }); } } else if (!TextUtils.isEmpty(name)) { @@ -663,7 +696,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } }); - } + }//用于显示一个对话框,让用户输入或修改一个文件夹的名称。 @Override public void onBackPressed() { @@ -688,27 +721,29 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt break; } } +// 重写返回键的行为,根据当前的状态执行不同的操作,如返回到上一级文件夹、返回到笔记列表、或者直接退出应用程序。 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); - } else if (appWidgetType == Notes.TYPE_WIDGET_4X) { - intent.setClass(this, NoteWidgetProvider_4x.class); } else if (appWidgetType == Notes.TYPE_WIDGET_3X) { intent.setClass(this, NoteWidgetProvider_3x.class); + } else if (appWidgetType == Notes.TYPE_WIDGET_4X) { + intent.setClass(this, NoteWidgetProvider_4x.class); } else { - Log.e(TAG, "Unspported widget type"); + Log.e(TAG, "Unsupported widget type"); return; } - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { - appWidgetId + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{ + appWidgetId }); sendBroadcast(intent); setResult(RESULT_OK, intent); } +// 更新小部件的方法,根据小部件的类型选择不同的小部件提供者,并发送广播更新小部件。 private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { @@ -720,6 +755,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } }; +// 长按文件夹时创建上下文菜单的监听器,菜单包括查看文件夹、删除文件夹和修改文件夹名称等选项。 @Override public void onContextMenuClosed(Menu menu) { @@ -728,6 +764,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } super.onContextMenuClosed(menu); } +// 上下文菜单关闭时的操作,将监听器设为null。 @Override public boolean onContextItemSelected(MenuItem item) { @@ -762,6 +799,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } +// 选择上下文菜单选项时的操作,根据所选选项执行不同的操作,如打开文件夹、删除文件夹或修改文件夹名称。 @Override public boolean onPrepareOptionsMenu(Menu menu) { @@ -780,6 +818,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } return true; } +// 准备选项菜单时的操作,根据当前的状态显示不同的菜单选项,如笔记列表、子文件夹或通话记录文件夹。 @Override public boolean onOptionsItemSelected(MenuItem item) { @@ -820,6 +859,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } return true; } +// 选择选项菜单选项时的操作,根据所选选项执行不同的操作,如打开笔记列表、打开子文件夹或打开通话记录文件夹。 @Override public boolean onSearchRequested() { @@ -872,12 +912,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } +// ,表示当前是否处于同步模式。它通过调用 NotesPreferenceActivity.getSyncAccountName(this) 获取同步账户名,并检查它的长度是否大于 0 来确定是否启用同步模式。 private void startPreferenceActivity() { Activity from = getParent() != null ? getParent() : this; Intent intent = new Intent(from, NotesPreferenceActivity.class); from.startActivityIfNeeded(intent, -1); } +// 方法启动设置活动,它创建一个 Intent 对象并使用当前活动作为上下文调用 startActivityIfNeeded() 方法来启动设置活动。如果当前活动已经是设置活动的父级,则使用 getParent() 方法获取父级活动。 private class OnListItemClickListener implements OnItemClickListener { @@ -919,24 +961,26 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } +// OnListItemClickListener 是一个内部类,实现了 OnItemClickListener 接口。它覆盖了 onItemClick() 方法,在列表项被单击时执行一系列操作。首先,它检查当前是否处于选择模式。如果是,则根据列表项的类型执行不同的操作。如果不是,则根据当前状态执行不同的操作,如打开文件夹或笔记。 private void startQueryDestinationFolders() { String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?"; - selection = (mState == ListEditState.NOTE_LIST) ? selection: - "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; + selection = (mState == ListEditState.NOTE_LIST) ? selection : + "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN, null, Notes.CONTENT_NOTE_URI, FoldersListAdapter.PROJECTION, selection, - new String[] { + new String[]{ String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER), String.valueOf(mCurrentFolderId) }, NoteColumns.MODIFIED_DATE + " DESC"); } +// 启动后台查询,以获取目标文件夹列表。它构建一个查询选择器,通过调用 mBackgroundQueryHandler.startQuery() 方法执行查询操作。查询的结果将被传递到 FoldersListAdapter 中进行处理。 public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { if (view instanceof NotesListItem) { @@ -954,4 +998,5 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } return false; } +// 在列表项被长按时执行。它首先获取当前长按的列表项,并将其类型存储在 mFocusNoteDataItem 中。如果类型为笔记且不在选择模式下,则启动上下文操作模式,并将当前列表项标记为已选中。如果类型为文件夹,则设置上下文菜单的创建监听器。 } diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java index 51c9cb9..18f72ef 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java @@ -53,7 +53,7 @@ public class NotesListAdapter extends CursorAdapter { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return new NotesListItem(context); - } + }//创建一个新的笔记列表项视图,即 NotesListItem。 @Override public void bindView(View view, Context context, Cursor cursor) { @@ -62,21 +62,21 @@ public class NotesListAdapter extends CursorAdapter { ((NotesListItem) view).bind(context, itemData, mChoiceMode, isSelectedItem(cursor.getPosition())); } - } + }//将笔记数据绑定到给定的笔记列表项视图中。 public void setCheckedItem(final int position, final boolean checked) { mSelectedIndex.put(position, checked); notifyDataSetChanged(); - } + }//设置给定位置的笔记是否被选中,并通知适配器数据已更改。 public boolean isInChoiceMode() { return mChoiceMode; - } + }//返回是否处于选择笔记的模式。 public void setChoiceMode(boolean mode) { mSelectedIndex.clear(); mChoiceMode = mode; - } + }//设置选择笔记的模式,并清空 mSelectedIndex。 public void selectAll(boolean checked) { Cursor cursor = getCursor(); @@ -87,7 +87,7 @@ public class NotesListAdapter extends CursorAdapter { } } } - } + }//选择所有笔记。 public HashSet getSelectedItemIds() { HashSet itemSet = new HashSet(); @@ -103,7 +103,8 @@ public class NotesListAdapter extends CursorAdapter { } return itemSet; - } + }//返回选定的笔记的 ID。 + public HashSet getSelectedWidget() { HashSet itemSet = new HashSet(); @@ -126,7 +127,7 @@ public class NotesListAdapter extends CursorAdapter { } } return itemSet; - } + }//返回选定的小部件信息。 public int getSelectedCount() { Collection values = mSelectedIndex.values(); @@ -141,31 +142,31 @@ public class NotesListAdapter extends CursorAdapter { } } 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); - } + }//返回给定位置的笔记是否被选中。 @Override protected void onContentChanged() { super.onContentChanged(); calcNotesCount(); - } + }//当笔记数据发生变化时,重新计算笔记数量。 @Override public void changeCursor(Cursor cursor) { super.changeCursor(cursor); calcNotesCount(); - } + }//更改笔记数据游标时,重新计算笔记数量。 private void calcNotesCount() { mNotesCount = 0; @@ -180,5 +181,5 @@ public class NotesListAdapter extends CursorAdapter { return; } } - } + }//计算笔记数量。 } diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListItem.java b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListItem.java index 1221e80..147c4ea 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListItem.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesListItem.java @@ -98,6 +98,7 @@ public class NotesListItem extends LinearLayout { setBackground(data); } + // 用于将数据绑定到视图的UI组件上,它接受一个NoteItemData对象,其中包含有关笔记项的信息,以及两个布尔标志:choiceMode和checked。 private void setBackground(NoteItemData data) { int id = data.getBgColorId(); diff --git a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java index 07c5f7e..ed4d6af 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java +++ b/src/Notes/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java @@ -86,7 +86,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { mOriAccounts = null; View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); getListView().addHeaderView(header, null, true); - } + }//当创建Activity时调用。在此方法中,ActionBar的返回按钮启用,加载应用程序的偏好设置,注册广播接收器,添加一个标题视图。 @Override protected void onResume() { @@ -114,7 +114,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { } refreshUI(); - } + }//当Activity从暂停状态恢复时调用。在此方法中,检查用户是否已添加了新帐户,如果是,则需要自动设置同步帐户。 @Override protected void onDestroy() { @@ -122,7 +122,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { unregisterReceiver(mReceiver); } super.onDestroy(); - } + }//当Activity被销毁时调用。在此方法中,注销广播接收器。 private void loadAccountPreference() { mAccountCategory.removeAll(); @@ -152,7 +152,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { }); mAccountCategory.addPreference(accountPref); - } + }//加载应用程序的帐户偏好设置,包括标题、摘要和单击事件监听器。 private void loadSyncButton() { Button syncButton = (Button) findViewById(R.id.preference_sync_button); @@ -191,12 +191,12 @@ public class NotesPreferenceActivity extends PreferenceActivity { lastSyncTimeView.setVisibility(View.GONE); } } - } + }//加载同步按钮和上次同步时间文本视图,并设置相应的单击事件监听器。 private void refreshUI() { loadAccountPreference(); loadSyncButton(); - } + }//刷新用户界面,加载帐户偏好设置和同步按钮。 private void showSelectAccountAlertDialog() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); @@ -252,7 +252,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { dialog.dismiss(); } }); - } + }//弹出一个对话框,提示用户选择一个帐户进行同步。 private void showChangeAccountConfirmAlertDialog() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); @@ -384,5 +384,5 @@ public class NotesPreferenceActivity extends PreferenceActivity { default: return false; } - } + }//当用户选择同步帐户时调用。在此方法中,更新同步按钮的文本视图,并启用同步按钮。 } diff --git a/src/Notes/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_3x.java b/src/Notes/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_3x.java index 9626f78..d7ddbd8 100644 --- a/src/Notes/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_3x.java +++ b/src/Notes/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_3x.java @@ -21,7 +21,7 @@ public class NoteWidgetProvider_3x extends NoteWidgetProvider{ // 3x3大小的 @Override // 重写窗口小部件中的获取资源ID函数 protected int getBgResourceId(int bgId) { - return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId); + return ResourceParser.WidgetBgResources.getWidget3xBgResource(bgId); } @Override // 重写窗口小部件中的获取宽度类型函数 diff --git a/src/Notes/app/src/main/res/values-zh-rCN/strings.xml b/src/Notes/app/src/main/res/values-zh-rCN/strings.xml index 09f75ed..b360297 100644 --- a/src/Notes/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/Notes/app/src/main/res/values-zh-rCN/strings.xml @@ -19,6 +19,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 便签 便签2x2 + 便签3x3 便签4x4 没有关联内容,点击新建便签。 访客模式下,便签内容不可见 diff --git a/src/Notes/app/src/main/res/values-zh-rTW/strings.xml b/src/Notes/app/src/main/res/values-zh-rTW/strings.xml index e29b79b..5eb467b 100644 --- a/src/Notes/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/Notes/app/src/main/res/values-zh-rTW/strings.xml @@ -19,6 +19,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 便簽 便簽2x2 + 便簽3x3 便簽4x4 沒有關聯內容,點擊新建便簽。 訪客模式下,便籤內容不可見 diff --git a/src/Notes/app/src/main/res/values/strings.xml b/src/Notes/app/src/main/res/values/strings.xml index 55df868..7d941bb 100644 --- a/src/Notes/app/src/main/res/values/strings.xml +++ b/src/Notes/app/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> Notes Notes 2x2 + Notes 3x3 Notes 4x4 No associated note found, click to create associated note. Privacy mode,can not see note content diff --git a/src/Notes/app/src/main/res/xml/widget_3x_info.xml b/src/Notes/app/src/main/res/xml/widget_3x_info.xml new file mode 100644 index 0000000..03936e4 --- /dev/null +++ b/src/Notes/app/src/main/res/xml/widget_3x_info.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/src/Notes/build.gradle b/src/Notes/build.gradle index cdb59e3..07f17b1 100644 --- a/src/Notes/build.gradle +++ b/src/Notes/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:8.0.0' } } diff --git a/src/Notes/gradle.properties b/src/Notes/gradle.properties new file mode 100644 index 0000000..f82049a --- /dev/null +++ b/src/Notes/gradle.properties @@ -0,0 +1,3 @@ +android.defaults.buildfeatures.buildconfig=true +android.nonFinalResIds=false +android.nonTransitiveRClass=false \ No newline at end of file diff --git a/src/Notes/gradle/wrapper/gradle-wrapper.properties b/src/Notes/gradle/wrapper/gradle-wrapper.properties index 829fbb8..ff44dd1 100644 --- a/src/Notes/gradle/wrapper/gradle-wrapper.properties +++ b/src/Notes/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Sun Apr 02 08:57:13 CST 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME