Compare commits

...

15 Commits

Author SHA1 Message Date
gq e5d7eba3a6 每个方法都添加了完整的JavaDoc注释,说明方法功能和返回值
2 months ago
gq 861aaddbcf 注释说明了适配器的用途和基本功能
2 months ago
gq 5c66d9ef96 解释了类如何封装PopupMenu的功能
2 months ago
gq 88c849dbf4 注释说明了这个广播接收器的主要功能
2 months ago
gq 07105431f7 注释了创建上下文菜单,特别是处理URL链接
3 months ago
gq fa0d2533ce 注释了处理键盘抬起事件
3 months ago
gq 710449d7e5 注释了处理键盘按下事件
3 months ago
gq 5301c396d8 注释的处理触摸事件并进行文本选择功能
3 months ago
gq 091c18441c test
3 months ago
pjkbof4hw 21c3a68f7d Merge pull request '解决关于小米便签功能不完全的问题' (#15) from d_merge_branch into d_branch
3 months ago
pjkbof4hw cccf12ce59 Merge pull request '解决 找不到符号 notification.setLatestEventInfo...' (#10) from d_merge_branch into d_branch
4 months ago
pjkbof4hw ea5bf13bee Merge pull request '为项目添加依赖包' (#9) from d_merge_branch into d_branch
4 months ago
pjkbof4hw 7b2375de27 Merge pull request '将源码对应的文件复制到 Android 项目的对应目录及文件下' (#8) from d_merge_branch into d_branch
4 months ago
pjkbof4hw 6eb30279b3 Merge pull request '将项目的AndroidManifest.xml替换为源代码提供的xml文件' (#7) from d_merge_branch into d_branch
4 months ago
pjkbof4hw 2295416170 Merge pull request '将源文件创建Android stdio项目文件' (#6) from d_merge_branch into d_branch
4 months ago

@ -1,2 +1,2 @@
#Thu Apr 17 19:12:09 CST 2025
java.home=E\:\\Android Studio\\jbr
#Wed May 14 23:31:33 CST 2025
java.home=D\:\\Android\\Android Studio\\jbr

@ -4,7 +4,6 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
@ -13,6 +12,7 @@
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

@ -1,6 +1,6 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

@ -73,6 +73,18 @@
<ProjectState />
</projectState>
</component>
<component name="ExternalProjectsManager">
<system id="GRADLE">
<state>
<projects_view>
<tree_state>
<expand />
<select />
</tree_state>
</projects_view>
</state>
</system>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
@ -105,7 +117,6 @@
<component name="RunManager">
<configuration name="app" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
<module name="Notes-master.app" />
<option name="ANDROID_RUN_CONFIGURATION_SCHEMA_VERSION" value="1" />
<option name="DEPLOY" value="true" />
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
<option name="DEPLOY_AS_INSTANT" value="false" />
@ -113,14 +124,10 @@
<option name="PM_INSTALL_OPTIONS" value="" />
<option name="ALL_USERS" value="false" />
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
<option name="ALLOW_ASSUME_VERIFIED" value="false" />
<option name="CLEAR_APP_STORAGE" value="false" />
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
<option name="MODE" value="default_activity" />
<option name="RESTORE_ENABLED" value="false" />
<option name="RESTORE_FILE" value="" />
<option name="RESTORE_FRESH_INSTALL_ONLY" value="false" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
@ -167,7 +174,6 @@
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
</Profilers>
<option name="DEEP_LINK" value="" />
<option name="ACTIVITY" value="" />
<option name="ACTIVITY_CLASS" value="" />
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />

@ -28,37 +28,62 @@ import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/**
* 广
*/
public class AlarmInitReceiver extends BroadcastReceiver {
// 查询笔记时需要的列名数组
private static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.ALERTED_DATE
NoteColumns.ID, // 笔记ID列
NoteColumns.ALERTED_DATE // 提醒日期列
};
private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1;
// 列索引常量
private static final int COLUMN_ID = 0; // ID列的索引
private static final int COLUMN_ALERTED_DATE = 1; // 提醒日期列的索引
/**
* 广
* @param context
* @param intent
*/
@Override
public void onReceive(Context context, Intent intent) {
// 获取当前系统时间
long currentDate = System.currentTimeMillis();
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) },
null);
// 查询内容提供器获取需要设置提醒的笔记
Cursor c = context.getContentResolver().query(
Notes.CONTENT_NOTE_URI, // 笔记内容URI
PROJECTION, // 要查询的列
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, // 查询条件:提醒日期大于当前时间且类型为普通笔记
new String[] { String.valueOf(currentDate) }, // 查询参数
null); // 排序方式
if (c != null) {
// 如果有查询结果
if (c.moveToFirst()) {
do {
// 获取提醒日期
long alertDate = c.getLong(COLUMN_ALERTED_DATE);
// 创建闹钟接收器Intent
Intent sender = new Intent(context, AlarmReceiver.class);
// 设置Intent的数据URI包含笔记ID
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
// 创建PendingIntent
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
AlarmManager alermManager = (AlarmManager) context
// 获取AlarmManager服务
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext());
// 设置闹钟,在指定时间触发
alarmManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext()); // 处理下一条记录
}
// 关闭Cursor
c.close();
}
}

@ -27,17 +27,38 @@ import android.widget.PopupMenu.OnMenuItemClickListener;
import net.micode.notes.R;
/**
*
* PopupMenu使便
*/
public class DropdownMenu {
// 触发下拉菜单的按钮控件
private Button mButton;
// PopupMenu对象实现下拉菜单功能
private PopupMenu mPopupMenu;
// 菜单对象,包含所有菜单项
private Menu mMenu;
/**
*
* @param context
* @param button
* @param menuId ID
*/
public DropdownMenu(Context context, Button button, int menuId) {
// 初始化按钮引用
mButton = button;
// 设置按钮背景图标
mButton.setBackgroundResource(R.drawable.dropdown_icon);
// 创建PopupMenu实例绑定到按钮
mPopupMenu = new PopupMenu(context, mButton);
// 获取菜单对象
mMenu = mPopupMenu.getMenu();
// 从资源文件填充菜单
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
// 设置按钮点击事件,点击时显示下拉菜单
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show();
@ -45,16 +66,29 @@ public class DropdownMenu {
});
}
/**
*
* @param listener
*/
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener);
}
}
/**
* ID
* @param id ID
* @return null
*/
public MenuItem findItem(int id) {
return mMenu.findItem(id);
}
/**
*
* @param title
*/
public void setTitle(CharSequence title) {
mButton.setText(title);
}

