diff --git a/src/net/micode/notes/ui/AlarmInitReceiver.java b/src/net/micode/notes/ui/AlarmInitReceiver.java index f221202..01da712 100644 --- a/src/net/micode/notes/ui/AlarmInitReceiver.java +++ b/src/net/micode/notes/ui/AlarmInitReceiver.java @@ -26,39 +26,64 @@ import android.database.Cursor; 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; + /** + * 接收广播并处理便签提醒初始化逻辑 + * + * @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); + // 遍历查询结果,为每个便签设置系统提醒 if (c != null) { if (c.moveToFirst()) { do { + // 获取便签提醒时间和ID long alertDate = c.getLong(COLUMN_ALERTED_DATE); + + // 创建触发闹钟时要发送的广播意图 Intent sender = new Intent(context, AlarmReceiver.class); sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); + // 创建待处理意图,用于系统在指定时间触发提醒 PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); + // 获取系统闹钟服务 AlarmManager alermManager = (AlarmManager) context .getSystemService(Context.ALARM_SERVICE); + // 设置提醒:使用RTC_WAKEUP类型,确保系统在指定时间唤醒并触发提醒 alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); } while (c.moveToNext()); } + // 关闭游标,释放资源 c.close(); } } diff --git a/src/net/micode/notes/ui/AlarmReceiver.java b/src/net/micode/notes/ui/AlarmReceiver.java index 54e503b..34dd963 100644 --- a/src/net/micode/notes/ui/AlarmReceiver.java +++ b/src/net/micode/notes/ui/AlarmReceiver.java @@ -19,12 +19,28 @@ package net.micode.notes.ui; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +/** + * 闹钟提醒接收器 - 负责接收系统闹钟触发的广播并启动提醒界面 + * + * 当便签设置的提醒时间到达时,系统会发送对应的广播,此接收器会捕获该广播 + * 并启动一个全屏的提醒活动,向用户展示提醒内容 + */ public class AlarmReceiver extends BroadcastReceiver { + /** + * 接收系统闹钟广播并处理提醒逻辑 + * + * @param context 应用上下文 + * @param intent 触发广播的意图,包含便签数据和提醒信息 + */ @Override public void onReceive(Context context, Intent intent) { + // 设置要启动的活动类为闹钟提醒界面 intent.setClass(context, AlarmAlertActivity.class); + // 添加FLAG_ACTIVITY_NEW_TASK标志,因为在广播接收器中启动活动需要此标志 + // 它表示在新的任务栈中启动活动,避免与现有任务栈冲突 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // 启动闹钟提醒界面,向用户展示便签提醒 context.startActivity(intent); } } diff --git a/src/net/micode/notes/ui/DateTimePickerDialog.java b/src/net/micode/notes/ui/DateTimePickerDialog.java index 2c47ba4..e0ad9dd 100644 --- a/src/net/micode/notes/ui/DateTimePickerDialog.java +++ b/src/net/micode/notes/ui/DateTimePickerDialog.java @@ -28,60 +28,119 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.text.format.DateFormat; import android.text.format.DateUtils; +/** + * 日期时间选择对话框 - 提供用户友好的界面来选择具体的日期和时间 + * + * 继承自AlertDialog,整合了自定义的DateTimePicker组件 + * 支持12/24小时制显示,并提供日期时间选择回调接口 + */ public class DateTimePickerDialog extends AlertDialog implements OnClickListener { - + // 当前选择的日期时间 private Calendar mDate = Calendar.getInstance(); + // 是否使用24小时制 private boolean mIs24HourView; + // 日期时间选择回调接口 private OnDateTimeSetListener mOnDateTimeSetListener; + // 自定义的日期时间选择器组件 private DateTimePicker mDateTimePicker; + /** + * 日期时间设置回调接口 + * 当用户确认选择的日期时间时触发 + */ public interface OnDateTimeSetListener { + /** + * 当用户设置日期时间时调用 + * + * @param dialog 日期时间选择对话框实例 + * @param date 选择的时间戳(毫秒) + */ void OnDateTimeSet(AlertDialog dialog, long date); } + /** + * 构造函数,初始化日期时间选择对话框 + * + * @param context 应用上下文 + * @param date 默认选中的时间戳(毫秒) + */ public DateTimePickerDialog(Context context, long date) { + // 初始化自定义日期时间选择器 super(context); mDateTimePicker = new DateTimePicker(context); setView(mDateTimePicker); + // 设置日期时间变化监听器 mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { public void onDateTimeChanged(DateTimePicker view, int year, int month, int dayOfMonth, int hourOfDay, int minute) { + // 更新内部Calendar对象 mDate.set(Calendar.YEAR, year); mDate.set(Calendar.MONTH, month); mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); mDate.set(Calendar.MINUTE, minute); + // 更新对话框标题显示 updateTitle(mDate.getTimeInMillis()); } }); + // 设置初始时间并清除秒数 mDate.setTimeInMillis(date); mDate.set(Calendar.SECOND, 0); + // 设置选择器的当前日期时间 mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); + // 设置对话框按钮 setButton(context.getString(R.string.datetime_dialog_ok), this); setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); + // 设置24小时制显示(基于系统设置) set24HourView(DateFormat.is24HourFormat(this.getContext())); + // 更新对话框标题 updateTitle(mDate.getTimeInMillis()); } + /** + * 设置时间显示格式(12/24小时制) + * + * @param is24HourView true表示使用24小时制,false表示使用12小时制 + */ public void set24HourView(boolean is24HourView) { mIs24HourView = is24HourView; } + /** + * 设置日期时间选择回调接口 + * + * @param callBack 实现了OnDateTimeSetListener接口的回调对象 + */ public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { mOnDateTimeSetListener = callBack; } + /** + * 更新对话框标题,显示当前选择的日期时间 + * + * @param date 要显示的时间戳(毫秒) + */ private void updateTitle(long date) { + // 设置日期时间显示标志 int flag = - DateUtils.FORMAT_SHOW_YEAR | - DateUtils.FORMAT_SHOW_DATE | - DateUtils.FORMAT_SHOW_TIME; + DateUtils.FORMAT_SHOW_YEAR | // 显示年份 + DateUtils.FORMAT_SHOW_DATE | // 显示日期 + DateUtils.FORMAT_SHOW_TIME; // 显示时间 + // 根据24小时制设置标志 flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; + // 更新对话框标题 setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); } + /** + * 处理对话框按钮点击事件 + * + * @param arg0 对话框接口 + * @param arg1 按钮标识 + */ public void onClick(DialogInterface arg0, int arg1) { + // 当用户点击"确定"按钮时,调用回调接口 if (mOnDateTimeSetListener != null) { mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); } diff --git a/src/net/micode/notes/ui/DropdownMenu.java b/src/net/micode/notes/ui/DropdownMenu.java index 613dc74..5925a2a 100644 --- a/src/net/micode/notes/ui/DropdownMenu.java +++ b/src/net/micode/notes/ui/DropdownMenu.java @@ -26,30 +26,60 @@ import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; import net.micode.notes.R; +/** + * 下拉菜单组件 - 封装PopupMenu实现按钮点击弹出菜单功能 + * + * 提供简洁的API来创建和管理下拉菜单,支持自定义菜单项和点击事件处理 + * 主要用于在按钮点击时显示上下文相关的操作选项 + */ public class DropdownMenu { + // 触发下拉菜单的按钮 private Button mButton; + // 系统弹出菜单组件 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(); } }); } + /** + * 设置菜单项点击监听器 + * + * @param listener 实现了OnMenuItemClickListener接口的监听器 + */ public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { if (mPopupMenu != null) { mPopupMenu.setOnMenuItemClickListener(listener); } } + /** + * 根据ID查找菜单项 + * + * @param id 菜单项ID + * @return 对应的MenuItem对象,如果未找到则返回null + */ public MenuItem findItem(int id) { return mMenu.findItem(id); diff --git a/src/net/micode/notes/ui/FoldersListAdapter.java b/src/net/micode/notes/ui/FoldersListAdapter.java index f77b8ae..4226870 100644 --- a/src/net/micode/notes/ui/FoldersListAdapter.java +++ b/src/net/micode/notes/ui/FoldersListAdapter.java @@ -27,50 +27,104 @@ import android.widget.TextView; import net.micode.notes.R; import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.NoteColumns; +/** + * 文件夹列表适配器 - 用于在ListView中显示便签文件夹列表 + * + * 继承自CursorAdapter,从数据库游标获取文件夹数据并绑定到视图 + * 支持特殊处理根文件夹,将其显示为"上级文件夹" + */ public class FoldersListAdapter extends CursorAdapter { + // 查询文件夹数据时需要获取的列 public static final String [] PROJECTION = { - NoteColumns.ID, - NoteColumns.SNIPPET + NoteColumns.ID, // 文件夹ID + NoteColumns.SNIPPET // 文件夹名称 }; + // 投影列索引常量,提高代码可读性 public static final int ID_COLUMN = 0; public static final int NAME_COLUMN = 1; + /** + * 构造函数,初始化文件夹列表适配器 + * + * @param context 应用上下文 + * @param c 包含文件夹数据的游标 + */ public FoldersListAdapter(Context context, Cursor c) { super(context, c); // TODO Auto-generated constructor stub } + /** + * 创建新的文件夹列表项视图 + * + * @param context 应用上下文 + * @param cursor 当前数据游标 + * @param parent 父视图组 + * @return 新创建的FolderListItem视图 + */ @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return new FolderListItem(context); } + /** + * 将游标数据绑定到已有的视图 + * + * @param view 要绑定数据的视图 + * @param context 应用上下文 + * @param 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); + // 绑定文件夹名称到视图 ((FolderListItem) view).bind(folderName); } } + /** + * 获取指定位置的文件夹名称 + * + * @param context 应用上下文 + * @param position 列表位置 + * @return 文件夹名称,如果是根文件夹则返回"上级文件夹" + */ 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; + /** + * 构造函数,初始化文件夹列表项视图 + * + * @param context 应用上下文 + */ public FolderListItem(Context context) { super(context); + // 加载布局资源 inflate(context, R.layout.folder_list_item, this); + // 获取文件夹名称文本视图引用 mName = (TextView) findViewById(R.id.tv_folder_name); } + /** + * 绑定文件夹名称到视图 + * + * @param name 要显示的文件夹名称 + */ public void bind(String name) { mName.setText(name);