增加了多级文件夹,修补了文件夹不能增加便签的bug #21

Merged
pr9ixgmc2 merged 1 commits from cuijiaxiang_branch into master 4 weeks ago

@ -130,6 +130,29 @@ public class DataUtils {
return true;
}
// 检查目标ID是否是一个文件夹TYPE_FOLDER或TYPE_SYSTEM
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, folderId),
new String[] { NoteColumns.TYPE },
null,
null,
null);
boolean isFolder = false;
if (cursor != null) {
if (cursor.moveToFirst()) {
int type = cursor.getInt(0);
if (type == Notes.TYPE_FOLDER || type == Notes.TYPE_SYSTEM) {
isFolder = true;
}
}
cursor.close();
}
if (!isFolder) {
Log.d(TAG, "target id is not a folder: " + folderId);
return false;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) {
ContentProviderOperation.Builder builder = ContentProviderOperation

@ -115,10 +115,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
// 背景选项
private static final String[] BACKGROUND_OPTIONS = {
"高山流水", "风中树叶", "长河落日"
"高山流水", "风中树叶", "长河落日"
};
private static final int[] BACKGROUND_RESOURCES = {
R.drawable.background_mountain, R.drawable.background_leaves, R.drawable.background_sunset
R.drawable.background_mountain, R.drawable.background_leaves, R.drawable.background_sunset
};
private ListEditState mState;
@ -183,7 +183,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.note_list);
// 获取隐私空间ID
Intent intent = getIntent();
if (intent != null) {
@ -192,7 +192,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mCurrentPrivacySpaceId = "";
}
}
initResources();
initBackground();
@ -254,17 +254,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
protected Boolean doInBackground(Void... unused) {
HashSet<Long> ids = mNotesListAdapter.getSelectedItemIds();
for (Long id : ids) {
// 查询当前便签的置顶状态
// 查询当前项目的置顶状态
Cursor cursor = mContentResolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.IS_PINNED },
new String[] { NoteColumns.IS_PINNED, NoteColumns.TYPE },
NoteColumns.ID + "=?",
new String[] { String.valueOf(id) },
null);
if (cursor != null && cursor.moveToFirst()) {
boolean isPinned = cursor.getInt(0) > 0;
int type = cursor.getInt(1);
cursor.close();
// 更新置顶状态
// 更新置顶状态,支持笔记和文件夹
ContentValues values = new ContentValues();
values.put(NoteColumns.IS_PINNED, isPinned ? 0 : 1);
values.put(NoteColumns.PIN_PRIORITY, isPinned ? 0 : System.currentTimeMillis());
@ -403,7 +404,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
mState = ListEditState.NOTE_LIST;
mModeCallBack = new ModeCallback();
// 检查是否处于隐私空间中
updatePrivacySpaceUI();
@ -575,6 +576,15 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
if (tagsMenu != null) {
tagsMenu.setOnMenuItemClickListener(this);
}
// 确保移动菜单项在有文件夹时可见
if (mMoveMenu != null) {
if (DataUtils.getUserFolderCount(mContentResolver) == 0) {
mMoveMenu.setVisible(false);
} else {
mMoveMenu.setVisible(true);
mMoveMenu.setOnMenuItemClickListener(this);
}
}
mActionMode = mode;
mNotesListAdapter.setChoiceMode(true);
mNotesListView.setLongClickable(false);
@ -741,6 +751,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private String mSelectedTag = "";
private void startAsyncNotesListQuery() {
// 临时删除功能:输入"delete:1"删除ID为1的项目
if (!TextUtils.isEmpty(mSearchQuery) && mSearchQuery.equals("delete:1")) {
Log.d(TAG, "User requested to delete item with ID 1");
deleteItemById(1);
mSearchQuery = "";
return;
}
String selection;
String[] selectionArgs;
@ -961,6 +979,30 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}.execute();
}
/**
* ID
*/
private void deleteItemById(long itemId) {
// 直接更新项目的父ID为回收站绕过batchMoveToFolder的检查
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.LOCAL_MODIFIED, 1);
values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
int rows = mContentResolver.update(Notes.CONTENT_NOTE_URI, values,
NoteColumns.ID + "=?", new String[] { String.valueOf(itemId) });
if (rows > 0) {
Log.d(TAG, "Successfully moved item " + itemId + " to trash");
Toast.makeText(this, "项目已移至回收站", Toast.LENGTH_SHORT).show();
} else {
Log.e(TAG, "Failed to move item " + itemId + " to trash");
Toast.makeText(this, "删除失败,请重试", Toast.LENGTH_SHORT).show();
}
startAsyncNotesListQuery();
}
private void deleteFolder(long folderId) {
if (folderId == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Wrong folder id, should not happen " + folderId);
@ -1025,7 +1067,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
startAsyncNotesListQuery();
}
}
/**
* UI
*/
@ -1108,6 +1150,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
ContentValues values = new ContentValues();
values.put(NoteColumns.SNIPPET, name);
values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
values.put(NoteColumns.PARENT_ID, mCurrentFolderId);
mContentResolver.insert(Notes.CONTENT_NOTE_URI, values);
}
dialog.dismiss();
@ -1145,10 +1188,37 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
public void onBackPressed() {
switch (mState) {
case SUB_FOLDER:
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
mState = ListEditState.NOTE_LIST;
// 查询当前文件夹的父文件夹ID
Cursor cursor = mContentResolver.query(
Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.PARENT_ID, NoteColumns.SNIPPET },
NoteColumns.ID + "=?",
new String[] { String.valueOf(mCurrentFolderId) },
null
);
if (cursor != null && cursor.moveToFirst()) {
long parentId = cursor.getLong(0);
String folderName = cursor.getString(1);
cursor.close();
if (parentId == Notes.ID_ROOT_FOLDER) {
// 返回到根文件夹
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
mState = ListEditState.NOTE_LIST;
mTitleBar.setVisibility(View.GONE);
} else {
// 返回到上一级文件夹
mCurrentFolderId = parentId;
mState = ListEditState.SUB_FOLDER;
mTitleBar.setText(folderName);
mTitleBar.setVisibility(View.VISIBLE);
}
} else if (cursor != null) {
cursor.close();
}
startAsyncNotesListQuery();
mTitleBar.setVisibility(View.GONE);
break;
case CALL_RECORD_FOLDER:
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
@ -1367,7 +1437,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
if (view instanceof NotesListItem) {
NoteItemData item = ((NotesListItem) view).getItemData();
if (mNotesListAdapter.isInChoiceMode()) {
if (item.getType() == Notes.TYPE_NOTE) {
if (item.getType() == Notes.TYPE_NOTE || item.getType() == Notes.TYPE_FOLDER) {
position = position - mNotesListView.getHeaderViewsCount();
mModeCallBack.onItemCheckedStateChanged(null, position, id,
!mNotesListAdapter.isSelectedItem(position));
@ -1377,21 +1447,21 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
switch (mState) {
case NOTE_LIST:
case SUB_FOLDER:
if (item.getType() == Notes.TYPE_FOLDER
|| item.getType() == Notes.TYPE_SYSTEM) {
openFolder(item);
} else if (item.getType() == Notes.TYPE_NOTE) {
openNode(item);
} else {
Log.e(TAG, "Wrong note type in NOTE_LIST");
Log.e(TAG, "Wrong note type in NOTE_LIST or SUB_FOLDER");
}
break;
case SUB_FOLDER:
case CALL_RECORD_FOLDER:
if (item.getType() == Notes.TYPE_NOTE) {
openNode(item);
} else {
Log.e(TAG, "Wrong note type in SUB_FOLDER");
Log.e(TAG, "Wrong note type in CALL_RECORD_FOLDER");
}
break;
default:
@ -1403,30 +1473,34 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
private void startQueryDestinationFolders() {
String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?";
selection = (mState == ListEditState.NOTE_LIST) ? selection:
"(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")";
// 查询所有有效的文件夹,包括普通文件夹、系统文件夹和根文件夹
// 排除当前文件夹和回收站文件夹
String selection = "(" + NoteColumns.TYPE + "=? OR " + NoteColumns.TYPE + "=?) AND " + NoteColumns.ID + "<>? AND " + NoteColumns.ID + "<>?";
String[] selectionArgs = new String[] {
String.valueOf(Notes.TYPE_FOLDER),
String.valueOf(Notes.TYPE_SYSTEM),
String.valueOf(mCurrentFolderId),
String.valueOf(Notes.ID_TRASH_FOLER)
};
mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN,
null,
Notes.CONTENT_NOTE_URI,
FoldersListAdapter.PROJECTION,
selection,
new String[] {
String.valueOf(Notes.TYPE_FOLDER),
String.valueOf(Notes.ID_TRASH_FOLER),
String.valueOf(mCurrentFolderId)
},
selectionArgs,
NoteColumns.MODIFIED_DATE + " DESC");
}
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (view instanceof NotesListItem) {
mFocusNoteDataItem = ((NotesListItem) view).getItemData();
if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) {
Log.d(TAG, "Long click item: id=" + id + ", type=" + mFocusNoteDataItem.getType() + ", parentId=" + mFocusNoteDataItem.getParentId());
if ((mFocusNoteDataItem.getType() == Notes.TYPE_NOTE || mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) && !mNotesListAdapter.isInChoiceMode()) {
if (mNotesListView.startActionMode(mModeCallBack) != null) {
mModeCallBack.onItemCheckedStateChanged(null, position, id, true);
mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
} else {
Log.e(TAG, "startActionMode fails");
}
@ -1445,7 +1519,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
Cursor cursor = mContentResolver.query(
Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.TAGS },
NoteColumns.TAGS + " <> '' AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
NoteColumns.TAGS + " <> ''",
null,
NoteColumns.TAGS + " ASC"
);
@ -1562,7 +1636,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
Cursor cursor = mContentResolver.query(
Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.TAGS },
NoteColumns.TAGS + " <> '' AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
NoteColumns.TAGS + " <> '' AND (" + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE + " OR " + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + ")",
null,
NoteColumns.TAGS + " ASC"
);
@ -1622,14 +1696,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
mCurrentBackgroundType = sp.getString(PREFERENCE_BACKGROUND + "_type", BACKGROUND_TYPE_DEFAULT);
mCurrentBackgroundPath = sp.getString(PREFERENCE_BACKGROUND + "_path", "");
if (BACKGROUND_TYPE_DEFAULT.equals(mCurrentBackgroundType)) {
int backgroundIndex = sp.getInt(PREFERENCE_BACKGROUND + "_index", 0);
if (backgroundIndex >= 0 && backgroundIndex < BACKGROUND_RESOURCES.length) {
mCurrentBackgroundResource = BACKGROUND_RESOURCES[backgroundIndex];
}
}
// 更新背景
updateBackground();
}
@ -1641,7 +1715,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
if (mBackgroundContainer == null) {
return;
}
try {
if (BACKGROUND_TYPE_DEFAULT.equals(mCurrentBackgroundType)) {
// 使用默认背景
@ -1659,23 +1733,23 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
// 如果是内部存储路径
bitmap = android.graphics.BitmapFactory.decodeFile(mCurrentBackgroundPath);
}
if (bitmap != null) {
// 计算屏幕尺寸
android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;
// 缩放图片以适配屏幕
android.graphics.Bitmap scaledBitmap = android.graphics.Bitmap.createScaledBitmap(
bitmap, screenWidth, screenHeight, true);
android.graphics.drawable.BitmapDrawable drawable = new android.graphics.drawable.BitmapDrawable(getResources(), scaledBitmap);
// 设置背景图片的缩放方式
drawable.setTileModeXY(android.graphics.Shader.TileMode.CLAMP, android.graphics.Shader.TileMode.CLAMP);
mBackgroundContainer.setBackground(drawable);
// 释放原始 bitmap
if (bitmap != scaledBitmap) {
bitmap.recycle();
@ -1703,7 +1777,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
SharedPreferences.Editor editor = sp.edit();
editor.putString(PREFERENCE_BACKGROUND + "_type", mCurrentBackgroundType);
editor.putString(PREFERENCE_BACKGROUND + "_path", mCurrentBackgroundPath);
if (BACKGROUND_TYPE_DEFAULT.equals(mCurrentBackgroundType)) {
// 找到当前背景资源的索引
int index = 0;
@ -1715,7 +1789,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
editor.putInt(PREFERENCE_BACKGROUND + "_index", index);
}
editor.apply();
}
@ -1725,12 +1799,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private void showBackgroundSelectorDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("选择背景");
// 创建背景选项数组,添加从相册选择的选项
String[] options = new String[BACKGROUND_OPTIONS.length + 1];
System.arraycopy(BACKGROUND_OPTIONS, 0, options, 0, BACKGROUND_OPTIONS.length);
options[BACKGROUND_OPTIONS.length] = "从相册选择";
builder.setItems(options, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@ -1751,7 +1825,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
});
builder.show();
}

@ -159,7 +159,8 @@ public class NotesListAdapter extends CursorAdapter {
Cursor cursor = getCursor();
for (int i = 0; i < getCount(); i++) {
if (cursor.moveToPosition(i)) {
if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) {
int type = NoteItemData.getNoteType(cursor);
if (type == Notes.TYPE_NOTE || type == Notes.TYPE_FOLDER) {
setCheckedItem(i, checked);
}
}
@ -308,7 +309,8 @@ public class NotesListAdapter extends CursorAdapter {
for (int i = 0; i < getCount(); i++) {
Cursor c = (Cursor) getItem(i);
if (c != null) {
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
int type = NoteItemData.getNoteType(c);
if (type == Notes.TYPE_NOTE || type == Notes.TYPE_FOLDER) {
mNotesCount++;
}
} else {

@ -94,7 +94,7 @@ public class NotesListItem extends LinearLayout {
*/
public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) {
// 设置复选框可见性和选中状态
if (choiceMode && data.getType() == Notes.TYPE_NOTE) {
if (choiceMode && (data.getType() == Notes.TYPE_NOTE || data.getType() == Notes.TYPE_FOLDER)) {
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setChecked(checked);
} else {
@ -135,6 +135,14 @@ public class NotesListItem extends LinearLayout {
+ context.getString(R.string.format_folder_files_count,
data.getNotesCount()));
mAlert.setVisibility(View.GONE);
// 设置置顶图标
if (data.isPinned()) {
mPinned.setVisibility(View.VISIBLE);
} else {
mPinned.setVisibility(View.GONE);
}
// 设置锁定图标
mLocked.setVisibility(View.GONE);
} else {
// 普通笔记
String title = data.getTitle();

@ -21,4 +21,8 @@
<item
android:id="@+id/menu_new_note"
android:title="@string/notelist_menu_new"/>
<item
android:id="@+id/menu_new_folder"
android:title="@string/menu_create_folder"/>
</menu>
Loading…
Cancel
Save