Compare commits

...

34 Commits

Author SHA1 Message Date
ps9up4ig6 cae1bbedac update
2 years ago
gexinghai 85ce95c4a5 更新 名称更新
2 years ago
gexinghai eb313c6e57 新增 小米便签用例交互图.png
2 years ago
gexinghai 9c4461a386 更新 README.md
2 years ago
gexinghai da3f024e09 添加 小米便签软件需求描述文档.docx
2 years ago
gexinghai b0cd181253 提交 文件
2 years ago
ps9up4ig6 c1d1830965 合并
2 years ago
gexinghai 2d03456343 更新 实验三
2 years ago
gexinghai cf23536248 1
2 years ago
gexinghai e64a3710e7 1
2 years ago
gexinghai 45775e5493 提交 gradle
2 years ago
gexinghai bb7b0b1dc1 更新 泛读报告
2 years ago
gexinghai 0ed72127a8 修改 泛读报告表1
2 years ago
gexinghai d7203bbc88 添加 目录组织
2 years ago
ps9up4ig6 4554e0ad20 新增 3x3窗口小部件
2 years ago
gexinghai 4d914865f1 新增 3x3窗口小部件
2 years ago
gexinghai 470714b7d3 Merge branch 'dev' of https://bdgit.educoder.net/ps9up4ig6/gitProject1 into dev
2 years ago
gexinghai c7a7013c76 提交
2 years ago
ps9up4ig6 759e3ace30 合并 赵杰ui包注释
2 years ago
ZhaoJie 068b14af6d 赵杰ui包注释
2 years ago
gexinghai 4874b422e4 删除 .gitignore
2 years ago
gexinghai c4fe645595 添加 READEME.md
2 years ago
gexinghai 6717e081de 整理文件夹
2 years ago
ps9up4ig6 cd23e46261 zhaojie
2 years ago
ps9up4ig6 6f2c67fc19 init
2 years ago
ZhaoJie 6fa8117322 1
2 years ago
ps9up4ig6 a99473d8c2 update
2 years ago
gexinghai e1622ab4c2 update
2 years ago
gexinghai 5c0b665b6d 添加 NoteWidgetProvider及其子类的注释
2 years ago
gexinghai 9c90967355 test
2 years ago
gexinghai 5ac09678c6 Merge branch 'dev' of https://bdgit.educoder.net/ps9up4ig6/gitProject1 into dev
2 years ago
ps9up4ig6 172c7ff27f 张心驰的tools注释
2 years ago
gexinghai 3d9e0f1604 新增 小米便签总览.png
2 years ago
gexinghai 774e1a8d95 删除部分无用注释
2 years ago

116
.gitignore vendored

@ -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/

3
.idea/.gitignore vendored

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/gitProject1.iml" filepath="$PROJECT_DIR$/.idea/gitProject1.iml" />
</modules>
</component>
</project>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

@ -1,2 +1,61 @@
# Notes
# 小米便签
#### 目录组织:
| 文件名 | 内容 |
| :-------- | ----------------------------------- |
| model | 存放UML模型 |
| doc | 存放各类文档 |
| src | 存放源程序代码 |
| other | 存放综合实践的总结、自评和汇报PPT等 |
| README.md | README.md |
#### 课外实验一
☑ 软件需求文档;
☑ 软件体系结构图,描述开源软件的模块构成;
☑ SonarQube的开源软件质量报告
#### 课外实验二
☑ 理解开源代码的语义,撰写技术博客总结精读的成果及心得体会
☑ 具有标注的开源软件代码及其文件;
#### 课外实验三
☑ UML用例图模型和软件需求描述文档
开源软件新增需求的用例交互图、分析类图、状态图以及软件需求规格说明书;
#### 课外实验四
软件体系结构模型(至少包括逻辑视点和物理视点的体系结构模型);
软件体系结构设计文档;
#### 课外实验五
用户界面原型用户界面的UML类图模型以及界面跳转的顺序图模型
#### 课外实验六
用类图、顺序图、活动图、状态图等描述的详细设计模型;
#### 课外实验七
开源软件的维护代码;
#### 课外实验八
反馈通过测试发现的软件缺陷;
#### 课外实验九
可运行和可展示的开源软件系统;
#### 课外实验十
汇报PPT、技术博客等

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

@ -1,2 +0,0 @@
# Notes

@ -1,2 +0,0 @@
#Sun Apr 02 08:57:27 CST 2023
gradle.version=7.5

@ -17,4 +17,5 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
namespace 'net.micode.notes'
}

