|
|
|
@ -62,12 +62,16 @@ import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
//主界面,一进入就是这个界面
|
|
|
|
|
/**
|
|
|
|
|
* @author k
|
|
|
|
|
*
|
|
|
|
|
* @Package: net.micode.notes.ui
|
|
|
|
|
* @ClassName: NotesListActivity
|
|
|
|
|
* @Description:
|
|
|
|
|
* @Author: WUSHUXIAN
|
|
|
|
|
* @CreateDate: 2023/12/20 23:02
|
|
|
|
|
* @Version: 1.0
|
|
|
|
|
*/
|
|
|
|
|
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { //没有用特定的标签加注释。。。感觉没有什么用
|
|
|
|
|
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;
|
|
|
|
@ -78,7 +82,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
|
|
|
|
|
private static final int MENU_FOLDER_CHANGE_NAME = 2;
|
|
|
|
|
|
|
|
|
|
private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; //单行超过80个字符
|
|
|
|
|
private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction";
|
|
|
|
|
|
|
|
|
|
private enum ListEditState {
|
|
|
|
|
NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER
|
|
|
|
@ -123,51 +127,68 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
|
|
|
|
|
private final static int REQUEST_CODE_OPEN_NODE = 102;
|
|
|
|
|
private final static int REQUEST_CODE_NEW_NODE = 103;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
// 创建类
|
|
|
|
|
protected void onCreate(final Bundle savedInstanceState) { //需要是final类型 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。
|
|
|
|
|
// final类不能被继承,没有子类,final类中的方法默认是final的。
|
|
|
|
|
//final方法不能被子类的方法覆盖,但可以被继承。
|
|
|
|
|
//final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
|
|
|
|
|
//final不能用于修饰构造方法。
|
|
|
|
|
/**
|
|
|
|
|
* @method onCreate
|
|
|
|
|
* @description 需要是final类型 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。
|
|
|
|
|
* final类不能被继承,没有子类,final类中的方法默认是final的。
|
|
|
|
|
* final方法不能被子类的方法覆盖,但可以被继承。
|
|
|
|
|
* final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
|
|
|
|
|
* final不能用于修饰构造方法。
|
|
|
|
|
* @date: 2023/12/20 23:13
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param void
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
protected void onCreate(final Bundle savedInstanceState) {
|
|
|
|
|
super.onCreate(savedInstanceState); // 调用父类的onCreate函数
|
|
|
|
|
setContentView(R.layout.note_list);
|
|
|
|
|
initResources();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert an introduction when user firstly use this application
|
|
|
|
|
*/
|
|
|
|
|
setAppInfoFromRawRes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
// 返回一些子模块完成的数据交给主Activity处理
|
|
|
|
|
/**
|
|
|
|
|
* @method onActivityResult
|
|
|
|
|
* @description: 返回一些子模块完成的数据交给主Activity处理
|
|
|
|
|
* 参数:
|
|
|
|
|
* requestCode:
|
|
|
|
|
* resultCode:
|
|
|
|
|
* data;
|
|
|
|
|
* @date: 2023/12/20 23:26
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param void
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
|
|
|
// 结果值 和 要求值 符合要求
|
|
|
|
|
if (resultCode == RESULT_OK
|
|
|
|
|
&& (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) {
|
|
|
|
|
mNotesListAdapter.changeCursor(null);
|
|
|
|
|
} else {
|
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
|
// 调用 Activity 的onActivityResult()
|
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);// 调用 Activity 的onActivityResult()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method setAppInfoFromRawRes
|
|
|
|
|
* @description:
|
|
|
|
|
* @date: 2023/12/20 23:24
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private void setAppInfoFromRawRes() {
|
|
|
|
|
// Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。
|
|
|
|
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
|
|
|
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);// Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。
|
|
|
|
|
if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
InputStream in = null;
|
|
|
|
|
try {
|
|
|
|
|
// 把资源文件放到应用程序的/raw/raw下,那么就可以在应用中使用getResources获取资源后,
|
|
|
|
|
// 以openRawResource方法(不带后缀的资源文件名)打开这个文件。
|
|
|
|
|
// 把资源文件放到应用程序的/raw/raw下,那么就可以在应用中使用getResources获取资源后,以openRawResource方法(不带后缀的资源文件名)打开这个文件。
|
|
|
|
|
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);
|
|
|
|
@ -210,8 +231,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
super.onStart();
|
|
|
|
|
startAsyncNotesListQuery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化资源
|
|
|
|
|
/**
|
|
|
|
|
* @method initResources
|
|
|
|
|
* @description 初始化资源
|
|
|
|
|
* @date: 2023/12/20 23:09
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private void initResources() {
|
|
|
|
|
mContentResolver = this.getContentResolver(); // 获取应用程序的数据,得到类似数据表的东西
|
|
|
|
|
mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
|
|
|
|
@ -236,7 +263,15 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
mModeCallBack = new ModeCallback();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener
|
|
|
|
|
//
|
|
|
|
|
/**
|
|
|
|
|
* @Package: net.micode.notes.ui
|
|
|
|
|
* @ClassName: ModeCallback
|
|
|
|
|
* @Description: 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener
|
|
|
|
|
* @Author: WUSHUXIAN
|
|
|
|
|
* @CreateDate: 2023/12/20 23:37
|
|
|
|
|
* @Version: 1.0
|
|
|
|
|
*/
|
|
|
|
|
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
|
|
|
|
|
private DropdownMenu mDropDownMenu;
|
|
|
|
|
private ActionMode mActionMode;
|
|
|
|
@ -274,8 +309,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
});
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新菜单
|
|
|
|
|
/**
|
|
|
|
|
* @method updateMenu
|
|
|
|
|
* @description 更新菜单
|
|
|
|
|
* @date: 2023/12/16 23:36
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private void updateMenu() {
|
|
|
|
|
int selectedCount = mNotesListAdapter.getSelectedCount();
|
|
|
|
|
// Update dropdown menu
|
|
|
|
@ -318,7 +359,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
mNotesListAdapter.setCheckedItem(position, checked);
|
|
|
|
|
updateMenu();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onMenuItemClick
|
|
|
|
|
* @description:
|
|
|
|
|
* @date: 2023/12/20 23:39
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public boolean onMenuItemClick(MenuItem item) {
|
|
|
|
|
if (mNotesListAdapter.getSelectedCount() == 0) {
|
|
|
|
|
Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none),
|
|
|
|
@ -350,9 +398,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//接口的实现
|
|
|
|
|
private class NewNoteOnTouchListener implements OnTouchListener {
|
|
|
|
|
|
|
|
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
|
|
|
switch (event.getAction()) {
|
|
|
|
|
case MotionEvent.ACTION_DOWN: {
|
|
|
|
@ -412,22 +459,44 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method startAsyncNotesListQuery
|
|
|
|
|
* @description: 启动异步Notes列表查询
|
|
|
|
|
* @date: 2023/12/20 23:45
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private void startAsyncNotesListQuery() {
|
|
|
|
|
String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION
|
|
|
|
|
: NORMAL_SELECTION;
|
|
|
|
|
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)
|
|
|
|
|
}, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
|
|
|
|
|
Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] {String.valueOf(mCurrentFolderId)},
|
|
|
|
|
NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @Package: net.micode.notes.ui
|
|
|
|
|
* @ClassName: BackgroundQueryHandler
|
|
|
|
|
* @Description: 对AsyncQueryHandler的拓展,背景查询处理
|
|
|
|
|
* @Author: WUSHUXIAN
|
|
|
|
|
* @CreateDate: 2023/12/21 0:01
|
|
|
|
|
* @Version: 1.0
|
|
|
|
|
*/
|
|
|
|
|
private final class BackgroundQueryHandler extends AsyncQueryHandler {
|
|
|
|
|
public BackgroundQueryHandler(ContentResolver contentResolver) {
|
|
|
|
|
super(contentResolver);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
/**
|
|
|
|
|
* @method onQueryComplete
|
|
|
|
|
* @description: 在异步查询完成时调用。
|
|
|
|
|
* @date: 2023/12/20 23:56
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param token 标识查询的令牌
|
|
|
|
|
* @param cookie 传入的cookie对象
|
|
|
|
|
* @param cursor 保存查询结果的光标
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
|
|
|
|
switch (token) {
|
|
|
|
|
case FOLDER_NOTE_LIST_QUERY_TOKEN:
|
|
|
|
@ -473,22 +542,29 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId);
|
|
|
|
|
this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method batchDelete
|
|
|
|
|
* @description: 删除便签操作
|
|
|
|
|
* @date: 2023/12/21 0:14
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
@SuppressLint("StaticFieldLeak")
|
|
|
|
|
private void batchDelete() {
|
|
|
|
|
new AsyncTask<Void, Void, HashSet<AppWidgetAttribute>>() {
|
|
|
|
|
protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) {
|
|
|
|
|
HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget();
|
|
|
|
|
//如果没有同步,直接删除
|
|
|
|
|
if (!isSyncMode()) {
|
|
|
|
|
// if not synced, delete notes directly
|
|
|
|
|
if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter
|
|
|
|
|
.getSelectedItemIds())) {
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Delete notes error, should not happens");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// in sync mode, we'll move the deleted note into the trash
|
|
|
|
|
// folder
|
|
|
|
|
}
|
|
|
|
|
//已同步,将删除的便签移到垃圾桶
|
|
|
|
|
else {
|
|
|
|
|
if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
|
|
|
|
|
.getSelectedItemIds(), Notes.ID_TRASH_FOLER)) {
|
|
|
|
|
Log.e(TAG, "Move notes to trash folder error, should not happens");
|
|
|
|
@ -511,7 +587,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}.execute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method deleteFolder
|
|
|
|
|
* @description: 删除文件夹
|
|
|
|
|
* @date: 2023/12/21 0:32
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param folderId 文件标识
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
private void deleteFolder(long folderId) {
|
|
|
|
|
if (folderId == Notes.ID_ROOT_FOLDER) {
|
|
|
|
|
Log.e(TAG, "Wrong folder id, should not happen " + folderId);
|
|
|
|
@ -580,7 +663,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
|
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method showCreateOrModifyFolderDialog
|
|
|
|
|
* @description: 创建或者修改文件夹时显示对话框
|
|
|
|
|
* @date: 2023/12/21 0:39
|
|
|
|
|
* @author: WUSHUXIAN
|
|
|
|
|
* @param create
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
private void showCreateOrModifyFolderDialog(final boolean create) {
|
|
|
|
|
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
|
|
|
|
@ -638,13 +728,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
dialog.dismiss();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//如果便签名是空的,则禁用确认按钮
|
|
|
|
|
if (TextUtils.isEmpty(etName.getText())) {
|
|
|
|
|
positive.setEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* When the name edit text is null, disable the positive button
|
|
|
|
|
*/
|
|
|
|
|
etName.addTextChangedListener(new TextWatcher() {
|
|
|
|
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
@ -671,7 +758,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
* 按返回键时根据情况更改类中的数据
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void onBackPressed() { switch (mState) {
|
|
|
|
|
public void onBackPressed() {
|
|
|
|
|
switch (mState) {
|
|
|
|
|
case SUB_FOLDER:
|
|
|
|
|
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
|
|
|
|
|
mState = ListEditState.NOTE_LIST;
|
|
|
|
|