@ -29,52 +29,103 @@ import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/**
*
* CursorAdapterCursor
*/
public class FoldersListAdapter extends CursorAdapter {
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
// 查询列名数组定义需要从Cursor中获取的列
public static final String[] PROJECTION = {
NoteColumns.ID, // 文件夹ID列
NoteColumns.SNIPPET // 文件夹名称/片段列
};
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
// 列索引常量
public static final int ID_COLUMN = 0; // ID列的索引位置
public static final int NAME_COLUMN = 1; // 名称列的索引位置
/**
*
* @param context
* @param c Cursor
*/
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
// TODO: 可在此处添加初始化代码
}
/**
*
* @param context
* @param cursor Cursor
* @param parent
* @return
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// 创建新的FolderListItem实例
return new FolderListItem(context);
}
/**
*
* @param view
* @param context
* @param cursor Cursor
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
// 检查视图类型是否正确
if (view instanceof FolderListItem) {
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
// 根据ID判断是否是根文件夹获取对应的显示名称
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER)
? context.getString(R.string.menu_move_parent_folder)
: cursor.getString(NAME_COLUMN);
// 调用FolderListItem的bind方法设置名称
((FolderListItem) view).bind(folderName);
}
}
/**
*
* @param context
* @param position
* @return
*/
public String getFolderName(Context context, int position) {
// 获取指定位置的Cursor对象
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);
// 根据ID判断是否是根文件夹返回对应的名称
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;
private TextView mName; // 显示文件夹名称的TextView
/**
*
* @param context
*/
public FolderListItem(Context context) {
super(context);
// 从布局文件填充视图
inflate(context, R.layout.folder_list_item, this);
// 查找名称TextView
mName = (TextView) findViewById(R.id.tv_folder_name);
}
/**
*
* @param name
*/
public void bind(String name) {
// 设置TextView文本
mName.setText(name);
}
}
}