@ -17,12 +17,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="net.micode.notes"
android:versionCode="1"
android:versionName="0.1" >
android:versionName="0.1">
<!-- 添加 tools:ignore="GradleOverrides" 忽略 Gradle 对 minSdkVersion 的重写-->
<uses-sdk android:minSdkVersion="14"
<uses-sdk
android:minSdkVersion="14"
tools:ignore="GradleOverrides" />
@ -38,21 +37,16 @@
<application
android:icon="@drawable/icon_app"
android:label="@string/app_name" >
<!-- 添加android:exported="true" -->
<!-- 原因As of Android 12, android:exported must be set; use true to make the activity available to other apps, and false otherwise. For launcher activities, this should be set to true.-->
<!-- 移除android:label="@string/app_name"-->
<!-- 原因Redundant label can be removed.冗余标签可以移除第41行已经给出-->
android:label="@string/app_name">
<activity
android:name=".ui.NotesListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan"
android:exported="true">
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -60,20 +54,19 @@
</intent-filter>
</activity>
<!-- 添加android:exported="true" -->
<!-- 原因: As of Android 12, android:exported must be set; use true to make the activity available to other apps, and false otherwise. For launcher activities, this should be set to true.-->
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:exported="true">
android:theme="@style/NoteTheme">
<intent-filter android:scheme="http"
<intent-filter
android:scheme="http"
tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
@ -81,6 +74,7 @@
<intent-filter>
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
@ -95,22 +89,18 @@
android:resource="@xml/searchable" />
</activity>
<!-- 添加android:exported="false"-->
<!-- 原因Exported content providers can provide access to potentially sensitive data-->
<provider
android:name="net.micode.notes.data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true"
android:exported="false" />
android:exported="false"
android:multiprocess="true" />
<!-- 添加android:exported="true" -->
<!-- 原因: As of Android 12, android:exported must be set; use true to make the activity available to other apps, and false otherwise. For launcher activities, this should be set to true.-->
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2"
android:exported="true">
android:exported="true"
android:label="@string/app_widget2x2">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
@ -122,14 +112,27 @@
android:resource="@xml/widget_2x_info" />
</receiver>
<!-- 添加android:exported="true" -->
<!-- 原因: As of Android 12, android:exported must be set; use true to make the activity available to other apps, and false otherwise. For launcher activities, this should be set to true.-->
<!--新增3x3大小窗口小部件-->
<receiver
android:name=".widget.NoteWidgetProvider_3x"
android:exported="true"
android:label="@string/app_widget3x3">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_3x_info" />
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4"
android:exported="true">
android:exported="true"
android:label="@string/app_widget4x4">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -142,11 +145,9 @@
android:resource="@xml/widget_4x_info" />
</receiver>
<!-- 添加android:exported="true" -->
<!-- 原因: As of Android 12, android:exported must be set; use true to make the activity available to other apps, and false otherwise. For launcher activities, this should be set to true.-->
<receiver android:name=".ui.AlarmInitReceiver"
<receiver
android:name=".ui.AlarmInitReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
@ -155,29 +156,22 @@
<receiver
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
<!-- 移除android:label="@string/app_name"-->
<!-- 原因Redundant label can be removed.冗余标签可以移除第41行已经给出-->
android:process=":remote" />
<activity
android:name=".ui.AlarmAlertActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" />
<activity
android:name="net.micode.notes.ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light" >
</activity>
android:theme="@android:style/Theme.Holo.Light" />
<service
android:name="net.micode.notes.gtask.remote.GTaskSyncService"
android:exported="false" >
</service>
android:exported="false" />
<meta-data
android:name="android.app.default_searchable"

@ -1,3 +1,4 @@
// Apache许可证协议
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*

