|
|
|
|
@ -60,7 +60,6 @@ import net.micode.notes.viewmodel.NotesListViewModel;
|
|
|
|
|
|
|
|
|
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
|
|
|
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -85,6 +84,7 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
private static final int REQUEST_CODE_OPEN_NODE = 102;
|
|
|
|
|
private static final int REQUEST_CODE_NEW_NODE = 103;
|
|
|
|
|
private static final int REQUEST_CODE_CHECK_PASSWORD_FOR_OPEN = 104;
|
|
|
|
|
private static final int REQUEST_CODE_CHECK_PASSWORD_FOR_LOCK = 105;
|
|
|
|
|
|
|
|
|
|
private NotesListViewModel viewModel;
|
|
|
|
|
private ListView notesListView;
|
|
|
|
|
@ -99,7 +99,11 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
private boolean isMultiSelectMode = false;
|
|
|
|
|
|
|
|
|
|
// 待打开的受保护笔记
|
|
|
|
|
private NotesRepository.NoteInfo mPendingNoteToOpen;
|
|
|
|
|
private long mPendingNodeIdToOpen = -1;
|
|
|
|
|
private int mPendingNodeTypeToOpen = -1;
|
|
|
|
|
private static final String KEY_PENDING_NODE_ID = "pending_node_id";
|
|
|
|
|
private static final String KEY_PENDING_NODE_TYPE = "pending_node_type";
|
|
|
|
|
private static final String KEY_CURRENT_FOLDER_ID = "current_folder_id";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 活动创建时的初始化方法
|
|
|
|
|
@ -128,10 +132,36 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
initViewModel();
|
|
|
|
|
|
|
|
|
|
// 恢复 pending 状态和当前文件夹
|
|
|
|
|
if (savedInstanceState != null) {
|
|
|
|
|
mPendingNodeIdToOpen = savedInstanceState.getLong(KEY_PENDING_NODE_ID, -1);
|
|
|
|
|
mPendingNodeTypeToOpen = savedInstanceState.getInt(KEY_PENDING_NODE_TYPE, -1);
|
|
|
|
|
|
|
|
|
|
long savedFolderId = savedInstanceState.getLong(KEY_CURRENT_FOLDER_ID, Notes.ID_ROOT_FOLDER);
|
|
|
|
|
if (savedFolderId != Notes.ID_ROOT_FOLDER) {
|
|
|
|
|
viewModel.setCurrentFolderId(savedFolderId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Restored pending node: " + mPendingNodeIdToOpen + ", type: " + mPendingNodeTypeToOpen + ", folder: " + savedFolderId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initViews();
|
|
|
|
|
observeViewModel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 保存 Activity 状态
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected void onSaveInstanceState(Bundle outState) {
|
|
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
|
outState.putLong(KEY_PENDING_NODE_ID, mPendingNodeIdToOpen);
|
|
|
|
|
outState.putInt(KEY_PENDING_NODE_TYPE, mPendingNodeTypeToOpen);
|
|
|
|
|
outState.putLong(KEY_CURRENT_FOLDER_ID, viewModel.getCurrentFolderId());
|
|
|
|
|
Log.d(TAG, "Saved pending node: " + mPendingNodeIdToOpen + ", current folder: " + viewModel.getCurrentFolderId());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 活动启动时的回调方法
|
|
|
|
|
* <p>
|
|
|
|
|
@ -141,12 +171,10 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
@Override
|
|
|
|
|
protected void onStart() {
|
|
|
|
|
super.onStart();
|
|
|
|
|
viewModel.loadNotes(Notes.ID_ROOT_FOLDER);
|
|
|
|
|
// 刷新当前文件夹的笔记,而不是强制加载根目录
|
|
|
|
|
// 这样可以保证从 PasswordActivity 返回时,如果 onStart 先执行,不会重置为根目录
|
|
|
|
|
viewModel.refreshNotes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 初始化ViewModel
|
|
|
|
|
*/
|
|
|
|
|
private void initViewModel() {
|
|
|
|
|
NotesRepository repository = new NotesRepository(getContentResolver());
|
|
|
|
|
viewModel = new ViewModelProvider(this,
|
|
|
|
|
@ -244,6 +272,15 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
// 普通模式
|
|
|
|
|
if (note.type == Notes.TYPE_FOLDER) {
|
|
|
|
|
// 文件夹:进入该文件夹
|
|
|
|
|
// 检查隐私锁
|
|
|
|
|
if (note.isLocked && SecurityManager.getInstance(this).isPasswordSet()) {
|
|
|
|
|
mPendingNodeIdToOpen = note.getId();
|
|
|
|
|
mPendingNodeTypeToOpen = note.type;
|
|
|
|
|
Intent intent = new Intent(this, PasswordActivity.class);
|
|
|
|
|
intent.setAction(PasswordActivity.ACTION_CHECK_PASSWORD);
|
|
|
|
|
startActivityForResult(intent, REQUEST_CODE_CHECK_PASSWORD_FOR_OPEN);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
viewModel.enterFolder(note.getId());
|
|
|
|
|
} else {
|
|
|
|
|
// 便签:打开编辑器
|
|
|
|
|
@ -307,26 +344,6 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 观察多选模式状态
|
|
|
|
|
viewModel.getIsMultiSelectMode().observe(this, new Observer<Boolean>() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onChanged(Boolean isMultiSelectMode) {
|
|
|
|
|
if (isMultiSelectMode != null && !isMultiSelectMode) {
|
|
|
|
|
// 退出多选模式
|
|
|
|
|
NotesListActivity.this.isMultiSelectMode = false;
|
|
|
|
|
updateToolbarForNormalMode();
|
|
|
|
|
if (adapter != null) {
|
|
|
|
|
adapter.setSelectedIds(new HashSet<>());
|
|
|
|
|
adapter.notifyDataSetChanged();
|
|
|
|
|
}
|
|
|
|
|
// 显示FAB按钮
|
|
|
|
|
if (fabNewNote != null) {
|
|
|
|
|
fabNewNote.setVisibility(View.VISIBLE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -398,6 +415,16 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
* 打开笔记编辑器
|
|
|
|
|
*/
|
|
|
|
|
private void openNoteEditor(NotesRepository.NoteInfo note) {
|
|
|
|
|
// 检查隐私锁
|
|
|
|
|
if (note.isLocked && SecurityManager.getInstance(this).isPasswordSet()) {
|
|
|
|
|
mPendingNodeIdToOpen = note.getId();
|
|
|
|
|
mPendingNodeTypeToOpen = note.type;
|
|
|
|
|
Intent intent = new Intent(this, PasswordActivity.class);
|
|
|
|
|
intent.setAction(PasswordActivity.ACTION_CHECK_PASSWORD);
|
|
|
|
|
startActivityForResult(intent, REQUEST_CODE_CHECK_PASSWORD_FOR_OPEN);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Intent intent = new Intent(this, NoteEditActivity.class);
|
|
|
|
|
intent.setAction(Intent.ACTION_VIEW);
|
|
|
|
|
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, note.getParentId());
|
|
|
|
|
@ -449,6 +476,15 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
showTrashItemDialog(note);
|
|
|
|
|
} else if (note.type == Notes.TYPE_FOLDER) {
|
|
|
|
|
// 文件夹:进入该文件夹
|
|
|
|
|
// 检查隐私锁
|
|
|
|
|
if (note.isLocked && SecurityManager.getInstance(this).isPasswordSet()) {
|
|
|
|
|
mPendingNodeIdToOpen = note.getId();
|
|
|
|
|
mPendingNodeTypeToOpen = note.type;
|
|
|
|
|
Intent intent = new Intent(this, PasswordActivity.class);
|
|
|
|
|
intent.setAction(PasswordActivity.ACTION_CHECK_PASSWORD);
|
|
|
|
|
startActivityForResult(intent, REQUEST_CODE_CHECK_PASSWORD_FOR_OPEN);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Log.d(TAG, "Folder clicked, entering folder: " + note.getId());
|
|
|
|
|
viewModel.enterFolder(note.getId());
|
|
|
|
|
} else {
|
|
|
|
|
@ -532,7 +568,6 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
*/
|
|
|
|
|
private void enterMultiSelectMode() {
|
|
|
|
|
isMultiSelectMode = true;
|
|
|
|
|
viewModel.enterMultiSelectMode();
|
|
|
|
|
// 隐藏FAB按钮
|
|
|
|
|
if (fabNewNote != null) {
|
|
|
|
|
fabNewNote.setVisibility(View.GONE);
|
|
|
|
|
@ -546,12 +581,12 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
*/
|
|
|
|
|
private void exitMultiSelectMode() {
|
|
|
|
|
isMultiSelectMode = false;
|
|
|
|
|
viewModel.exitMultiSelectMode();
|
|
|
|
|
// 显示FAB按钮
|
|
|
|
|
if (fabNewNote != null) {
|
|
|
|
|
fabNewNote.setVisibility(View.VISIBLE);
|
|
|
|
|
}
|
|
|
|
|
// 清除选中状态
|
|
|
|
|
viewModel.clearSelection();
|
|
|
|
|
if (adapter != null) {
|
|
|
|
|
adapter.setSelectedIds(new java.util.HashSet<>());
|
|
|
|
|
adapter.notifyDataSetChanged();
|
|
|
|
|
@ -683,15 +718,33 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
if (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE) {
|
|
|
|
|
viewModel.refreshNotes();
|
|
|
|
|
} else if (requestCode == REQUEST_CODE_CHECK_PASSWORD_FOR_OPEN) {
|
|
|
|
|
if (mPendingNoteToOpen != null) {
|
|
|
|
|
if (mPendingNoteToOpen.type == Notes.TYPE_FOLDER) {
|
|
|
|
|
viewModel.enterFolder(mPendingNoteToOpen.getId());
|
|
|
|
|
if (mPendingNodeIdToOpen != -1) {
|
|
|
|
|
if (mPendingNodeTypeToOpen == Notes.TYPE_FOLDER) {
|
|
|
|
|
// 文件夹密码验证通过,直接进入文件夹
|
|
|
|
|
Log.d(TAG, "Password verified for folder: " + mPendingNodeIdToOpen);
|
|
|
|
|
viewModel.enterFolder(mPendingNodeIdToOpen);
|
|
|
|
|
} else {
|
|
|
|
|
openNoteEditor(mPendingNoteToOpen);
|
|
|
|
|
// 密码验证通过,直接打开编辑器
|
|
|
|
|
Intent intent = new Intent(this, NoteEditActivity.class);
|
|
|
|
|
intent.setAction(Intent.ACTION_VIEW);
|
|
|
|
|
intent.putExtra(Intent.EXTRA_UID, mPendingNodeIdToOpen);
|
|
|
|
|
startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
|
|
|
|
|
}
|
|
|
|
|
mPendingNoteToOpen = null;
|
|
|
|
|
mPendingNodeIdToOpen = -1;
|
|
|
|
|
mPendingNodeTypeToOpen = -1;
|
|
|
|
|
}
|
|
|
|
|
} else if (requestCode == REQUEST_CODE_CHECK_PASSWORD_FOR_LOCK) {
|
|
|
|
|
// 加锁/解锁密码验证通过
|
|
|
|
|
boolean wasLocked = viewModel.isAllSelectedLocked();
|
|
|
|
|
viewModel.toggleSelectedNotesLock();
|
|
|
|
|
String lockMsg = wasLocked ? getString(R.string.menu_unlock) + "成功" : getString(R.string.menu_lock) + "成功";
|
|
|
|
|
Toast.makeText(this, lockMsg, Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
} else if (requestCode == REQUEST_CODE_CHECK_PASSWORD_FOR_LOCK) {
|
|
|
|
|
// 加锁/解锁密码验证失败或取消
|
|
|
|
|
boolean wasLocked = viewModel.isAllSelectedLocked();
|
|
|
|
|
String lockMsg = wasLocked ? getString(R.string.menu_unlock) + "失败" : getString(R.string.menu_lock) + "失败";
|
|
|
|
|
Toast.makeText(this, lockMsg, Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -748,10 +801,10 @@ public class NotesListActivity extends AppCompatActivity
|
|
|
|
|
case R.id.multi_select_lock:
|
|
|
|
|
// 检查是否设置了隐私密码
|
|
|
|
|
if (SecurityManager.getInstance(this).isPasswordSet()) {
|
|
|
|
|
boolean wasLocked = viewModel.isAllSelectedLocked();
|
|
|
|
|
viewModel.toggleSelectedNotesLock();
|
|
|
|
|
String lockMsg = wasLocked ? getString(R.string.menu_unlock) + "成功" : getString(R.string.menu_lock) + "成功";
|
|
|
|
|
Toast.makeText(this, lockMsg, Toast.LENGTH_SHORT).show();
|
|
|
|
|
// 需要先验证密码
|
|
|
|
|
Intent intent = new Intent(this, PasswordActivity.class);
|
|
|
|
|
intent.setAction(PasswordActivity.ACTION_CHECK_PASSWORD);
|
|
|
|
|
startActivityForResult(intent, REQUEST_CODE_CHECK_PASSWORD_FOR_LOCK);
|
|
|
|
|
} else {
|
|
|
|
|
Toast.makeText(this, "请先在设置中设置隐私密码", Toast.LENGTH_SHORT).show();
|
|
|
|
|
// 跳转到设置密码界面
|
|
|
|
|
|