@ -37,6 +37,7 @@ import net.micode.notes.R;
import java.util.HashMap;
import java.util.Map;
//笔记编辑ui
public class NoteEditText extends EditText {
private static final String TAG = "NoteEditText";
private int mIndex;
@ -99,71 +100,118 @@ public class NoteEditText extends EditText {
// TODO Auto-generated constructor stub
}
/**
*
*
* @param event
* @return truefalse
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_DOWN: // 手指按下屏幕事件
// 1. 获取触摸点的原始坐标
int x = (int) event.getX();
int y = (int) event.getY();
x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();
x += getScrollX();
y += getScrollY();
// 2. 调整坐标,去除内边距的影响
x -= getTotalPaddingLeft(); // 减去左侧内边距
y -= getTotalPaddingTop(); // 减去顶部内边距
// 3. 考虑滚动偏移量
x += getScrollX(); // 加上水平滚动距离
y += getScrollY(); // 加上垂直滚动距离
// 4. 获取文本布局对象
Layout layout = getLayout();
// 5. 根据y坐标获取行号
int line = layout.getLineForVertical(y);
// 6. 根据x坐标获取该行内的字符偏移量
int off = layout.getOffsetForHorizontal(line, x);
// 7. 设置文本选择位置
Selection.setSelection(getText(), off);
break;
}
// 调用父类方法处理其他触摸事件(如移动、抬起等)
return super.onTouchEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 处理键盘按下事件
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_ENTER: // 回车键处理
// 当存在文本变化监听器时,不消费回车键事件
// 以便监听器可以自定义回车键行为(如换行处理)
if (mOnTextViewChangeListener != null) {
return false;
return false; // false表示允许事件继续传递
}
break;
case KeyEvent.KEYCODE_DEL:
case KeyEvent.KEYCODE_DEL: // 删除键处理
// 记录删除前的光标起始位置
// 用于支持撤销操作或特殊删除逻辑
mSelectionStartBeforeDelete = getSelectionStart();
break;
default:
// 其他按键不做特殊处理
break;
}
// 未被处理的按键事件交由父类默认处理
return super.onKeyDown(keyCode, event);
}
/**
*
* @param keyCode KeyEvent.KEYCODE_DEL
* @param event
* @return truefalse
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch(keyCode) {
case KeyEvent.KEYCODE_DEL:
case KeyEvent.KEYCODE_DEL: // 删除键抬起事件
// 当设置了文本变化监听器时
if (mOnTextViewChangeListener != null) {
// 如果光标在文本开头且不是第一个编辑框
if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
// 回调删除事件,传递当前索引和文本内容
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
return true;
return true; // 事件已处理
}
} else {
Log.d(TAG, "OnTextViewChangeListener was not seted");
Log.d(TAG, "OnTextViewChangeListener was not set");
}
break;
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_ENTER: // 回车键抬起事件
// 当设置了文本变化监听器时
if (mOnTextViewChangeListener != null) {
// 获取当前光标位置
int selectionStart = getSelectionStart();
// 截取光标后的文本
String text = getText().subSequence(selectionStart, length()).toString();
// 保留光标前的文本
setText(getText().subSequence(0, selectionStart));
// 回调回车事件,传递下一个索引和截取的文本
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
} else {
Log.d(TAG, "OnTextViewChangeListener was not seted");
Log.d(TAG, "OnTextViewChangeListener was not set");
}
break;
default:
// 其他按键不做特殊处理
break;
}
// 未被处理的按键事件交由父类处理
return super.onKeyUp(keyCode, event);
}
@ -179,39 +227,57 @@ public class NoteEditText extends EditText {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
/**
*
* URL
*/
@Override
protected void onCreateContextMenu(ContextMenu menu) {
// 检查当前文本是否包含富文本样式(如超链接)
if (getText() instanceof Spanned) {
// 获取当前选中的文本范围
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
// 确保起始和结束位置正确排序
int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd);
// 从选中文本中提取URLSpan对象超链接
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
// 如果只选中了一个URL链接
if (urls.length == 1) {
int defaultResId = 0;
for(String schema: sSchemaActionResMap.keySet()) {
int defaultResId = 0; // 默认菜单项资源ID
// 遍历预定义的URL协议映射表
for(String schema : sSchemaActionResMap.keySet()) {
// 检查当前URL是否包含特定协议如http, mailto等
if(urls[0].getURL().indexOf(schema) >= 0) {
// 获取对应的菜单项文本资源ID
defaultResId = sSchemaActionResMap.get(schema);
break;
}
}
// 如果没有匹配的协议,使用默认"其他链接"菜单项
if (defaultResId == 0) {
defaultResId = R.string.note_link_other;
}
// 添加菜单项并设置点击监听器
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
// goto a new intent
// 当菜单项被点击时触发URL链接的默认行为
// 比如打开浏览器或邮件客户端
urls[0].onClick(NoteEditText.this);
return true;
return true; // 表示事件已处理
}
});
}
}
// 调用父类方法继续处理其他上下文菜单逻辑
super.onCreateContextMenu(menu);
}
}

@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");

Loading…
Cancel
Save