@ -24,10 +24,10 @@ public class Notes {
public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2;
/**
/*
* Following IDs are system folders' identifiers
* {@link Notes#ID_ROOT_FOLDER } is default folder
* {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder
* {@link Notes#ID_TEMPORARY_FOLDER } is for notes belonging no folder
* {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records
*/
public static final int ID_ROOT_FOLDER = 0;
@ -45,6 +45,7 @@ public class Notes {
public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0;
public static final int TYPE_WIDGET_4X = 1;
public static final int TYPE_WIDGET_3X = 2; // 3x3窗口小部件
public static class DataConstants {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
@ -205,35 +206,35 @@ public class Notes {
public static final String CONTENT = "content";
/**
/*
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA1 = "data1";
/**
/*
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA2 = "data2";
/**
/*
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA3 = "data3";
/**
/*
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA4 = "data4";
/**
/*
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>

@ -141,6 +141,20 @@ public class ResourceParser {
return BG_2X_RESOURCES[id];
}
//通过ID获取较小的图片
private final static int [] BG_3X_RESOURCES = new int [] {//通过id获得3x的小窗口背景资源
R.drawable.widget_2x_yellow,
R.drawable.widget_2x_blue,
R.drawable.widget_2x_white,
R.drawable.widget_2x_green,
R.drawable.widget_2x_red,
};
public static int getWidget3xBgResource(int id) {
return BG_3X_RESOURCES[id];
}
//通过ID获取较小的图片
private final static int [] BG_4X_RESOURCES = new int [] {
R.drawable.widget_4x_yellow,
R.drawable.widget_4x_blue,

@ -60,6 +60,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}
// 在Activity创建时被调用它首先设置Activity的特性然后获取传递过来的Intent从中获取提醒的ID和摘录信息并根据提醒的ID判断提醒是否可以在Note数据库中找到并显示对应的提醒对话框和播放提醒声音。
Intent intent = getIntent();
@ -82,11 +83,14 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
finish();
}
}
// 以一个try-catch块开始尝试从意图中提取一个笔记ID使用笔记ID从内容提供程序中检索与该笔记相关的文本片段并在文本片段太长时截断它。如果在此过程中抛出IllegalArgumentException异常则捕获该异常并返回方法。
//接下来的代码块创建一个新的MediaPlayer对象并检查与笔记ID关联的笔记是否在笔记数据库中可见。如果可见则调用名为showActionDialog()的方法该方法可能显示一个对话框给用户。还调用了playAlarmSound()方法,该方法可能会播放警报声。如果笔记在数据库中不可见,则方法仅完成而不显示对话框或播放声音。
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
// 用于判断屏幕是否打开。
private void playAlarmSound() {
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
@ -118,6 +122,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
e.printStackTrace();
}
}
// 用于播放提醒声音首先获取系统默认的闹铃铃声然后判断当前是否为静音模式如果是则设置MediaPlayer的音频流类型为系统当前可影响铃声的流否则设置为闹钟流类型。最后设置铃声数据源、循环播放并开始播放。
private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
@ -129,6 +134,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
dialog.show().setOnDismissListener(this);
}
// 用于显示提醒对话框,其中包含提醒的摘录信息和两个按钮(确认和进入)。
public void onClick(DialogInterface dialog, int which) {
switch (which) {
@ -142,11 +148,13 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
break;
}
}
// 用于处理对话框中按钮的点击事件如果是进入按钮则启动NoteEditActivity并携带提醒的ID将它作为Extra参数传递给NoteEditActivity以便打开对应的Note。如果是确认按钮则什么都不做。
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
finish();
}
// 用于处理提醒对话框关闭事件停止播放提醒声音并结束Activity。
private void stopAlarmSound() {
if (mPlayer != null) {
@ -156,3 +164,4 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
}
}
// 用于停止播放提醒声音。

@ -28,6 +28,8 @@ import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
//这里定义了一个包名为net.micode.notes.ui的Java类AlarmInitReceiver它继承了BroadcastReceiver类。引入了Android系统提供的AlarmManager、PendingIntent、BroadcastReceiver、ContentUris等类。还引入了笔记相关的数据模型Notes和NoteColumns。
//PROJECTION是笔记查询时的投影指定了需要查询的列。COLUMN_ID和COLUMN_ALERTED_DATE则是笔记查询结果中对应的列索引。
public class AlarmInitReceiver extends BroadcastReceiver {
private static final String [] PROJECTION = new String [] {
@ -62,4 +64,5 @@ public class AlarmInitReceiver extends BroadcastReceiver {
c.close();
}
}
// onReceive方法是接收广播后执行的方法。在这里首先获取当前时间戳currentDate然后通过getContentResolver().query方法查询所有需要提醒的笔记查询条件是提醒时间大于当前时间戳并且类型是笔记类型。
}

@ -27,4 +27,6 @@ public class AlarmReceiver extends BroadcastReceiver {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
// onReceive方法中首先获取传入的Intent对象并通过setClass方法将Intent的目标Activity设置为AlarmAlertActivity。然后通过addFlags方法设置Intent的标志位FLAG_ACTIVITY_NEW_TASK表示启动一个新的Task来显示Activity。最后通过context.startActivity方法启动Activity。
}
//这段代码的作用是在系统闹钟触发时启动AlarmAlertActivity来显示提醒内容。

@ -67,9 +67,9 @@ public class DateTimePicker extends FrameLayout {
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
updateDateControl();
onDateTimeChanged();
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);// 使用Calendar类的add方法将mDate对象的日期字段即Calendar.DAY_OF_YEAR增加newVal - oldVal天以更新日期。
updateDateControl();//调用updateDateControl方法该方法用来更新日期控件的显示。
onDateTimeChanged();//调用onDateTimeChanged方法该方法用来通知其他组件该日期时间已经发生了变化。
}
};
@ -104,16 +104,20 @@ public class DateTimePicker extends FrameLayout {
isDateChanged = true;
}
}
// 根据24小时制或12小时制以及上下午状态等情况计算新的时间并更新到mDate字段中。
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
mDate.set(Calendar.HOUR_OF_DAY, newHour);
onDateTimeChanged();
// 调用onDateTimeChanged方法该方法用来通知其他组件该日期时间已经发生了变化。
if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR));
setCurrentMonth(cal.get(Calendar.MONTH));
setCurrentDay(cal.get(Calendar.DAY_OF_MONTH));
}
// 如果日期发生了变化则调用setCurrentYear和setCurrentMonth方法更新年份和月份控件的显示。
}
};
// 这段代码定义了一个监听器对象用于监听小时NumberPicker控件的值变化事件。
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
@ -126,6 +130,7 @@ public class DateTimePicker extends FrameLayout {
} else if (oldVal == minValue && newVal == maxValue) {
offset -= 1;
}
// 当监听器被触发时,它首先根据 NumberPicker 的旧值和新值计算出一个 offset。如果旧值是最大值且新值是最小值则将 offset 增加1。如果旧值是最小值且新值是最大值则将 offset 减少1。
if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset);
mHourSpinner.setValue(getCurrentHour());
@ -139,10 +144,13 @@ public class DateTimePicker extends FrameLayout {
updateAmPmControl();
}
}
// 如果 offset 不为0则监听器会更新 mDate 变量,将 offset 添加到小时数中,将小时选择器的值设置为当前小时,调用 updateDateControl() 更新日期控件,并根据新的小时数更新 AM/PM 控件。
mDate.set(Calendar.MINUTE, newVal);
onDateTimeChanged();
// 更新 mDate 变量后,监听器将分钟值设置为新值,并调用 onDateTimeChanged() 通知任何监听器日期和时间已更新。
}
};
// 定义了一个私有字段 mOnMinuteChangedListener它是 NumberPicker.OnValueChangeListener 的一个实例。当表示分钟的 NumberPicker 的值发生变化时,此监听器将被触发。
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
@ -156,12 +164,16 @@ public class DateTimePicker extends FrameLayout {
updateAmPmControl();
onDateTimeChanged();
}
// 当监听器被触发时,它将 mIsAm 变量取反,表示用户选择了 AM 还是 PM。如果 mIsAm 是 true则说明用户选择了 AM此时监听器将 mDate 变量减去半天的小时数。如果 mIsAm 是 false则说明用户选择了 PM此时监听器将 mDate 变量加上半天的小时数。然后,监听器会调用 updateAmPmControl() 更新 AM/PM 控件,并调用 onDateTimeChanged() 通知任何监听器日期和时间已更新。
};
// 定义了一个私有字段 mOnAmPmChangedListener它是 NumberPicker.OnValueChangeListener 的一个实例。当表示 AM/PM 的 NumberPicker 的值发生变化时,此监听器将被触发。
public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute);
// 该接口有一个抽象方法 onDateTimeChanged(),它在日期或时间发生变化时被调用。该方法接收 6 个参数view 表示当前 DateTimePicker 实例year 表示年份month 表示月份(从 0 开始dayOfMonth 表示月中的某一天hourOfDay 表示小时数24 小时制minute 表示分钟数。
}
//定义了一个接口 OnDateTimeChangedListener它用于监听日期和时间的变化。当日期或时间发生变化时可以调用该接口的 onDateTimeChanged() 方法通知任何实现该接口的监听器。通过实现该接口并在需要的地方注册监听器,可以在日期或时间发生变化时执行自定义操作,例如更新 UI 或执行某些计算。
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
@ -173,15 +185,18 @@ public class DateTimePicker extends FrameLayout {
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
mDate = Calendar.getInstance();
mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this);
// 首先调用了父类 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.

@ -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() 方法中,从而通知调用者。
}

@ -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);
}
}//用于设置菜单的标题。
}

@ -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 应用程序中显示一个文件夹列表。

@ -63,6 +63,7 @@ import net.micode.notes.tool.ResourceParser.TextAppearanceResources;
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_3x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.util.HashMap;
@ -83,8 +84,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public ImageView ibSetBgColor;
}
// HeadViewHolder类定义了一组视图用于在列表或网格中显示信息。这些视图包括一个TextView用于显示修改信息一个ImageView用于显示警报图标另一个TextView用于显示警报日期还有一个ImageView用于选择背景颜色。
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
static {
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED);
@ -94,6 +97,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>();
static {
sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select);
sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select);
@ -101,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<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>();
static {
sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE);
sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL);
@ -111,12 +117,14 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>();
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";
@ -184,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
@ -197,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);
@ -204,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);
@ -211,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);
@ -269,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
@ -296,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()) {
@ -304,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
@ -321,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
@ -335,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;
}
@ -383,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);
@ -400,37 +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_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, "Unspported widget type");
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);
@ -450,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) {
@ -471,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) {
@ -503,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) {
@ -557,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();
@ -572,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
@ -584,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()) {
@ -606,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) {
/**
@ -626,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);
@ -645,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();
@ -659,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 {
@ -671,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");
}
@ -696,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++;
}
@ -707,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);
@ -724,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);
@ -755,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) {
@ -781,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;
@ -804,6 +846,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
return hasChecked;
}
// getWorkingText()方法用于获取当前工作文本。如果当前模式为清单模式,则将所有条目合并为一个字符串,并添加检查框状态。否则,将返回当前编辑器文本。
private boolean saveNote() {
getWorkingText();

@ -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);
}
// 创建上下文菜单,当用户长按控件中的链接时,根据链接的协议类型创建不同的菜单项,点击菜单项后跳转到相应的链接。
}

@ -70,6 +70,7 @@ import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_3x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.io.BufferedReader;
@ -81,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;
@ -93,7 +94,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private enum ListEditState {
NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER
};
}
;
private ListEditState mState;
@ -133,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) {
@ -156,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);
@ -180,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) {
@ -202,6 +207,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
}
// 这个方法从一个原始的资源文件中读取介绍文件并将其内容添加到应用程序的SharedPreferences中。如果介绍文件尚未被添加到SharedPreferences中它将被添加并设置一个标志表示文件已被添加。在此之后每次启动应用程序时它将不再读取介绍文件。
@Override
protected void onStart() {
@ -258,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();
@ -268,6 +274,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
});
return true;
}
// 这是Activity的onCreate()方法它在创建活动时被调用。它设置了视图并调用了setAppInfoFromRawRes()和initNoteListView()方法以初始化应用程序。
private void updateMenu() {
int selectedCount = mNotesListAdapter.getSelectedCount();
@ -284,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) {
@ -325,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;
@ -344,6 +351,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
return true;
}
// 处理下拉菜单中的菜单项点击事件。该方法在用户点击下拉菜单中的菜单项时调用并根据菜单项的ID执行相应的操作。如果成功处理了菜单项则返回true否则返回false。如果没有选中任何笔记则显示一个Toast提示用户需要先选择笔记。如果选择了“删除”菜单项则弹出一个对话框询问用户是否确定要删除所选笔记。如果选择了“移动”菜单项则启动查询目标文件夹的操作。
}
private class NewNoteOnTouchListener implements OnTouchListener {
@ -406,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;
@ -441,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<Void, Void, HashSet<AppWidgetAttribute>>() {
protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) {
HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget();
@ -533,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);
@ -605,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);
@ -623,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)) {
@ -662,7 +696,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
});
}
}//用于显示一个对话框,让用户输入或修改一个文件夹的名称。
@Override
public void onBackPressed() {
@ -687,25 +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_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) {
@ -717,6 +755,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
};
// 长按文件夹时创建上下文菜单的监听器,菜单包括查看文件夹、删除文件夹和修改文件夹名称等选项。
@Override
public void onContextMenuClosed(Menu menu) {
@ -725,6 +764,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
super.onContextMenuClosed(menu);
}
// 上下文菜单关闭时的操作将监听器设为null。
@Override
public boolean onContextItemSelected(MenuItem item) {
@ -759,6 +799,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true;
}
// 选择上下文菜单选项时的操作,根据所选选项执行不同的操作,如打开文件夹、删除文件夹或修改文件夹名称。
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
@ -777,6 +818,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
return true;
}
// 准备选项菜单时的操作,根据当前的状态显示不同的菜单选项,如笔记列表、子文件夹或通话记录文件夹。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@ -817,6 +859,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
return true;
}
// 选择选项菜单选项时的操作,根据所选选项执行不同的操作,如打开笔记列表、打开子文件夹或打开通话记录文件夹。
@Override
public boolean onSearchRequested() {
@ -869,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 {
@ -916,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) {
@ -951,4 +998,5 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
return false;
}
// 在列表项被长按时执行。它首先获取当前长按的列表项,并将其类型存储在 mFocusNoteDataItem 中。如果类型为笔记且不在选择模式下,则启动上下文操作模式,并将当前列表项标记为已选中。如果类型为文件夹,则设置上下文菜单的创建监听器。
}

@ -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<Long> getSelectedItemIds() {
HashSet<Long> itemSet = new HashSet<Long>();
@ -103,7 +103,8 @@ public class NotesListAdapter extends CursorAdapter {
}
return itemSet;
}
}//返回选定的笔记的 ID。
public HashSet<AppWidgetAttribute> getSelectedWidget() {
HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>();
@ -126,7 +127,7 @@ public class NotesListAdapter extends CursorAdapter {
}
}
return itemSet;
}
}//返回选定的小部件信息。
public int getSelectedCount() {
Collection<Boolean> 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;
}
}
}
}//计算笔记数量。
}

@ -98,6 +98,7 @@ public class NotesListItem extends LinearLayout {
setBackground(data);
}
// 用于将数据绑定到视图的UI组件上它接受一个NoteItemData对象其中包含有关笔记项的信息以及两个布尔标志choiceMode和checked。
private void setBackground(NoteItemData data) {
int id = data.getBgColorId();

@ -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;
}
}
}//当用户选择同步帐户时调用。在此方法中,更新同步按钮的文本视图,并启用同步按钮。
}

@ -32,7 +32,8 @@ import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NoteEditActivity;
import net.micode.notes.ui.NotesListActivity;
public abstract class NoteWidgetProvider extends AppWidgetProvider {
// 该类实现了桌面中的窗口小部件
public abstract class NoteWidgetProvider extends AppWidgetProvider { // 小米便签窗口小部件
public static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.BG_COLOR_ID,
@ -46,18 +47,18 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
private static final String TAG = "NoteWidgetProvider";
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
public void onDeleted(Context context, int[] appWidgetIds) { // 重写删除窗口小部件函数
ContentValues values = new ContentValues();
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
for (int i = 0; i < appWidgetIds.length; i++) {
for (int appWidgetId : appWidgetIds) {
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
values,
NoteColumns.WIDGET_ID + "=?",
new String[] { String.valueOf(appWidgetIds[i])});
new String[]{String.valueOf(appWidgetId)});
}
}
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
private Cursor getNoteWidgetInfo(Context context, int widgetId) { // 获取窗口小部件宽度信息
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?",
@ -70,20 +71,23 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
}
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
boolean privacyMode) {
for (int i = 0; i < appWidgetIds.length; i++) {
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
boolean privacyMode) { // 更新窗口小部件中的内容
/*
* Generate the pending intent to start host for the widget
*/
for (int appWidgetId : appWidgetIds) {
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
int bgId = ResourceParser.getDefaultBgId(context);
String snippet = "";
Intent intent = new Intent(context, NoteEditActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetId);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]);
Cursor c = getNoteWidgetInfo(context, appWidgetId);
if (c != null && c.moveToFirst()) {
if (c.getCount() > 1) {
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
Log.e(TAG, "Multiple message with same widget id:" + appWidgetId);
c.close();
return;
}
@ -103,30 +107,30 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
/**
/*
* Generate the pending intent to start host for the widget
*/
PendingIntent pendingIntent = null;
if (privacyMode) {
rv.setTextViewText(R.id.widget_text,
context.getString(R.string.widget_under_visit_mode));
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent(
pendingIntent = PendingIntent.getActivity(context, appWidgetId, new Intent(
context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
} else {
rv.setTextViewText(R.id.widget_text, snippet);
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent,
pendingIntent = PendingIntent.getActivity(context, appWidgetId, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
appWidgetManager.updateAppWidget(appWidgetId, rv);
}
}
}
protected abstract int getBgResourceId(int bgId);
protected abstract int getBgResourceId(int bgId); // 从背景资源中获取当前应用ID
protected abstract int getLayoutId();
protected abstract int getLayoutId(); // 获取布局ID
protected abstract int getWidgetType();
protected abstract int getWidgetType(); // 获取窗口小部件的类型即2x2型或者3x3型或者4x4型
}

@ -24,23 +24,23 @@ import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
public class NoteWidgetProvider_2x extends NoteWidgetProvider {
@Override
public class NoteWidgetProvider_2x extends NoteWidgetProvider { // 2x2大小的窗口小部件
@Override // 重写窗口小部件中的更新函数
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.update(context, appWidgetManager, appWidgetIds);
}
@Override
@Override // 重写窗口小部件中的获取布局ID函数
protected int getLayoutId() {
return R.layout.widget_2x;
}
@Override
@Override // 重写窗口小部件中的获取资源ID函数
protected int getBgResourceId(int bgId) {
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
}
@Override
@Override // 重写窗口小部件中的获取宽度类型函数
protected int getWidgetType() {
return Notes.TYPE_WIDGET_2X;
}

@ -0,0 +1,46 @@
/*
* 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.widget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
public class NoteWidgetProvider_3x extends NoteWidgetProvider{ // 3x3大小的窗口小部件
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.update(context, appWidgetManager, appWidgetIds);
}
@Override // 重写窗口小部件中的获取布局ID函数
protected int getLayoutId() {
return R.layout.widget_3x;
}
@Override // 重写窗口小部件中的获取资源ID函数
protected int getBgResourceId(int bgId) {
return ResourceParser.WidgetBgResources.getWidget3xBgResource(bgId);
}
@Override // 重写窗口小部件中的获取宽度类型函数
protected int getWidgetType() {
return Notes.TYPE_WIDGET_3X;
}
}

@ -24,22 +24,23 @@ import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
public class NoteWidgetProvider_4x extends NoteWidgetProvider {
@Override
public class NoteWidgetProvider_4x extends NoteWidgetProvider { // 4x4大小的窗口小部件
@Override // 重写窗口小部件中的更新函数
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.update(context, appWidgetManager, appWidgetIds);
}
@Override // 重写窗口小部件中的获取布局ID函数
protected int getLayoutId() {
return R.layout.widget_4x;
}
@Override
@Override // 重写窗口小部件中的获取资源ID函数
protected int getBgResourceId(int bgId) {
return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId);
}
@Override
@Override // 重写窗口小部件中的获取宽度类型函数
protected int getWidgetType() {
return Notes.TYPE_WIDGET_4X;
}

@ -16,7 +16,7 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#88555555" />
<item android:state_selected="true" android:color="#ff999999" />
<item android:color="#ff000000" />
<item android:color="#88555555" android:state_pressed="true" />
<item android:color="#ff999999" android:state_selected="true" />
<item android:color="#ff000000" />
</selector>

@ -16,5 +16,5 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#50000000" />
<item android:color="#50000000" />
</selector>

@ -1,23 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/new_note_pressed" />
<item
android:drawable="@drawable/new_note_normal" />
<item android:drawable="@drawable/new_note_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/new_note_normal" />
</selector>

@ -24,13 +24,13 @@
<TextView
android:id="@+id/account_dialog_title"
style="?android:attr/textAppearanceMedium"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2.7dip"
android:layout_marginBottom="-2.7dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
android:ellipsize="end"
android:gravity="center"
android:singleLine="true" />
<TextView
android:id="@+id/account_dialog_subtitle"
@ -38,6 +38,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:layout_marginBottom="1dip"
android:gravity="center"/>
android:gravity="center" />
</LinearLayout>

@ -19,14 +19,14 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="50dip"
android:gravity="center_vertical"
android:minHeight="50dip"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/preferences_add_account" />
android:text="@string/preferences_add_account"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

@ -19,5 +19,5 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/et_foler_name"
android:layout_width="fill_parent"
android:hint="@string/hint_foler_name"
android:layout_height="fill_parent" />
android:layout_height="fill_parent"
android:hint="@string/hint_foler_name" />

@ -18,7 +18,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="50dip" >
android:minHeight="50dip">
<TextView
android:id="@+id/tv_folder_name"

@ -24,16 +24,16 @@
android:id="@+id/cb_edit_item"
android:layout_width="wrap_content"
android:layout_height="28dip"
android:layout_gravity="top|left"
android:checked="false"
android:focusable="false"
android:layout_gravity="top|left" />
android:focusable="false" />
<net.micode.notes.ui.NoteEditText
android:id="@+id/et_edit_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:lineSpacingMultiplier="1.2"
android:layout_gravity="center_vertical"
android:textAppearance="@style/TextAppearancePrimaryItem"
android:background="@null" />
android:background="@null"
android:lineSpacingMultiplier="1.2"
android:textAppearance="@style/TextAppearancePrimaryItem" />
</LinearLayout>

@ -65,8 +65,8 @@
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:clickable="false"
android:focusable="false"
android:visibility="gone" />
</LinearLayout>
@ -74,5 +74,5 @@
android:id="@+id/iv_alert_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right"/>
android:layout_gravity="top|right" />
</FrameLayout>

@ -31,11 +31,11 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/title_bar_bg"
android:visibility="gone"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="#FFEAD1AE"
android:textSize="@dimen/text_font_size_medium" />
android:textSize="@dimen/text_font_size_medium"
android:visibility="gone" />
<ListView
android:id="@+id/notes_list"
@ -43,16 +43,16 @@
android:layout_height="0dip"
android:layout_weight="1"
android:cacheColorHint="@null"
android:listSelector="@android:color/transparent"
android:divider="@null"
android:fadingEdge="@null" />
android:fadingEdge="@null"
android:listSelector="@android:color/transparent" />
</LinearLayout>
<Button
android:id="@+id/btn_new_note"
android:background="@drawable/new_note"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:layout_gravity="bottom" />
android:layout_gravity="bottom"
android:background="@drawable/new_note"
android:focusable="false" />
</FrameLayout>

@ -19,6 +19,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="100dip"
android:visibility="invisible"
android:background="@drawable/list_footer_bg"
android:focusable="false"
android:background="@drawable/list_footer_bg" />
android:visibility="invisible" />

@ -23,19 +23,19 @@
<Button
android:id="@+id/preference_sync_button"
style="?android:attr/textAppearanceMedium"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dip"
android:layout_marginLeft="30dip"
android:layout_marginTop="15dip"
android:layout_marginRight="30dip"
style="?android:attr/textAppearanceMedium"
android:text="@string/preferences_button_sync_immediately"/>
android:text="@string/preferences_button_sync_immediately" />
<TextView
android:id="@+id/prefenerece_sync_status_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
android:visibility="gone" />
</LinearLayout>

@ -19,19 +19,21 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="146dip"
android:layout_height="146dip">
<ImageView
android:id="@+id/widget_bg_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:id="@+id/widget_text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="20dip"
android:lineSpacingMultiplier="1.2"
android:maxLines="6"
android:paddingLeft="15dip"
android:paddingTop="20dip"
android:paddingRight="15dip"
android:textSize="14sp"
android:textColor="#FF663300"
android:maxLines="6"
android:lineSpacingMultiplier="1.2" />
android:textSize="14sp" />
</FrameLayout>

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="220dip"
android:layout_height="220dip">
<ImageView
android:id="@+id/widget_bg_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:id="@+id/widget_text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:lineSpacingMultiplier="1.2"
android:maxLines="9"
android:paddingLeft="15dip"
android:paddingTop="30dip"
android:paddingRight="15dip"
android:textColor="#FF663300"
android:textSize="14sp" />
</FrameLayout>

@ -29,11 +29,11 @@
android:id="@+id/widget_text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="40dip"
android:lineSpacingMultiplier="1.2"
android:maxLines="12"
android:paddingLeft="15dip"
android:paddingTop="40dip"
android:paddingRight="15dip"
android:textSize="14sp"
android:textColor="#FF663300"
android:maxLines="12"
android:lineSpacingMultiplier="1.2" />
android:textSize="14sp" />
</FrameLayout>

@ -24,7 +24,7 @@
<item
android:id="@+id/menu_font_size"
android:title="@string/menu_font_size"/>
android:title="@string/menu_font_size" />
<item
android:id="@+id/menu_list_mode"
@ -32,11 +32,11 @@
<item
android:id="@+id/menu_share"
android:title="@string/menu_share"/>
android:title="@string/menu_share" />
<item
android:id="@+id/menu_send_to_desktop"
android:title="@string/menu_send_to_desktop"/>
android:title="@string/menu_send_to_desktop" />
<item
android:id="@+id/menu_alert"

@ -20,15 +20,15 @@
<item
android:id="@+id/menu_new_note"
android:title="@string/notelist_menu_new"/>
android:title="@string/notelist_menu_new" />
<item
android:id="@+id/menu_delete"
android:title="@string/menu_delete"/>
android:title="@string/menu_delete" />
<item
android:id="@+id/menu_font_size"
android:title="@string/menu_font_size"/>
android:title="@string/menu_font_size" />
<item
android:id="@+id/menu_list_mode"
@ -36,11 +36,11 @@
<item
android:id="@+id/menu_share"
android:title="@string/menu_share"/>
android:title="@string/menu_share" />
<item
android:id="@+id/menu_send_to_desktop"
android:title="@string/menu_send_to_desktop"/>
android:title="@string/menu_send_to_desktop" />
<item
android:id="@+id/menu_alert"

@ -19,15 +19,15 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_new_folder"
android:title="@string/menu_create_folder"/>
android:title="@string/menu_create_folder" />
<item
android:id="@+id/menu_export_text"
android:title="@string/menu_export_text"/>
android:title="@string/menu_export_text" />
<item
android:id="@+id/menu_sync"
android:title="@string/menu_sync"/>
android:title="@string/menu_sync" />
<item
android:id="@+id/menu_setting"
@ -35,5 +35,5 @@
<item
android:id="@+id/menu_search"
android:title="@string/menu_search"/>
android:title="@string/menu_search" />
</menu>

@ -16,5 +16,7 @@
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_select_all" android:title="@string/menu_select_all" />
<item
android:id="@+id/action_select_all"
android:title="@string/menu_select_all" />
</menu>

@ -19,13 +19,13 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/move"
android:title="@string/menu_move"
android:icon="@drawable/menu_move"
android:showAsAction="always|withText" />
android:showAsAction="always|withText"
android:title="@string/menu_move" />
<item
android:id="@+id/delete"
android:title="@string/menu_delete"
android:icon="@drawable/menu_delete"
android:showAsAction="always|withText" />
android:showAsAction="always|withText"
android:title="@string/menu_delete" />
</menu>

@ -20,5 +20,5 @@
<item
android:id="@+id/menu_new_note"
android:title="@string/notelist_menu_new"/>
android:title="@string/notelist_menu_new" />
</menu>

@ -19,6 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">便签</string>
<string name="app_widget2x2">便签2x2</string>
<string name="app_widget3x3">便签3x3</string>
<string name="app_widget4x4">便签4x4</string>
<string name="widget_havenot_content">没有关联内容,点击新建便签。</string>
<string name="widget_under_visit_mode">访客模式下,便签内容不可见</string>

@ -19,6 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">便簽</string>
<string name="app_widget2x2">便簽2x2</string>
<string name="app_widget3x3">便簽3x3</string>
<string name="app_widget4x4">便簽4x4</string>
<string name="widget_havenot_content">沒有關聯內容,點擊新建便簽。</string>
<string name="widget_under_visit_mode">訪客模式下,便籤內容不可見</string>

@ -19,6 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Notes</string>
<string name="app_widget2x2">Notes 2x2</string>
<string name="app_widget3x3" translatable="false">Notes 3x3</string>
<string name="app_widget4x4">Notes 4x4</string>
<string name="widget_havenot_content">No associated note found, click to create associated note.</string>
<string name="widget_under_visit_mode">Privacy modecan not see note content</string>

@ -16,18 +16,22 @@
-->
<resources>
<style name="TextAppearanceSuper">
<item name="android:textSize">@dimen/text_font_size_super</item>
<item name="android:textColorLink">#0000ff</item>
</style>
<style name="TextAppearanceLarge">
<item name="android:textSize">@dimen/text_font_size_large</item>
<item name="android:textColorLink">#0000ff</item>
</style>
<style name="TextAppearanceMedium">
<item name="android:textSize">@dimen/text_font_size_medium</item>
<item name="android:textColorLink">#0000ff</item>
</style>
<style name="TextAppearanceNormal">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColorLink">#0000ff</item>
@ -49,7 +53,7 @@
</style>
<style name="HighlightTextAppearancePrimary">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColor">@color/primary_text_dark</item>
</style>

@ -15,13 +15,10 @@
limitations under the License.
-->
<searchable
xmlns:android="http://schemas.android.com/apk/res/android"
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint"
android:searchMode="queryRewriteFromText"
android:searchSuggestAuthority="notes"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:searchMode="queryRewriteFromText"
android:searchSettingsDescription="@string/search_setting_description"
android:includeInGlobalSearch="true" />
android:searchSuggestAuthority="notes"
android:searchSuggestIntentAction="android.intent.action.VIEW" />

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_3x"
android:minWidth="220dip"
android:minHeight="220dip">
</appwidget-provider>

@ -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'
}
}

@ -0,0 +1,3 @@
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false
android.nonTransitiveRClass=false

@ -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

Loading…
Cancel
Save