diff --git a/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java b/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java index 85723be..f2f10f1 100644 --- a/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java +++ b/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java @@ -41,24 +41,27 @@ import java.io.IOException; public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { - private long mNoteId; - private String mSnippet; + private long mNoteId; //文本在数据库存储中的ID号 + private String mSnippet; //闹钟提示时出现的文本片段 private static final int SNIPPET_PREW_MAX_LEN = 60; MediaPlayer mPlayer; @Override protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); + + // Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的 + // saveInstanceState是用来保存Activity的状态的 + super.onCreate(savedInstanceState); // 能从onCreate的参数saveInstanceState中获得状态数据 + requestWindowFeature(Window.FEATURE_NO_TITLE); // 显示无标题界面 final Window win = getWindow(); win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); if (!isScreenOn()) { - win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON - | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON - | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); + win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON // 保持窗体点亮 + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON // 将窗体点亮 + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON // 允许窗体点亮时锁屏 + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); // 在手机锁屏后如果到了闹钟提示时间,点亮屏幕 } Intent intent = getIntent(); @@ -66,9 +69,12 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD try { mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); + // 根据ID从数据库中获取标签的内容; + // getContentResolver() 是实现数据共享,实例存储 mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) : mSnippet; + // 判断标签片段是否达到符合长度 } catch (IllegalArgumentException e) { e.printStackTrace(); return; @@ -76,21 +82,23 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD mPlayer = new MediaPlayer(); if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { - showActionDialog(); - playAlarmSound(); + showActionDialog(); // 弹出对话框 + playAlarmSound(); // 闹钟提示音激发 } else { finish(); } } private boolean isScreenOn() { + // 调用系统函数判断屏幕是否锁屏 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); return pm.isScreenOn(); } private void playAlarmSound() { + // 播放闹钟声音 Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); - + // 得到系统的闹钟铃声 int silentModeStreams = Settings.System.getInt(getContentResolver(), Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); @@ -100,10 +108,10 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); } try { - mPlayer.setDataSource(this, url); - mPlayer.prepare(); - mPlayer.setLooping(true); - mPlayer.start(); + mPlayer.setDataSource(this, url); // 设置声音数据来源 + mPlayer.prepare(); // 同步 + mPlayer.setLooping(true); // 是否循环播放 + mPlayer.start(); //播放 } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -121,12 +129,16 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD private void showActionDialog() { AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle(R.string.app_name); - dialog.setMessage(mSnippet); + // AlertDialog的构造方法全部是Protected的 + // 所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。 + // 要创建一个AlertDialog,就要用到AlertDialog.Builder中的create()方法 + dialog.setTitle(R.string.app_name); // 为对话框设置标题 + dialog.setMessage(mSnippet); // 为对话框设置内容 dialog.setPositiveButton(R.string.notealert_ok, this); if (isScreenOn()) { dialog.setNegativeButton(R.string.notealert_enter, this); } + // 添加按钮 dialog.show().setOnDismissListener(this); } @@ -151,7 +163,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD private void stopAlarmSound() { if (mPlayer != null) { mPlayer.stop(); - mPlayer.release(); + mPlayer.release(); // 释放MediaPlayer对象 mPlayer = null; } } diff --git a/app/src/main/java/net/micode/notes/ui/AlarmInitReceiver.java b/app/src/main/java/net/micode/notes/ui/AlarmInitReceiver.java index f221202..6904af8 100644 --- a/app/src/main/java/net/micode/notes/ui/AlarmInitReceiver.java +++ b/app/src/main/java/net/micode/notes/ui/AlarmInitReceiver.java @@ -34,19 +34,19 @@ public class AlarmInitReceiver extends BroadcastReceiver { NoteColumns.ID, NoteColumns.ALERTED_DATE }; - + //对数据库的操作,调用标签ID和闹钟时间 private static final int COLUMN_ID = 0; private static final int COLUMN_ALERTED_DATE = 1; @Override public void onReceive(Context context, Intent intent) { - long currentDate = System.currentTimeMillis(); + long currentDate = System.currentTimeMillis(); // 一个自1970年1月1日0时起到当前的毫秒数 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 { @@ -61,5 +61,7 @@ public class AlarmInitReceiver extends BroadcastReceiver { } c.close(); } + // 对于闹钟机制的启动,通常需要上面的几个步骤 + // 这里就是根据数据库里的闹钟时间创建一个闹钟机制 } } diff --git a/app/src/main/java/net/micode/notes/ui/AlarmReceiver.java b/app/src/main/java/net/micode/notes/ui/AlarmReceiver.java index 54e503b..117ed47 100644 --- a/app/src/main/java/net/micode/notes/ui/AlarmReceiver.java +++ b/app/src/main/java/net/micode/notes/ui/AlarmReceiver.java @@ -23,8 +23,9 @@ import android.content.Intent; public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - intent.setClass(context, AlarmAlertActivity.class); + intent.setClass(context, AlarmAlertActivity.class); // 启动AlarmAlertActivity intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); + // activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈 } } diff --git a/app/src/main/java/net/micode/notes/ui/DateTimePicker.java b/app/src/main/java/net/micode/notes/ui/DateTimePicker.java index 496b0cd..48b8aa4 100644 --- a/app/src/main/java/net/micode/notes/ui/DateTimePicker.java +++ b/app/src/main/java/net/micode/notes/ui/DateTimePicker.java @@ -29,7 +29,8 @@ import android.widget.FrameLayout; import android.widget.NumberPicker; public class DateTimePicker extends FrameLayout { - + // FrameLayout是布局模板之一 + // 所有的子元素全部在屏幕的右上方 private static final boolean DEFAULT_ENABLE_STATE = true; private static final int HOURS_IN_HALF_DAY = 12; @@ -46,11 +47,14 @@ public class DateTimePicker extends FrameLayout { private static final int AMPM_SPINNER_MIN_VAL = 0; private static final int AMPM_SPINNER_MAX_VAL = 1; + // 初始化控件 private final NumberPicker mDateSpinner; private final NumberPicker mHourSpinner; private final NumberPicker mMinuteSpinner; private final NumberPicker mAmPmSpinner; - private Calendar mDate; + // 4个数字选择器,设置闹钟时需要选择的变量(即日期、时、分、上午或者下午) + + private Calendar mDate; // 操作时间 private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; @@ -67,8 +71,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(); + updateDateControl(); // 同步日期 onDateTimeChanged(); } }; @@ -166,13 +171,14 @@ public class DateTimePicker extends FrameLayout { public DateTimePicker(Context context) { this(context, System.currentTimeMillis()); } - + // 通过对数据库的访问,获取当前的系统时间 public DateTimePicker(Context context, long date) { this(context, date, DateFormat.is24HourFormat(context)); } + // 得到一个1970至今的秒数,并使用 DateFormat 将其变得有意义 public DateTimePicker(Context context, long date, boolean is24HourView) { - super(context); + super(context); // 获取系统时间 mDate = Calendar.getInstance(); mInitialising = true; mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY; diff --git a/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java b/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java index 2c47ba4..e5524c3 100644 --- a/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java +++ b/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java @@ -33,8 +33,10 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener private Calendar mDate = Calendar.getInstance(); private boolean mIs24HourView; - private OnDateTimeSetListener mOnDateTimeSetListener; + private OnDateTimeSetListener mOnDateTimeSetListener; // 时间日期滚动选择控件 private DateTimePicker mDateTimePicker; + // 控件一般用于让用户可以从日期列表中选择单个值 + // 两个部分:一个下拉列表,一个用于选择日期的 public interface OnDateTimeSetListener { void OnDateTimeSet(AlertDialog dialog, long date); @@ -42,8 +44,8 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener public DateTimePickerDialog(Context context, long date) { super(context); - mDateTimePicker = new DateTimePicker(context); - setView(mDateTimePicker); + 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) { @@ -52,6 +54,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); mDate.set(Calendar.MINUTE, minute); + // 将视图中的各选项设置为系统当前时间 updateTitle(mDate.getTimeInMillis()); } }); @@ -71,6 +74,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { mOnDateTimeSetListener = callBack; } + //将时间日期滚动选择控件实例化 private void updateTitle(long date) { int flag = @@ -80,8 +84,10 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); } + // android开发中常见日期管理工具类(API)——DateUtils:按照上下午显示时间 public void onClick(DialogInterface arg0, int arg1) { + // arg0: 接收到点击事件的对话框 arg1: 该对话框上的按钮 if (mOnDateTimeSetListener != null) { mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); } diff --git a/app/src/main/java/net/micode/notes/ui/DropdownMenu.java b/app/src/main/java/net/micode/notes/ui/DropdownMenu.java index 613dc74..11f90e9 100644 --- a/app/src/main/java/net/micode/notes/ui/DropdownMenu.java +++ b/app/src/main/java/net/micode/notes/ui/DropdownMenu.java @@ -29,15 +29,16 @@ import net.micode.notes.R; public class DropdownMenu { private Button mButton; - private PopupMenu mPopupMenu; + private PopupMenu mPopupMenu; // 下拉菜单 private Menu mMenu; public DropdownMenu(Context context, Button button, int menuId) { mButton = button; - mButton.setBackgroundResource(R.drawable.dropdown_icon); + mButton.setBackgroundResource(R.drawable.dropdown_icon); // 设置这个view的背景 mPopupMenu = new PopupMenu(context, mButton); mMenu = mPopupMenu.getMenu(); mPopupMenu.getMenuInflater().inflate(menuId, mMenu); + // 实例化Menu目录下的Menu布局文件,并根据ID来确认menu的内容选项 mButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { mPopupMenu.show(); @@ -49,13 +50,16 @@ public class DropdownMenu { if (mPopupMenu != null) { mPopupMenu.setOnMenuItemClickListener(listener); } + // 设置菜单的监听 } public MenuItem findItem(int id) { return mMenu.findItem(id); } + // 对于菜单选项的初始化,根据索引搜索菜单需要的选项 public void setTitle(CharSequence title) { mButton.setText(title); } + // 布局文件,设置标题 } diff --git a/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java b/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java index 96b77da..0553070 100644 --- a/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java +++ b/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java @@ -30,10 +30,12 @@ import net.micode.notes.data.Notes.NoteColumns; public class FoldersListAdapter extends CursorAdapter { + // 主要作用是便签数据库和用户的交互 + // 这里就是用folder(文件夹)的形式展现给用户 public static final String [] PROJECTION = { NoteColumns.ID, NoteColumns.SNIPPET - }; + }; // 调用数据库中便签的ID和片段 public static final int ID_COLUMN = 0; public static final int NAME_COLUMN = 1; @@ -45,8 +47,10 @@ public class FoldersListAdapter extends CursorAdapter { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { + // ViewGroup是容器 return new FolderListItem(context); } + // 创建一个文件夹,对于各文件夹中子标签的初始化 @Override public void bindView(View view, Context context, Cursor cursor) { @@ -56,19 +60,21 @@ public class FoldersListAdapter extends CursorAdapter { ((FolderListItem) view).bind(folderName); } } + // 将各个布局文件绑定起来 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); } + // 根据数据库中标签的ID得到标签的各项内容 private class FolderListItem extends LinearLayout { private TextView mName; public FolderListItem(Context context) { super(context); - inflate(context, R.layout.folder_list_item, this); + inflate(context, R.layout.folder_list_item, this); // 根据布局文件的名字等信息将其找出来 mName = (TextView) findViewById(R.id.tv_folder_name); } diff --git a/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java index 862883b..9620e4c 100644 --- a/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java +++ b/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java @@ -74,6 +74,7 @@ import java.util.regex.Pattern; public class NoteEditActivity extends Activity implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener { + // 该类主要是针对标签的编辑 private class HeadViewHolder { public TextView tvModified; @@ -122,20 +123,20 @@ public class NoteEditActivity extends Activity implements OnClickListener, private HeadViewHolder mNoteHeaderHolder; - private View mHeadViewPanel; + private View mHeadViewPanel; // 界面对表头操作 - private View mNoteBgColorSelector; + private View mNoteBgColorSelector; // 对背景颜色的操作 - private View mFontSizeSelector; + private View mFontSizeSelector; // 对标签字体的操作 - private EditText mNoteEditor; + private EditText mNoteEditor; // 编辑文本控件操作 - private View mNoteEditorPanel; + private View mNoteEditorPanel; // 文本编辑的控制板 private WorkingNote mWorkingNote; - private SharedPreferences mSharedPrefs; - private int mFontSizeId; + private SharedPreferences mSharedPrefs; // 基于XML文件存储key-value键值对数据 + private int mFontSizeId; // 字体大小 private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; @@ -144,7 +145,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, public static final String TAG_CHECKED = String.valueOf('\u221A'); public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); - private LinearLayout mEditTextList; + private LinearLayout mEditTextList; // 线性布局 private String mUserQuery; private Pattern mPattern; @@ -177,6 +178,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } Log.d(TAG, "Restoring from killed activity"); } + // 为防止内存不足时程序的终止,在这里有一个保存现场的函数 } private boolean initActivityState(Intent intent) { @@ -196,7 +198,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); } - + // 根据键值查找ID if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { Intent jump = new Intent(this, NotesListActivity.class); startActivity(jump); @@ -213,7 +215,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); // 软键盘输入模式 } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { // New note long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); @@ -294,8 +296,8 @@ public class NoteEditActivity extends Activity implements OnClickListener, */ showAlertHeader(); } - private void showAlertHeader() { + // 设置闹钟的显示 if (mWorkingNote.hasClockAlert()) { long time = System.currentTimeMillis(); if (time > mWorkingNote.getAlertDate()) { @@ -303,9 +305,10 @@ public class NoteEditActivity extends Activity implements OnClickListener, } else { mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); - } + } // 如果系统时间大于了闹钟设置的时间,那么闹钟失效 mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); + //显示闹钟开启的图标 } else { mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); @@ -328,6 +331,8 @@ public class NoteEditActivity extends Activity implements OnClickListener, */ if (!mWorkingNote.existInDatabase()) { saveNote(); + // 在创建一个新的标签时,先在数据库中匹配 + // 如果不存在,那么先在数据库中存储 } outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); @@ -335,21 +340,24 @@ public class NoteEditActivity extends Activity implements OnClickListener, @Override public boolean dispatchTouchEvent(MotionEvent ev) { + // MotionEvent是对屏幕触控的传递机制 if (mNoteBgColorSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mNoteBgColorSelector, ev)) { mNoteBgColorSelector.setVisibility(View.GONE); return true; } - + // 颜色选择器在屏幕上可见 if (mFontSizeSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mFontSizeSelector, ev)) { mFontSizeSelector.setVisibility(View.GONE); return true; } + // 字体大小选择器在屏幕上可见 return super.dispatchTouchEvent(ev); } private boolean inRangeOfView(View view, MotionEvent ev) { + // 对屏幕触控的坐标进行操作 int []location = new int[2]; view.getLocationOnScreen(location); int x = location[0]; @@ -377,13 +385,13 @@ public class NoteEditActivity extends Activity implements OnClickListener, for (int id : sBgSelectorBtnsMap.keySet()) { ImageView iv = (ImageView) findViewById(id); iv.setOnClickListener(this); - } + } // 对标签各项属性内容的初始化 mFontSizeSelector = findViewById(R.id.font_size_selector); 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); /** @@ -406,6 +414,9 @@ public class NoteEditActivity extends Activity implements OnClickListener, clearSettingState(); } + /** + * 同步桌面小工具 + */ private void updateWidget() { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { @@ -430,7 +441,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, 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); @@ -480,6 +491,9 @@ public class NoteEditActivity extends Activity implements OnClickListener, mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); } + /** + * 对选择菜单的准备 + */ @Override public boolean onPrepareOptionsMenu(Menu menu) { if (isFinishing()) { @@ -505,12 +519,17 @@ public class NoteEditActivity extends Activity implements OnClickListener, return true; } + /** + * 动态改变菜单选项内容 + */ @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); + // 根据菜单的id来编剧相关项目 if (itemId == R.id.menu_new_note) { - createNewNote(); + createNewNote(); // 创建标签 } else if (itemId == R.id.menu_delete) { + // 删除便签 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); @@ -523,104 +542,136 @@ public class NoteEditActivity extends Activity implements OnClickListener, } }); builder.setNegativeButton(android.R.string.cancel, null); + // 创建关于删除操作的对话框 builder.show(); } else if (itemId == R.id.menu_font_size) { + // 字体大小的编辑 mFontSizeSelector.setVisibility(View.VISIBLE); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); } else if (itemId == R.id.menu_list_mode) { + // 选择列表模式 mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ? TextNote.MODE_CHECK_LIST : 0); } else if (itemId == R.id.menu_share) { + // 菜单共享 getWorkingText(); - sendTo(this, mWorkingNote.getContent()); + sendTo(this, mWorkingNote.getContent()); // 将运行文本发送到遍历的本文内 } else if (itemId == R.id.menu_send_to_desktop) { + // 发送到桌面 sendToDesktop(); } else if (itemId == R.id.menu_alert) { + // 创建提醒器 setReminder(); } else if (itemId == R.id.menu_delete_remind) { + // 删除日期提醒 mWorkingNote.setAlertDate(0, false); } return true; } + /** + * 建立事件提醒器 + */ private void setReminder() { DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis()); + // 建立修改时间日期的对话框 d.setOnDateTimeSetListener(new OnDateTimeSetListener() { public void OnDateTimeSet(AlertDialog dialog, long date) { mWorkingNote.setAlertDate(date , true); + // 选择提醒的日期 } - }); + }); // 建立时间日期的监听器 d.show(); } /** + * 共享便签 * Share note to apps that support {@link Intent#ACTION_SEND} action * and {@text/plain} type */ private void sendTo(Context context, String info) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_TEXT, info); - intent.setType("text/plain"); - context.startActivity(intent); + Intent intent = new Intent(Intent.ACTION_SEND); // 建立intent链接选项 + intent.putExtra(Intent.EXTRA_TEXT, info); // 将需要传递的便签信息放入text文件中 + intent.setType("text/plain"); // 编辑连接器的类型 + context.startActivity(intent); // 在Activity中进行链接 } + /** + * 创建一个新的便签 + */ private void createNewNote() { // Firstly, save current editing notes - saveNote(); + saveNote(); // 保存当前便签 // For safety, start a new NoteEditActivity finish(); - Intent intent = new Intent(this, NoteEditActivity.class); - intent.setAction(Intent.ACTION_INSERT_OR_EDIT); + Intent intent = new Intent(this, NoteEditActivity.class); // 设置链接器 + intent.setAction(Intent.ACTION_INSERT_OR_EDIT); // 该活动定义为创建或编辑 intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); + // 将运行便签的id添加到INTENT_EXTRA_FOLDER_ID标记中 startActivity(intent); } + /** + * 删除当前便签 + */ private void deleteCurrentNote() { if (mWorkingNote.existInDatabase()) { + // 假如当前运行的便签内存有数据 HashSet ids = new HashSet(); long id = mWorkingNote.getNoteId(); if (id != Notes.ID_ROOT_FOLDER) { - ids.add(id); + ids.add(id); // 如果不是头文件夹建立一个hash表把便签id存起来 } else { Log.d(TAG, "Wrong note id, should not happen"); } if (!isSyncMode()) { + // 在非同步模式情况下进行删除操作 if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { Log.e(TAG, "Delete Note error"); } } else { + //同步模式中移动至垃圾文件夹的操作 if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { Log.e(TAG, "Move notes to trash folder error, should not happens"); } } } - mWorkingNote.markDeleted(true); + mWorkingNote.markDeleted(true); // 将这些标签的删除标记置为true } + /** + * 判断是否为同步模式 + */ private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } + /** + * 设置提醒时间 + */ public void onClockAlertChanged(long date, boolean set) { /** * User could set clock to an unsaved note, so before setting the * alert clock, we should save the note first */ if (!mWorkingNote.existInDatabase()) { - saveNote(); + saveNote(); // 首先保存已有的便签 } if (mWorkingNote.getNoteId() > 0) { Intent intent = new Intent(this, AlarmReceiver.class); intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); + // 若有有运行的便签就是建立一个链接器将标签id都存在uri中 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); + // 设置提醒管理器 showAlertHeader(); if(!set) { alarmManager.cancel(pendingIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); } + // 如果用户设置了时间,就通过提醒管理器设置一个监听事项 } else { /** * There is the condition that user has input nothing (the note is @@ -632,22 +683,29 @@ public class NoteEditActivity extends Activity implements OnClickListener, } } + /** + * Widget发生改变的所触发的事件 + */ public void onWidgetChanged() { updateWidget(); } + /** + * 删除编辑文本框所触发的事件 + */ public void onEditTextDelete(int index, String text) { int childCount = mEditTextList.getChildCount(); if (childCount == 1) { return; } - + // 没有编辑框的话直接返回 for (int i = index + 1; i < childCount; i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) - .setIndex(i - 1); + .setIndex(i - 1); // 通过id把编辑框存在便签编辑框中 } mEditTextList.removeViewAt(index); + // 删除特定位置的视图 NoteEditText edit = null; if(index == 0) { edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( @@ -656,12 +714,16 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( R.id.et_edit_text); } + // 通过id把编辑框存在空的NoteEditText中 int length = edit.length(); edit.append(text); - edit.requestFocus(); - edit.setSelection(length); + edit.requestFocus(); // 请求优先完成该此 编辑 + edit.setSelection(length); // 定位到length位置处的条目 } + /** + * 进入编辑文本框所触发的事件 + */ public void onEditTextEnter(int index, String text) { /** * Should not happen, check for debug @@ -672,53 +734,68 @@ public class NoteEditActivity extends Activity implements OnClickListener, View view = getListItem(text, index); mEditTextList.addView(view, index); + // 建立一个新的视图并添加到编辑文本框内 NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - edit.requestFocus(); - edit.setSelection(0); + edit.requestFocus(); // 请求优先操作 + edit.setSelection(0); // 定位到起始位置 for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) - .setIndex(i); + .setIndex(i); // 遍历子文本框并设置对应对下标 } } + /** + * 切换至列表模式 + */ private void switchToListMode(String text) { mEditTextList.removeAllViews(); String[] items = text.split("\n"); - int index = 0; + int index = 0; // 清空所有视图,初始化下标 for (String item : items) { if(!TextUtils.isEmpty(item)) { mEditTextList.addView(getListItem(item, index)); index++; + // 遍历所有文本单元并添加到文本框中 } } mEditTextList.addView(getListItem("", index)); mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); + // 优先请求此操作 - mNoteEditor.setVisibility(View.GONE); - mEditTextList.setVisibility(View.VISIBLE); + mNoteEditor.setVisibility(View.GONE); // 便签编辑器不可见 + mEditTextList.setVisibility(View.VISIBLE); // 将文本编辑框置为可见 } + /** + * 获取高亮效果的反馈情况 + */ private Spannable getHighlightQueryResult(String fullText, String userQuery) { SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); + // 新建一个效果选项 if (!TextUtils.isEmpty(userQuery)) { - mPattern = Pattern.compile(userQuery); - Matcher m = mPattern.matcher(fullText); + mPattern = Pattern.compile(userQuery); // 将用户的询问进行解析 + Matcher m = mPattern.matcher(fullText); // 建立一个状态机检查Pattern并进行匹配 int start = 0; while (m.find(start)) { spannable.setSpan( new BackgroundColorSpan(this.getResources().getColor( R.color.user_query_highlight)), m.start(), m.end(), - Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - start = m.end(); + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); // 设置背景颜色 + start = m.end(); // 更新起始位置 } } return spannable; } + /** + * 获取列表项 + */ private View getListItem(String item, int index) { View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); + // 创建一个视图 final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); + // 创建一个文本编辑框并设置可见性 CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @@ -728,13 +805,15 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); } } - }); + }); // 建立一个打钩框并设置监听器 if (item.startsWith(TAG_CHECKED)) { + // 选择勾选 cb.setChecked(true); edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); item = item.substring(TAG_CHECKED.length(), item.length()).trim(); } else if (item.startsWith(TAG_UNCHECKED)) { + // 选择不勾选 cb.setChecked(false); edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); @@ -743,9 +822,13 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit.setOnTextViewChangeListener(this); edit.setIndex(index); edit.setText(getHighlightQueryResult(item, mUserQuery)); + // 运行编辑框的监听器对该行为作出反应,并设置下标及文本内容 return view; } + /** + * 便签内容发生改变所 触发的事件 + */ public void onTextChange(int index, boolean hasText) { if (index >= mEditTextList.getChildCount()) { Log.e(TAG, "Wrong index, should not happen"); @@ -756,45 +839,59 @@ public class NoteEditActivity extends Activity implements OnClickListener, } else { mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE); } + // 如果内容不为空则将其子编辑框可见性置为可见,否则不可见 } - + /** + * 检查模式和列表模式的切换 + */ public void onCheckListModeChanged(int oldMode, int newMode) { if (newMode == TextNote.MODE_CHECK_LIST) { - switchToListMode(mNoteEditor.getText().toString()); + switchToListMode(mNoteEditor.getText().toString()); // 检查模式切换到列表模式 } else { if (!getWorkingText()) { mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", "")); } + // 若是获取到文本就改变其检查标记 mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); mEditTextList.setVisibility(View.GONE); - mNoteEditor.setVisibility(View.VISIBLE); + mNoteEditor.setVisibility(View.VISIBLE); // 修改文本编辑器的内容和可见性 } } + /** + * 设置勾选选项表并返回是否勾选的标记 + */ private boolean getWorkingText() { - boolean hasChecked = false; + boolean hasChecked = false; // 初始化check标记 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); // 创建可变字符串 for (int i = 0; i < mEditTextList.getChildCount(); i++) { - View view = mEditTextList.getChildAt(i); + View view = mEditTextList.getChildAt(i); // 遍历所有子编辑框的视图 NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); if (!TextUtils.isEmpty(edit.getText())) { + // 若文本不为空 if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { + // 该选项框已打钩 sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); - hasChecked = true; + hasChecked = true; // 扩展字符串为已打钩并把标记置true } else { sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n"); + // 扩展字符串添加未打钩 } } } - mWorkingNote.setWorkingText(sb.toString()); + mWorkingNote.setWorkingText(sb.toString()); // 利用编辑好的字符串设置运行便签的内容 } else { mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); + // 若不是该模式直接用编辑器中的内容设置运行中标签的内容 } return hasChecked; } + /** + * 保存便签 + */ private boolean saveNote() { getWorkingText(); boolean saved = mWorkingNote.saveNote(); @@ -806,11 +903,15 @@ public class NoteEditActivity extends Activity implements OnClickListener, * new node requires to the top of the list. This code * {@link #RESULT_OK} is used to identify the create/edit state */ + // 2种情况,一是创建后保存,二是修改后保存 setResult(RESULT_OK); } return saved; } + /** + * 将便签发送至桌面 + */ private void sendToDesktop() { /** * Before send message to home, we should make sure that current @@ -818,21 +919,23 @@ public class NoteEditActivity extends Activity implements OnClickListener, * save it */ if (!mWorkingNote.existInDatabase()) { - saveNote(); + saveNote(); //若不存在数据也就是新的标签就保存起来先 } if (mWorkingNote.getNoteId() > 0) { Intent sender = new Intent(); Intent shortcutIntent = new Intent(this, NoteEditActivity.class); - shortcutIntent.setAction(Intent.ACTION_VIEW); + // 建立发送到桌面的连接器 + shortcutIntent.setAction(Intent.ACTION_VIEW); // 链接为一个视图 shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, makeShortcutIconTitle(mWorkingNote.getContent())); sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app)); - sender.putExtra("duplicate", true); + sender.putExtra("duplicate", true); // 将便签的相关信息都添加到要发送的文件里 sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); + //设置sneder的行为是发送 showToast(R.string.info_note_enter_desktop); sendBroadcast(sender); } else { @@ -846,17 +949,27 @@ public class NoteEditActivity extends Activity implements OnClickListener, } } + /** + * 编辑小图标的标题 + */ private String makeShortcutIconTitle(String content) { content = content.replace(TAG_CHECKED, ""); content = content.replace(TAG_UNCHECKED, ""); return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, SHORTCUT_ICON_TITLE_MAX_LEN) : content; + // 直接设置为content中的内容并返回,有勾选和未勾选2种 } + /** + * 显示提示的视图 + */ private void showToast(int resId) { showToast(resId, Toast.LENGTH_SHORT); } + /** + * 持续显示提示的视图 + */ private void showToast(int resId, int duration) { Toast.makeText(this, resId, duration).show(); } diff --git a/app/src/main/java/net/micode/notes/ui/NoteItemData.java b/app/src/main/java/net/micode/notes/ui/NoteItemData.java index 0f5a878..8477826 100644 --- a/app/src/main/java/net/micode/notes/ui/NoteItemData.java +++ b/app/src/main/java/net/micode/notes/ui/NoteItemData.java @@ -76,6 +76,11 @@ public class NoteItemData { private boolean mIsOneNoteFollowingFolder; private boolean mIsMultiNotesFollowingFolder; + /** + * 初始化NoteItemData,主要利用光标cursor获取的东西 + * @param context + * @param cursor + */ public NoteItemData(Context context, Cursor cursor) { mId = cursor.getLong(ID_COLUMN); mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); @@ -92,6 +97,7 @@ public class NoteItemData { mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); + // 初始化电话号码的信息 mPhoneNumber = ""; if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); @@ -109,21 +115,31 @@ public class NoteItemData { checkPostion(cursor); } + /** + * 根据鼠标的位置设置标记,和位置 + * @param cursor + */ private void checkPostion(Cursor cursor) { mIsLastItem = cursor.isLast() ? true : false; mIsFirstItem = cursor.isFirst() ? true : false; mIsOnlyOneItem = (cursor.getCount() == 1); + // 初始化“多重子文件”“单一子文件”2个标记 mIsMultiNotesFollowingFolder = false; mIsOneNoteFollowingFolder = false; - + // 主要是设置上诉2标记 if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { + // 若是note格式并且不是第一个元素 int position = cursor.getPosition(); if (cursor.moveToPrevious()) { + // 获取光标位置后看上一行 if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { + // 若光标满足系统或note格式 if (cursor.getCount() > (position + 1)) { + // 若是数据行数大于但前位置+1则设置成正确 mIsMultiNotesFollowingFolder = true; } else { + // 单一文件夹标记为true mIsOneNoteFollowingFolder = true; } } @@ -214,6 +230,10 @@ public class NoteItemData { return (mAlertDate > 0); } + /** + * 若数据父id为保存至文件夹模式的id且满足电话号码单元不为空 + * @return boolean + */ public boolean isCallRecord() { return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); } diff --git a/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java b/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java index 51c9cb9..8f0319c 100644 --- a/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java +++ b/app/src/main/java/net/micode/notes/ui/NotesListAdapter.java @@ -35,51 +35,82 @@ public class NotesListAdapter extends CursorAdapter { private static final String TAG = "NotesListAdapter"; private Context mContext; private HashMap mSelectedIndex; - private int mNotesCount; - private boolean mChoiceMode; + private int mNotesCount; // 便签数 + private boolean mChoiceMode; // 选择模式标记 + /** + * 桌面widget的属性,包括编号和类型 + */ public static class AppWidgetAttribute { public int widgetId; public int widgetType; }; + /** + * 初始化便签链接器 + * @param context + */ public NotesListAdapter(Context context) { - super(context, null); + super(context, null); // 父类对象置空 + // 新建选项下标的hash表 mSelectedIndex = new HashMap(); mContext = context; mNotesCount = 0; } + /** + * 新建一个视图来存储光标所指向的数据 + * @return View 视图 + */ @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return new NotesListItem(context); } + /** + * 将已经存在的视图和鼠标指向的数据进行捆绑 + */ @Override public void bindView(View view, Context context, Cursor cursor) { if (view instanceof NotesListItem) { + // 若view是NotesListItem的一个实例 NoteItemData itemData = new NoteItemData(context, cursor); ((NotesListItem) view).bind(context, itemData, mChoiceMode, isSelectedItem(cursor.getPosition())); + // 则新建一个项目选项并且用bind跟将view和鼠标,内容,便签数据捆绑在一起 } } + /** + * 设置勾选框 + */ public void setCheckedItem(final int position, final boolean checked) { - mSelectedIndex.put(position, checked); - notifyDataSetChanged(); + mSelectedIndex.put(position, checked); // 根据定位和是否勾选设置下标 + notifyDataSetChanged(); // 在修改后刷新activity } + /** + * 判断单选按钮是否勾选 + * @return boolean + */ public boolean isInChoiceMode() { return mChoiceMode; } + /** + * 设置单项选项框 + */ public void setChoiceMode(boolean mode) { mSelectedIndex.clear(); mChoiceMode = mode; } + /** + * 选择全部选项 + */ public void selectAll(boolean checked) { - Cursor cursor = getCursor(); + Cursor cursor = getCursor(); // 获取光标位置 + // 遍历所有光标可用的位置在判断为便签类型之后勾选单项框 for (int i = 0; i < getCount(); i++) { if (cursor.moveToPosition(i)) { if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { @@ -89,6 +120,9 @@ public class NotesListAdapter extends CursorAdapter { } } + /** + * 建立选择项的下标列表 + */ public HashSet getSelectedItemIds() { HashSet itemSet = new HashSet(); for (Integer position : mSelectedIndex.keySet()) { @@ -105,12 +139,16 @@ public class NotesListAdapter extends CursorAdapter { return itemSet; } + /** + * 建立桌面Widget的选项表 + */ public HashSet getSelectedWidget() { HashSet itemSet = new HashSet(); for (Integer position : mSelectedIndex.keySet()) { if (mSelectedIndex.get(position) == true) { Cursor c = (Cursor) getItem(position); if (c != null) { + // 光标位置可用的话就建立新的Widget属性并编辑下标和类型,最后添加到选项集中 AppWidgetAttribute widget = new AppWidgetAttribute(); NoteItemData item = new NoteItemData(mContext, c); widget.widgetId = item.getWidgetId(); @@ -128,13 +166,16 @@ public class NotesListAdapter extends CursorAdapter { return itemSet; } + /** + * 获取选项个数 + */ public int getSelectedCount() { - Collection values = mSelectedIndex.values(); + Collection values = mSelectedIndex.values(); // 首先获取选项下标的值 if (null == values) { return 0; } Iterator iter = values.iterator(); - int count = 0; + int count = 0; // 初始化叠加器 while (iter.hasNext()) { if (true == iter.next()) { count++; @@ -143,11 +184,18 @@ 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; @@ -155,25 +203,34 @@ public class NotesListAdapter extends CursorAdapter { return mSelectedIndex.get(position); } + /** + * 在activity内容发生局部变动的时候回调该函数计算便签的数量 + */ @Override protected void onContentChanged() { super.onContentChanged(); calcNotesCount(); } + /** + * 在activity光标发生局部变动的时候回调该函数计算便签的数量 + */ @Override public void changeCursor(Cursor cursor) { super.changeCursor(cursor); calcNotesCount(); } + /** + * 计算便签数量 + */ private void calcNotesCount() { mNotesCount = 0; for (int i = 0; i < getCount(); i++) { Cursor c = (Cursor) getItem(i); if (c != null) { if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { - mNotesCount++; + mNotesCount++; // 若该位置不为空并且文本类型为便签就+1 } } else { Log.e(TAG, "Invalid cursor"); diff --git a/app/src/main/java/net/micode/notes/ui/NotesListItem.java b/app/src/main/java/net/micode/notes/ui/NotesListItem.java index 1221e80..eb2ea9b 100644 --- a/app/src/main/java/net/micode/notes/ui/NotesListItem.java +++ b/app/src/main/java/net/micode/notes/ui/NotesListItem.java @@ -29,18 +29,23 @@ import net.micode.notes.data.Notes; import net.micode.notes.tool.DataUtils; import net.micode.notes.tool.ResourceParser.NoteItemBgResources; - +// 创建便签列表项目选项 public class NotesListItem extends LinearLayout { - private ImageView mAlert; - private TextView mTitle; - private TextView mTime; - private TextView mCallName; - private NoteItemData mItemData; - private CheckBox mCheckBox; + private ImageView mAlert; // 闹钟图片 + private TextView mTitle; // 标题 + private TextView mTime; // 时间 + private TextView mCallName; // 昵称 + private NoteItemData mItemData; // 标签数据 + private CheckBox mCheckBox; // 打钩框 + /** + * 初始化基本信息 + * @param context + */ public NotesListItem(Context context) { super(context); - inflate(context, R.layout.note_item, this); + inflate(context, R.layout.note_item, this); // 将一个xml中定义的布局控件找出来 + // findViewById用于从contentView中查找指定ID的View,转换出来的形式根据需要而定 mAlert = (ImageView) findViewById(R.id.iv_alert_icon); mTitle = (TextView) findViewById(R.id.tv_title); mTime = (TextView) findViewById(R.id.tv_time); @@ -48,15 +53,19 @@ public class NotesListItem extends LinearLayout { mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); } + /** + * 根据data的属性对各个控件的属性的控制 + */ public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { if (choiceMode && data.getType() == Notes.TYPE_NOTE) { - mCheckBox.setVisibility(View.VISIBLE); - mCheckBox.setChecked(checked); + mCheckBox.setVisibility(View.VISIBLE); // 设置可见行为可见 + mCheckBox.setChecked(checked); // 格子打钩 } else { mCheckBox.setVisibility(View.GONE); } mItemData = data; + // 设置控件属性,一共三种情况,由data的id和父id是否与保存到文件夹的id一致来决定 if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { mCallName.setVisibility(View.GONE); mAlert.setVisibility(View.VISIBLE); @@ -69,8 +78,9 @@ public class NotesListItem extends LinearLayout { mCallName.setText(data.getCallName()); mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem); mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + // 关于闹钟的设置 if (data.hasAlert()) { - mAlert.setImageResource(R.drawable.clock); + mAlert.setImageResource(R.drawable.clock); // 图片来源的设置 mAlert.setVisibility(View.VISIBLE); } else { mAlert.setVisibility(View.GONE); @@ -94,17 +104,25 @@ public class NotesListItem extends LinearLayout { } } } + // 设置内容,获取相关时间,从data里编辑的日期中获取 mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); setBackground(data); } + /** + * 根据data的文件属性来设置背景 + * @param data + */ private void setBackground(NoteItemData data) { int id = data.getBgColorId(); if (data.getType() == Notes.TYPE_NOTE) { + // 若是note型文件,则4种情况,对于4种不同情况的背景来源 if (data.isSingle() || data.isOneFollowingFolder()) { + // 单个数据并且只有一个子文件夹 setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); } else if (data.isLast()) { + // 是最后一个数据 setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); } else if (data.isFirst() || data.isMultiFollowingFolder()) { setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); @@ -112,6 +130,7 @@ public class NotesListItem extends LinearLayout { setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); } } else { + // 若不是note直接调用文件夹的背景来源 setBackgroundResource(NoteItemBgResources.getFolderBgRes()); } } diff --git a/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java b/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java index 07c5f7e..0bee969 100644 --- a/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java +++ b/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java @@ -47,47 +47,57 @@ import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.gtask.remote.GTaskSyncService; - +/** + * 在小米便签中主要实现的是对背景颜色和字体大小的数据储存 + */ public class NotesPreferenceActivity extends PreferenceActivity { - public static final String PREFERENCE_NAME = "notes_preferences"; + public static final String PREFERENCE_NAME = "notes_preferences"; // 优先名 - public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name"; + public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name"; // 同步账号 - public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time"; + public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time"; // 同步时间 public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear"; - private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; + private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; // 同步密码 - private static final String AUTHORITIES_FILTER_KEY = "authorities"; + private static final String AUTHORITIES_FILTER_KEY = "authorities"; // 本地密码 - private PreferenceCategory mAccountCategory; + private PreferenceCategory mAccountCategory; // 账户分组 - private GTaskReceiver mReceiver; + private GTaskReceiver mReceiver; // 同步任务接收器 - private Account[] mOriAccounts; + private Account[] mOriAccounts; // 账户 - private boolean mHasAddedAccount; + private boolean mHasAddedAccount; // 账户的hash标记 + /** + * 创建一个activity,在函数里要完成所有的正常静态设置 + * @param icicle activity 当前的状态 + */ @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); /* using the app icon for navigation */ - getActionBar().setDisplayHomeAsUpEnabled(true); + getActionBar().setDisplayHomeAsUpEnabled(true); // 给左上角图标的左边加上一个返回的图标 - addPreferencesFromResource(R.xml.preferences); + addPreferencesFromResource(R.xml.preferences); // 添加xml来源并显示 xml mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); + // 根据同步账户关键码来初始化分组 mReceiver = new GTaskReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME); - registerReceiver(mReceiver, filter); + registerReceiver(mReceiver, filter); // 初始化同步组件 mOriAccounts = null; View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); - getListView().addHeaderView(header, null, true); + getListView().addHeaderView(header, null, true); // 在listview组件上方添加其他组件 } + /** + * activity交互功能的实现,用于接受用户的输入 + */ @Override protected void onResume() { super.onResume(); @@ -95,8 +105,10 @@ public class NotesPreferenceActivity extends PreferenceActivity { // need to set sync account automatically if user has added a new // account if (mHasAddedAccount) { - Account[] accounts = getGoogleAccounts(); + // 若用户新加了账户则自动设置同步账户 + Account[] accounts = getGoogleAccounts(); // 获取google同步账户 if (mOriAccounts != null && accounts.length > mOriAccounts.length) { + // 若原账户不为空且当前账户有增加 for (Account accountNew : accounts) { boolean found = false; for (Account accountOld : mOriAccounts) { @@ -107,42 +119,52 @@ public class NotesPreferenceActivity extends PreferenceActivity { } if (!found) { setSyncAccount(accountNew.name); + // 若是没有找到旧的账户,那么同步账号中就只添加新账户 break; } } } } - - refreshUI(); + refreshUI(); // 刷新标签界面 } + /** + * 销毁一个activity + */ @Override protected void onDestroy() { if (mReceiver != null) { - unregisterReceiver(mReceiver); + unregisterReceiver(mReceiver); // 注销接收器 } - super.onDestroy(); + super.onDestroy(); // 执行父类的销毁动作 } + /** + * 重新设置账户信息 + */ private void loadAccountPreference() { mAccountCategory.removeAll(); - - Preference accountPref = new Preference(this); + // 销毁所有的分组 + Preference accountPref = new Preference(this); // 建立首选项 final String defaultAccount = getSyncAccountName(this); accountPref.setTitle(getString(R.string.preferences_account_title)); accountPref.setSummary(getString(R.string.preferences_account_summary)); + // 设置首选项的大标题和小标题 accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { if (!GTaskSyncService.isSyncing()) { if (TextUtils.isEmpty(defaultAccount)) { // the first time to set account + // 若是第一次建立账户显示选择账户提示对话框 showSelectAccountAlertDialog(); } else { // if the account has already been set, we need to promp // user about the risk + // 若是已经建立则显示修改对话框并进行修改操作 showChangeAccountConfirmAlertDialog(); } } else { + // 若在没有同步的情况下,则在toast中显示不能修改 Toast.makeText(NotesPreferenceActivity.this, R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT) .show(); @@ -150,15 +172,19 @@ public class NotesPreferenceActivity extends PreferenceActivity { return true; } }); - + // 根据新建首选项编辑新的账户分组 mAccountCategory.addPreference(accountPref); } + /** + * 设置按键的状态和最后同步的时间 + */ private void loadSyncButton() { Button syncButton = (Button) findViewById(R.id.preference_sync_button); TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); - + // 获取同步按钮控件和最终同步时间的的窗口 // set button state + // 设置按钮的状态 if (GTaskSyncService.isSyncing()) { syncButton.setText(getString(R.string.preferences_button_sync_cancel)); syncButton.setOnClickListener(new View.OnClickListener() { @@ -166,6 +192,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { GTaskSyncService.cancelSync(NotesPreferenceActivity.this); } }); + // 设置按钮显示的文本为“取消同步”以及监听器 } else { syncButton.setText(getString(R.string.preferences_button_sync_immediately)); syncButton.setOnClickListener(new View.OnClickListener() { @@ -173,50 +200,64 @@ public class NotesPreferenceActivity extends PreferenceActivity { GTaskSyncService.startSync(NotesPreferenceActivity.this); } }); + // 若是不同步则设置按钮显示的文本为“立即同步”以及对应监听器 } syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); + // 设置按键可用还是不可用 - // set last sync time + // set last sync time 设置最终同步时间 if (GTaskSyncService.isSyncing()) { + // 若是在同步的情况下 lastSyncTimeView.setText(GTaskSyncService.getProgressString()); lastSyncTimeView.setVisibility(View.VISIBLE); + // 根据当前同步服务器设置时间显示框的文本以及可见性 } else { + // 若是非同步情况 long lastSyncTime = getLastSyncTime(this); if (lastSyncTime != 0) { lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time, DateFormat.format(getString(R.string.preferences_last_sync_time_format), lastSyncTime))); lastSyncTimeView.setVisibility(View.VISIBLE); + //则根据最后同步时间的信息来编辑时间显示框的文本内容和可见性 } else { + // 若时间为空直接设置为不可见状态 lastSyncTimeView.setVisibility(View.GONE); } } } + /** + * 刷新标签界面 + */ private void refreshUI() { loadAccountPreference(); loadSyncButton(); } + /** + * 显示账户选择的对话框并进行账户的设置 + */ private void showSelectAccountAlertDialog() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - + // 创建一个新的对话框 View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); titleTextView.setText(getString(R.string.preferences_dialog_select_account_title)); TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips)); - + // 设置标题以及子标题的内容 dialogBuilder.setCustomTitle(titleView); dialogBuilder.setPositiveButton(null, null); - + // 设置对话框的自定义标题,建立一个YES的按钮 Account[] accounts = getGoogleAccounts(); String defAccount = getSyncAccountName(this); - + // 获取同步账户信息 mOriAccounts = accounts; mHasAddedAccount = false; if (accounts.length > 0) { + // 若账户不为空 CharSequence[] items = new CharSequence[accounts.length]; final CharSequence[] itemMapping = items; int checkedItem = -1; @@ -224,57 +265,70 @@ public class NotesPreferenceActivity extends PreferenceActivity { for (Account account : accounts) { if (TextUtils.equals(account.name, defAccount)) { checkedItem = index; + // 在账户列表中查询到所需账户 } items[index++] = account.name; } dialogBuilder.setSingleChoiceItems(items, checkedItem, new DialogInterface.OnClickListener() { + // 在对话框建立一个单选的复选框 public void onClick(DialogInterface dialog, int which) { setSyncAccount(itemMapping[which].toString()); - dialog.dismiss(); + dialog.dismiss(); // 取消对话框 refreshUI(); } + // 设置点击后执行的事件,包括检录新同步账户和刷新标签界面 }); + // 建立对话框网络版的监听器 } View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null); dialogBuilder.setView(addAccountView); - + // 显示对话框 final AlertDialog dialog = dialogBuilder.show(); addAccountView.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - mHasAddedAccount = true; - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + mHasAddedAccount = true; // 将新加账户的hash置true + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); // 建立网络建立组件 intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] { "gmail-ls" }); - startActivityForResult(intent, -1); + startActivityForResult(intent, -1); // 跳回上一个选项 dialog.dismiss(); } }); + // 建立新加账户对话框的监听器 } + /** + * 显示账户选择对话框和相关账户操作 + */ private void showChangeAccountConfirmAlertDialog() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - + // 创建一个新的对话框 View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); titleTextView.setText(getString(R.string.preferences_dialog_change_account_title, getSyncAccountName(this))); TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg)); + // 根据同步修改的账户信息设置标题以及子标题的内容 dialogBuilder.setCustomTitle(titleView); - + // 设置对话框的自定义标题 CharSequence[] menuItemArray = new CharSequence[] { getString(R.string.preferences_menu_change_account), getString(R.string.preferences_menu_remove_account), getString(R.string.preferences_menu_cancel) - }; + }; //定义一些标记字符串 dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { + // 设置对话框要显示的一个list,用于显示几个命令时,即change,remove,cancel public void onClick(DialogInterface dialog, int which) { + // 按键功能,由which来决定 if (which == 0) { + // 进入账户选择对话框 showSelectAccountAlertDialog(); } else if (which == 1) { + // 删除账户并且跟新便签界面 removeSyncAccount(); refreshUI(); } @@ -283,23 +337,32 @@ public class NotesPreferenceActivity extends PreferenceActivity { dialogBuilder.show(); } + /** + * 获取谷歌账户 + */ private Account[] getGoogleAccounts() { AccountManager accountManager = AccountManager.get(this); return accountManager.getAccountsByType("com.google"); } + /** + * 设置同步账户 + * @param account 账号 + */ private void setSyncAccount(String account) { if (!getSyncAccountName(this).equals(account)) { + // 假如该账号不在同步账号列表中 SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); + SharedPreferences.Editor editor = settings.edit(); // 编辑共享的首选项 if (account != null) { editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); } else { editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } - editor.commit(); + // 将该账号加入到首选项中 + editor.commit(); // 提交修改的数据 - // clean up last sync time + // clean up last sync time 将最后同步时间清零 setLastSyncTime(this, 0); // clean up local gtask related info @@ -310,24 +373,28 @@ public class NotesPreferenceActivity extends PreferenceActivity { values.put(NoteColumns.SYNC_ID, 0); getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } - }).start(); + }).start(); // 重置当地同步任务的信息 Toast.makeText(NotesPreferenceActivity.this, getString(R.string.preferences_toast_success_set_accout, account), Toast.LENGTH_SHORT).show(); + // 将toast的文本信息置为“设置账户成功”并显示出来 } } + /** + * 删除同步账户 + */ private void removeSyncAccount() { SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); + SharedPreferences.Editor editor = settings.edit(); // 设置共享首选项 if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) { - editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); + editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); // 假如当前首选项中有账户就删除 } if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) { - editor.remove(PREFERENCE_LAST_SYNC_TIME); + editor.remove(PREFERENCE_LAST_SYNC_TIME); // 删除当前首选项中有账户时间 } - editor.commit(); + editor.commit(); // 提交更新后的数据 // clean up local gtask related info new Thread(new Runnable() { @@ -337,50 +404,76 @@ public class NotesPreferenceActivity extends PreferenceActivity { values.put(NoteColumns.SYNC_ID, 0); getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } - }).start(); + }).start(); // 重置当地同步任务的信息 } + /** + * 获取同步账户名称 + * @param context 共享的首选项里的信息 + * @return String 用户名 + */ public static String getSyncAccountName(Context context) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } + /** + * 设置最终同步的时间 + * @param context 共享的首选项里的信息 + * @param time 时间 + */ public static void setLastSyncTime(Context context, long time) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); + SharedPreferences.Editor editor = settings.edit(); // 从共享首选项中找到相关账户并获取其编辑器 editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); - editor.commit(); + editor.commit(); // 编辑最终同步时间并提交更新 } + /** + * 获取最终同步时间 + * @param context 共享的首选项里的信息 + * @return long + */ public static long getLastSyncTime(Context context) { SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); } + /** + * 接受同步信息 + */ private class GTaskReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { refreshUI(); if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { + // 获取随广播而来的Intent中的同步服务的数据 TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview); syncStatus.setText(intent .getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG)); + // 通过获取的数据在设置系统的状态 } } } + /** + * 处理菜单的选项 + * @param item MenuItem菜单选项 + * @return boolean + */ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { + // 根据选项的id选择,这里只有一个主页 case android.R.id.home: Intent intent = new Intent(this, NotesListActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); - return true; + return true; // 在主页情况下在创建连接组件intent,发出清空的信号并开始一个相应的activity default: return false; }