新增便签管理,但是搜索功能尚未完成

pull/25/head
Surponess 2 months ago
parent aff190b6a7
commit ba94c2c8e3

@ -42,6 +42,13 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
@ -65,15 +72,6 @@
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
@ -162,7 +160,7 @@
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
android:value=".ui.NotesListActivity" />
<!-- <activity-->
<!-- android:name=".MainActivity"-->

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/black" android:strokeColor="@android:color/black" android:strokeWidth="2" android:pathData="M5,15 L19,15"/>
</vector>

@ -64,8 +64,8 @@
android:layout_gravity="center"
android:background="@drawable/bg_btn_set_color" />
<!-- Insert image button OMO -->
<ImageButton
<!-- Insert image button OMO -->
<ImageButton
android:id="@+id/btn_insert_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -75,6 +75,71 @@
android:layout_marginRight="8dip" />
</LinearLayout>
<!-- Tag Management Section - Initially Hidden -->
<LinearLayout
android:id="@+id/tag_management_section"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:orientation="vertical"
android:padding="8dp"
android:background="@drawable/list_background"
android:visibility="gone">
<!-- Existing Tags -->
<HorizontalScrollView
android:id="@+id/existing_tags_scroll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
android:minHeight="30dp">
<LinearLayout
android:id="@+id/existing_tags_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="4dp"
android:layout_gravity="center_vertical">
</LinearLayout>
</HorizontalScrollView>
<!-- Add Tag Input -->
<LinearLayout
android:id="@+id/add_tag_input_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="4dp"
android:layout_marginTop="8dp"
android:minHeight="40dp">
<EditText
android:id="@+id/et_tag_input"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:hint="添加标签最多5个1-15字符"
android:inputType="text"
android:maxLength="15"
android:singleLine="true"
android:textAppearance="@style/TextAppearancePrimaryItem"
android:background="@android:drawable/editbox_background_normal"
android:gravity="center_vertical"
android:paddingHorizontal="8dp" />
<Button
android:id="@+id/btn_add_tag"
android:layout_width="80dp"
android:layout_height="40dp"
android:layout_marginLeft="8dp"
android:text="添加"
android:textAppearance="@style/TextAppearancePrimaryItem"
android:gravity="center" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/sv_note_edit"
android:layout_width="fill_parent"
@ -128,12 +193,17 @@
android:layout_height="7dip"
android:background="@drawable/bg_color_btn_mask" />
<!-- 横向滚动的富文本工具栏 -->
<!-- 横向滚动的富文本工具栏 -->
<HorizontalScrollView
android:id="@+id/floating_editor_toolbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="bottom|center"
android:background="#f5f5f5"
android:scrollbars="none">
android:scrollbars="none"
android:elevation="8dp"
android:layout_marginBottom="40dp">
<LinearLayout
android:layout_width="wrap_content"
@ -174,7 +244,7 @@
android:backgroundTint="@null"
android:focusable="false"
android:clickable="true"/>
<!-- 下划线按钮 -->
<Button
android:id="@+id/action_underline"
android:layout_width="40dp"
@ -189,6 +259,8 @@
</HorizontalScrollView>
</LinearLayout>
<!-- 富文本工具栏 - 放置在页面底部 -->
</LinearLayout>

@ -109,4 +109,4 @@
android:layout_gravity="top|right"
android:layout_marginEnd="24dp"
android:visibility="gone"/>
</FrameLayout>
</FrameLayout>

@ -40,35 +40,75 @@
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dip"
android:gravity="center_vertical|end">
<!-- 菜单按钮 -->
<ImageButton
android:id="@+id/btn_menu"
android:layout_width="50dip"
android:orientation="vertical"
android:padding="10dip">
<!-- 搜索栏 -->
<LinearLayout
android:id="@+id/search_bar"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:src="@android:drawable/ic_menu_more"
android:background="@null"
android:onClick="showCustomMenu" />
<!-- 搜索图标按钮 -->
<ImageButton
android:id="@+id/btn_search"
android:layout_width="50dp"
android:layout_height="50dip"
android:layout_marginRight="10dip"
android:src="@android:drawable/ic_menu_search"
android:background="@null"
android:onClick="handleSearchClick" />
android:orientation="horizontal"
android:background="@drawable/bg_btn_set_color"
android:gravity="center_vertical"
android:visibility="gone"
android:layout_marginBottom="10dip">
<EditText
android:id="@+id/et_search"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:hint="搜索笔记和标签"
android:textColor="#FFFFFF"
android:paddingLeft="15dip"
android:paddingRight="10dip"
android:singleLine="true"
android:textSize="16sp"
android:imeOptions="actionSearch" />
<ImageButton
android:id="@+id/btn_clear_search"
android:layout_width="40dip"
android:layout_height="40dip"
android:src="@android:drawable/ic_menu_close_clear_cancel"
android:background="@null"
android:padding="10dip"
android:tint="#FFFFFF" />
</LinearLayout>
<!-- 工具栏按钮 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical|end">
<!-- 正方形添加按钮 -->
<Button
android:id="@+id/btn_new_note"
android:background="@drawable/new_note"
android:layout_width="50dip"
android:layout_height="50dip"
android:focusable="false" />
<!-- 菜单按钮 -->
<ImageButton
android:id="@+id/btn_menu"
android:layout_width="50dip"
android:layout_height="50dip"
android:src="@android:drawable/ic_menu_more"
android:background="@null"
android:onClick="showCustomMenu" />
<!-- 搜索图标按钮 -->
<ImageButton
android:id="@+id/btn_search"
android:layout_width="50dp"
android:layout_height="50dip"
android:layout_marginRight="10dip"
android:src="@android:drawable/ic_menu_search"
android:background="@null"
android:onClick="handleSearchClick" />
<!-- 正方形添加按钮 -->
<Button
android:id="@+id/btn_new_note"
android:background="@drawable/new_note"
android:layout_width="50dip"
android:layout_height="50dip"
android:focusable="false" />
</LinearLayout>
</LinearLayout>
<ListView
@ -124,6 +164,4 @@
android:minWidth="0dip" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</FrameLayout>

@ -49,4 +49,8 @@
<item
android:id="@+id/menu_delete_remind"
android:title="@string/menu_remove_remind" />
<item
android:id="@+id/menu_tag_management"
android:title="标签管理" />
</menu>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 定义退出搜索菜单项的ID -->
<item name="menu_exit_search" type="id" />
</resources>

@ -80,6 +80,8 @@ public class Notes {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
// 通话记录笔记的MIME类型
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
// 标签的MIME类型
public static final String TAG = TagNote.CONTENT_ITEM_TYPE;
}
// URI 是 ContentProvider 的标准访问入口,用于统一访问应用的数据。
@ -251,4 +253,28 @@ public class Notes {
// 通话记录笔记的URI
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
}
/**
* TagNote -
* URI
*/
public static final class TagNote implements DataColumns {
// 标签名称
public static final String TAG_NAME = CONTENT;
// 标签颜色
public static final String TAG_COLOR = DATA1;
// 标签使用次数
public static final String TAG_COUNT = DATA2;
// 标签的目录MIME类型
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/tag_note";
// 标签的单项MIME类型
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/tag_note";
// 标签的URI
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/tag_note");
}
}

@ -30,7 +30,7 @@ import net.micode.notes.data.Notes.NoteColumns;
public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 7;
private static final int DB_VERSION = 8;
public interface TABLE {
public static final String NOTE = "note";
@ -326,6 +326,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
// 添加搜索相关的索引,优化搜索性能
db.execSQL("CREATE INDEX IF NOT EXISTS data_mime_type_content_index ON " + TABLE.DATA + "(" + DataColumns.MIME_TYPE + ", " + DataColumns.CONTENT + ");");
Log.d(TAG, "data table has been created");
}
@ -402,6 +404,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
oldVersion++;
}
if (oldVersion == 7) {
upgradeToV8(db);
oldVersion++;
}
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
@ -467,6 +474,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
createTrashDataTable(db);
Log.d(TAG, "Upgraded to version 7: created trash_data table");
}
private void upgradeToV8(SQLiteDatabase db) {
// 升级到版本8添加标签支持
// 标签数据将存储在现有的data表中使用新的MIME类型
Log.d(TAG, "Upgraded to version 8: added tag support");
}
public void createEncryptedNotePasswordTable(SQLiteDatabase db) {
db.execSQL(CREATE_ENCRYPTED_NOTE_PASSWORD_TABLE_SQL);

@ -79,9 +79,13 @@ public class NotesProvider extends ContentProvider {
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
+ " LEFT JOIN " + TABLE.DATA + " ON " + TABLE.NOTE + "." + NoteColumns.ID + "=" + TABLE.DATA + "." + DataColumns.NOTE_ID
+ " WHERE (" + NoteColumns.SNIPPET + " LIKE ?"
+ " OR (" + TABLE.DATA + "." + DataColumns.MIME_TYPE + "=? AND " + TABLE.DATA + "." + DataColumns.CONTENT + " LIKE ?" + "))"
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE
+ " GROUP BY " + TABLE.NOTE + "." + NoteColumns.ID
+ " ORDER BY CASE WHEN " + TABLE.DATA + "." + DataColumns.MIME_TYPE + "=? AND " + TABLE.DATA + "." + DataColumns.CONTENT + " LIKE ?" + " THEN 0 ELSE 1 END, " + NoteColumns.MODIFIED_DATE + " DESC";
@Override
public boolean onCreate() {
@ -145,8 +149,9 @@ public class NotesProvider extends ContentProvider {
try {
searchString = String.format("%%%s%%", searchString);
String tagMimeType = Notes.DataConstants.TAG;
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
new String[] { searchString });
new String[] { searchString, tagMimeType, searchString, tagMimeType, searchString });
} catch (IllegalStateException ex) {
Log.e(TAG, "got exception: " + ex.toString());
}

@ -28,7 +28,9 @@ import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TagNote;
import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList;
@ -149,6 +151,21 @@ public class Note {
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
/**
*
* @param tagName
*/
public void addTagData(String tagName) {
mNoteData.addTagData(tagName);
}
/**
*
*/
public void clearTagData() {
mNoteData.clearTagData();
}
/**
*
@ -193,7 +210,7 @@ public class Note {
/**
*
*
*
*/
private class NoteData {
private long mTextDataId; // 文本笔记数据ID
@ -201,17 +218,23 @@ public class Note {
private long mCallDataId; // 通话笔记数据ID
private ContentValues mCallDataValues; // 通话笔记数据值
private static final String TAG = "NoteData"; // 日志标签
// 标签相关数据
private ArrayList<ContentValues> mTagDataValuesList; // 标签数据值列表
private ArrayList<Long> mTagDataIdList; // 标签数据ID列表
/** 构造函数:初始化两个数据集与对应 ID */
/** 构造函数:初始化数据集与对应 ID */
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
// 初始化标签相关数据
mTagDataValuesList = new ArrayList<>();
mTagDataIdList = new ArrayList<>();
}
/**
@ -219,7 +242,7 @@ public class Note {
* @return truefalse
*/
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0 || mTagDataValuesList.size() > 0;
}
/**
@ -267,6 +290,28 @@ public class Note {
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
*
* @param tagName
*/
void addTagData(String tagName) {
ContentValues tagValues = new ContentValues();
tagValues.put(TagNote.TAG_NAME, tagName);
mTagDataValuesList.add(tagValues);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
*
*/
void clearTagData() {
mTagDataValuesList.clear();
mTagDataIdList.clear();
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
*
@ -330,6 +375,29 @@ public class Note {
mCallDataValues.clear();
}
// 处理标签数据
if (mTagDataValuesList.size() > 0) {
// 先删除现有标签数据
String selection = DataColumns.NOTE_ID + "=? AND " + DataColumns.MIME_TYPE + "=?";
String[] selectionArgs = {String.valueOf(noteId), TagNote.CONTENT_ITEM_TYPE};
context.getContentResolver().delete(Notes.CONTENT_DATA_URI, selection, selectionArgs);
// 插入新标签数据
for (ContentValues tagValues : mTagDataValuesList) {
tagValues.put(DataColumns.NOTE_ID, noteId);
tagValues.put(DataColumns.MIME_TYPE, TagNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, tagValues);
try {
long tagDataId = Long.valueOf(uri.getPathSegments().get(1));
mTagDataIdList.add(tagDataId);
} catch (NumberFormatException e) {
Log.e(TAG, "Insert new tag data fail with noteId" + noteId);
return null;
}
}
mTagDataValuesList.clear();
}
if (operationList.size() > 0) {
try {
ContentProviderResult[] results = context.getContentResolver().applyBatch(

@ -162,7 +162,7 @@ public class WorkingNote {
/**
* data
* <p>NOTECALL_NOTEID</p>
* <p>NOTECALL_NOTEIDTAG</p>
*/
private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
@ -180,6 +180,10 @@ public class WorkingNote {
mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN));
} else if (DataConstants.CALL_NOTE.equals(type)) {
mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN));
} else if (DataConstants.TAG.equals(type)) {
// 加载标签数据
String tagName = cursor.getString(DATA_CONTENT_COLUMN);
mNote.addTagData(tagName);
} else {
Log.d(TAG, "Wrong note type with type:" + type);
}
@ -529,6 +533,21 @@ public class WorkingNote {
}
return encrypted;
}
/**
*
* @param tagName
*/
public void addTag(String tagName) {
mNote.addTagData(tagName);
}
/**
*
*/
public void clearTags() {
mNote.clearTagData();
}
/**
*

@ -36,6 +36,7 @@ import android.view.WindowManager;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.ui.NoteEditActivity;
import java.io.IOException;

@ -28,6 +28,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Build;
@ -46,9 +47,14 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.util.DisplayMetrics;
import android.widget.HorizontalScrollView;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -57,6 +63,7 @@ import android.util.Base64;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
@ -72,14 +79,21 @@ import android.content.res.Resources;
// import android.support.annotation.NonNull;
import android.Manifest;
import android.graphics.Color;
import java.io.InputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import android.os.Environment;
import android.text.format.DateUtils;
import android.view.ViewGroup;
import android.content.ActivityNotFoundException;
import java.io.InputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jp.wasabeef.richeditor.RichEditor;
import net.micode.notes.R;
@ -96,12 +110,6 @@ import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
@ -181,6 +189,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private View mFontSizeSelector; // 字体大小选择器
private RichEditor mNoteEditor; // 富文本编辑器
private View mNoteEditorPanel; // 笔记编辑器面板
private HorizontalScrollView mFloatingToolbar; // 浮动富文本工具栏
private WorkingNote mWorkingNote; // 工作笔记对象
private SharedPreferences mSharedPrefs; // 共享偏好设置
private int mFontSizeId; // 字体大小ID
@ -198,6 +207,18 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery; // 用户查询字符串
private Pattern mPattern; // 正则表达式模式(用于高亮查询结果)
private ChecklistManager mChecklistManager; // 清单管理器OMO
// 标签管理相关控件
private LinearLayout mTagManagementSection; // 标签管理区域
private LinearLayout mExistingTagsContainer; // 现有标签容器
private LinearLayout mBottomTagsContainer; // 底部标签显示容器
private EditText mTagInput; // 标签输入框
private Button mAddTagButton; // 添加标签按钮
private ArrayList<String> mTagsList; // 标签列表
// 搜索历史相关
private static final String PREFERENCE_SEARCH_HISTORY = "search_history"; // 搜索历史偏好设置键
private static final int MAX_SEARCH_HISTORY = 20; // 最大搜索历史记录数
/**
*
@ -275,6 +296,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return false;
}
}
// 保存搜索历史
if (!TextUtils.isEmpty(mUserQuery)) {
saveSearchHistory(mUserQuery);
}
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
@ -503,6 +529,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* is not ready
*/
showAlertHeader(); // 显示提醒头部
// 加载现有标签
loadExistingTags();
}
/**
@ -736,6 +765,12 @@ public class NoteEditActivity extends Activity implements OnClickListener,
Log.e(TAG, "RichEditor is null! Check layout file.");
return;
}
// 初始化浮动富文本工具栏
mFloatingToolbar = findViewById(R.id.floating_editor_toolbar);
if (mFloatingToolbar != null) {
setupFloatingToolbarDrag();
}
// 初始化富文本编辑器配置
initRichEditor();
@ -798,6 +833,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mBtnInsertImage.setOnClickListener(this);
}
// 初始化标签管理相关控件
initTagManagement();
// 初始化富文本功能按钮
initRichEditorButtons();
}
@ -1001,11 +1039,28 @@ public class NoteEditActivity extends Activity implements OnClickListener,
case R.id.menu_delete_remind:
mWorkingNote.setAlertDate(0, false); // 删除提醒
break;
case R.id.menu_tag_management:
// 切换标签管理界面显示
toggleTagManagement();
break;
default:
break;
}
return true;
}
/**
* /
*/
private void toggleTagManagement() {
if (mTagManagementSection.getVisibility() == View.VISIBLE) {
// 隐藏标签管理界面
mTagManagementSection.setVisibility(View.GONE);
} else {
// 显示标签管理界面
mTagManagementSection.setVisibility(View.VISIBLE);
}
}
/**
*
@ -1403,6 +1458,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
*/
private boolean saveNote() {
getWorkingText(); // 获取当前工作文本
// 保存标签数据
saveTagsToNote();
boolean saved = mWorkingNote.saveNote(); // 保存笔记到数据库
if (saved) {
/**
@ -1416,6 +1475,69 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
return saved;
}
/**
*
*/
private void saveTagsToNote() {
// 清空现有标签
mWorkingNote.clearTags();
// 添加所有标签
for (String tag : mTagsList) {
mWorkingNote.addTag(tag);
}
}
/**
*
* @param query
*/
private void saveSearchHistory(String query) {
if (TextUtils.isEmpty(query)) {
return;
}
// 获取SharedPreferences
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
// 获取现有的搜索历史
String historyString = sp.getString(PREFERENCE_SEARCH_HISTORY, "");
// 将搜索历史拆分为列表
ArrayList<String> historyList = new ArrayList<>();
if (!TextUtils.isEmpty(historyString)) {
String[] historyArray = historyString.split(",");
for (String item : historyArray) {
if (!TextUtils.isEmpty(item) && !historyList.contains(item)) {
historyList.add(item);
}
}
}
// 如果搜索关键词已存在,先移除
historyList.remove(query);
// 将新的搜索关键词添加到列表开头
historyList.add(0, query);
// 限制搜索历史记录数量
if (historyList.size() > MAX_SEARCH_HISTORY) {
historyList = new ArrayList<>(historyList.subList(0, MAX_SEARCH_HISTORY));
}
// 将搜索历史列表转换为字符串,用逗号分隔
StringBuilder sb = new StringBuilder();
for (int i = 0; i < historyList.size(); i++) {
if (i > 0) {
sb.append(",");
}
sb.append(historyList.get(i));
}
// 保存到SharedPreferences
sp.edit().putString(PREFERENCE_SEARCH_HISTORY, sb.toString()).apply();
}
/**
*
@ -1685,7 +1807,264 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteEditor.setEditorFontSize(18); // 默认值
}
}
/**
*
*/
private void initTagManagement() {
// 初始化标签管理相关控件
mTagManagementSection = findViewById(R.id.tag_management_section);
mExistingTagsContainer = findViewById(R.id.existing_tags_container);
mTagInput = findViewById(R.id.et_tag_input);
mAddTagButton = findViewById(R.id.btn_add_tag);
// 初始化标签列表
mTagsList = new ArrayList<>();
// 设置添加标签按钮的点击事件
mAddTagButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
addTag();
}
});
// 加载现有标签
loadExistingTags();
}
/**
*
*/
private void addTag() {
String tagName = mTagInput.getText().toString().trim();
// 检查标签是否有效
if (isValidTag(tagName)) {
// 添加标签到列表
mTagsList.add(tagName);
// 更新UI显示
updateTagsDisplay();
// 清空输入框
mTagInput.setText("");
}
}
/**
*
* @param tagName
* @return
*/
private boolean isValidTag(String tagName) {
// 检查标签是否为空
if (TextUtils.isEmpty(tagName)) {
Toast.makeText(this, "标签不能为空", Toast.LENGTH_SHORT).show();
return false;
}
// 检查标签长度
if (tagName.length() < 1 || tagName.length() > 15) {
Toast.makeText(this, "标签长度必须在1-15个字符之间", Toast.LENGTH_SHORT).show();
return false;
}
// 检查标签数量是否超过限制
if (mTagsList.size() >= 5) {
Toast.makeText(this, "每个笔记最多只能添加5个标签", Toast.LENGTH_SHORT).show();
return false;
}
// 检查标签是否已存在
if (mTagsList.contains(tagName)) {
Toast.makeText(this, "该标签已存在", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
/**
*
*/
private void updateTagsDisplay() {
// 清空现有标签容器
mExistingTagsContainer.removeAllViews();
// 添加所有标签到容器
for (final String tag : mTagsList) {
// 创建标签管理区域的标签视图
LinearLayout tagView = new LinearLayout(this);
LinearLayout.LayoutParams tagViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
36);
tagViewParams.setMargins(0, 0, 8, 0);
tagView.setLayoutParams(tagViewParams);
tagView.setOrientation(LinearLayout.HORIZONTAL);
tagView.setGravity(Gravity.CENTER_VERTICAL);
tagView.setPadding(12, 0, 8, 0);
tagView.setBackgroundResource(R.drawable.bg_color_btn_mask);
tagView.setClickable(true);
tagView.setFocusable(true);
// 创建标签文本
TextView tagText = new TextView(this);
tagText.setText(tag);
tagText.setTextAppearance(this, R.style.TextAppearancePrimaryItem);
tagText.setTextColor(Color.WHITE);
tagText.setPadding(0, 0, 8, 0);
tagText.setSingleLine(true);
tagText.setTextSize(14);
// 创建删除按钮
ImageView deleteButton = new ImageView(this);
LinearLayout.LayoutParams deleteParams = new LinearLayout.LayoutParams(
24, 24);
deleteButton.setLayoutParams(deleteParams);
deleteButton.setImageResource(android.R.drawable.ic_delete);
deleteButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
deleteButton.setClickable(true);
deleteButton.setFocusable(true);
deleteButton.setTag(tag);
// 设置删除按钮点击事件
deleteButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String tagToRemove = (String) v.getTag();
removeTag(tagToRemove);
}
});
// 添加控件到标签视图
tagView.addView(tagText);
tagView.addView(deleteButton);
// 添加标签视图到容器
mExistingTagsContainer.addView(tagView);
}
}
/**
*
* @param tagName
*/
private void removeTag(String tagName) {
mTagsList.remove(tagName);
updateTagsDisplay();
}
/**
*
*/
private void setupFloatingToolbarDrag() {
// 记录拖拽状态
final boolean[] isDragging = {false};
final int[] lastX = {0};
final int[] lastY = {0};
// 设置触摸监听器
mFloatingToolbar.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 记录初始触摸位置
isDragging[0] = false;
lastX[0] = x;
lastY[0] = y;
break;
case MotionEvent.ACTION_MOVE:
// 计算移动距离
int deltaX = x - lastX[0];
int deltaY = y - lastY[0];
// 判断是否开始拖拽
if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
isDragging[0] = true;
}
if (isDragging[0]) {
// 更新工具栏位置
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
// 计算新的位置
int newLeftMargin = params.leftMargin + deltaX;
int newTopMargin = params.topMargin + deltaY;
// 限制位置在屏幕范围内
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;
// 计算工具栏宽度和高度
int toolbarWidth = v.getWidth();
int toolbarHeight = v.getHeight();
// 限制左边界
newLeftMargin = Math.max(0, Math.min(newLeftMargin, screenWidth - toolbarWidth));
// 限制上边界
newTopMargin = Math.max(0, Math.min(newTopMargin, screenHeight - toolbarHeight));
// 更新布局参数
params.leftMargin = newLeftMargin;
params.topMargin = newTopMargin;
v.setLayoutParams(params);
// 更新最后触摸位置
lastX[0] = x;
lastY[0] = y;
return true; // 消耗事件
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// 结束拖拽
if (isDragging[0]) {
return true; // 消耗事件
}
break;
}
return false; // 不消耗事件,允许其他触摸事件处理
}
});
}
/**
*
*/
private void loadExistingTags() {
// 从数据库加载现有标签
if (mWorkingNote != null && mWorkingNote.getNoteId() > 0) {
Cursor cursor = getContentResolver().query(
Notes.CONTENT_DATA_URI,
new String[]{Notes.DataColumns.CONTENT},
Notes.DataColumns.NOTE_ID + "=? AND " + Notes.DataColumns.MIME_TYPE + "=?",
new String[]{String.valueOf(mWorkingNote.getNoteId()), Notes.DataConstants.TAG},
null);
if (cursor != null) {
while (cursor.moveToNext()) {
String tagName = cursor.getString(0);
if (!TextUtils.isEmpty(tagName) && !mTagsList.contains(tagName)) {
mTagsList.add(tagName);
}
}
cursor.close();
}
// 更新UI显示
updateTagsDisplay();
}
}
// 初始化富文本编辑器配置
private void initRichEditor() {
mNoteEditor.setEditorHeight(600); // 设置编辑器高度

@ -24,6 +24,7 @@ import net.micode.notes.data.Contact;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.ui.NoteEditActivity;
/**
*

@ -20,6 +20,7 @@ import android.app.Activity;
import net.micode.notes.ui.PasswordInputActivity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
@ -56,6 +57,8 @@ import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.TextView;
@ -65,6 +68,7 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.data.NotesDatabaseHelper;
import net.micode.notes.gtask.remote.GTaskSyncService;
import net.micode.notes.model.ChecklistManager;
import net.micode.notes.model.WorkingNote;
@ -80,9 +84,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Set;
import android.os.Build;
import android.view.Gravity;
import android.view.ViewConfiguration;
import android.graphics.Color;
import java.lang.reflect.Field;
/**
@ -99,6 +108,26 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private static final int MENU_FOLDER_VIEW = 1;
// 标签云相关控件
private LinearLayout mTagCloudSection; // 标签云区域
private LinearLayout mTagCloudContainer; // 标签云容器
private Button mAllNotesTag; // 全部笔记标签
private String mCurrentFilterTag; // 当前过滤标签
// 搜索历史相关
private static final String PREFERENCE_SEARCH_HISTORY = "search_history"; // 搜索历史偏好设置键
private static final int MAX_SEARCH_HISTORY = 20; // 最大搜索历史记录数
private String mSearchQuery; // 当前搜索查询字符串
private boolean mIsSearchMode; // 是否处于搜索模式
// 实时搜索相关
private LinearLayout mSearchBar; // 搜索栏容器
private EditText mSearchEditText; // 搜索输入框
private ImageButton mClearSearchButton; // 清除搜索按钮
private static final int SEARCH_DEBOUNCE_DELAY = 300; // 搜索防抖延迟时间(毫秒)
private Runnable mSearchRunnable; // 搜索任务
private long mLastSearchTime; // 上次搜索时间
private static final int MENU_FOLDER_CHANGE_NAME = 2;
private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction";
@ -277,6 +306,73 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mIsChecklistMode = false;
updateModeButtons();
mChecklistManager = new ChecklistManager(mContentResolver);
// 初始化搜索相关控件
mSearchBar = (LinearLayout) findViewById(R.id.search_bar);
mSearchEditText = findViewById(R.id.et_search);
mClearSearchButton = (ImageButton) findViewById(R.id.btn_clear_search);
// 设置搜索监听器
initSearchListeners();
// 标签云功能已移除,相关代码已注释
// mTagCloudSection = findViewById(R.id.tag_cloud_section);
// mTagCloudContainer = findViewById(R.id.tag_cloud_container);
// mAllNotesTag = findViewById(R.id.tag_all_notes);
// mCurrentFilterTag = null;
//
// // 加载标签云
// loadTagCloud();
}
/**
*
*/
private void initSearchListeners() {
// 初始化搜索任务
mSearchRunnable = new Runnable() {
@Override
public void run() {
// 执行搜索查询
setSearchMode(!TextUtils.isEmpty(mSearchQuery), mSearchQuery);
}
};
// 搜索输入框文本变化监听器
mSearchEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// 文本变化前的处理
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 文本变化时的处理
mSearchQuery = s.toString();
// 移除之前的搜索任务
mSearchEditText.removeCallbacks(mSearchRunnable);
// 延迟执行搜索任务
mSearchEditText.postDelayed(mSearchRunnable, SEARCH_DEBOUNCE_DELAY);
}
@Override
public void afterTextChanged(Editable s) {
// 文本变化后的处理
}
});
// 清除搜索按钮点击监听器
mClearSearchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 清除搜索内容
mSearchEditText.setText("");
// 移除未执行的搜索任务
mSearchEditText.removeCallbacks(mSearchRunnable);
// 退出搜索模式
exitSearchMode();
}
});
}
/**
@ -500,32 +596,185 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
String selection;
String[] selectionArgs;
if (mCurrentFolderId == Notes.ID_ROOT_FOLDER) {
if (mIsChecklistMode) {
// 根文件夹下的清单模式:只显示清单类型的笔记
selection = "(" + NoteColumns.TYPE + "=" + Notes.TYPE_CHECKLIST + " AND " + NoteColumns.PARENT_ID + "=?)" +
// 基础查询条件
if (mIsSearchMode) {
// 搜索模式:忽略清单模式,搜索所有笔记和清单
if (mCurrentFolderId == Notes.ID_ROOT_FOLDER) {
// 根文件夹下的搜索:显示所有类型的笔记(普通笔记、清单、文件夹、通话记录文件夹)
selection = "(" + NoteColumns.TYPE + " IN (" + Notes.TYPE_NOTE + ", " + Notes.TYPE_CHECKLIST + ", " + Notes.TYPE_FOLDER + ") AND " + NoteColumns.PARENT_ID + "=?)" +
" OR (" + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + NoteColumns.NOTES_COUNT + ">0)";
} else {
// 根文件夹下的笔记模式:显示文件夹、普通笔记和非空通话记录文件夹
selection = "(" + NoteColumns.TYPE + "<>" + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" +
" OR (" + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + NoteColumns.NOTES_COUNT + ">0)";
// 普通文件夹下的搜索:显示所有类型的笔记(普通笔记和清单)
selection = NoteColumns.PARENT_ID + "=? AND " + NoteColumns.TYPE + " IN (" + Notes.TYPE_NOTE + ", " + Notes.TYPE_CHECKLIST + ")";
}
} else {
if (mIsChecklistMode) {
// 普通文件夹下的清单模式:只显示清单类型的笔记
selection = NoteColumns.PARENT_ID + "=? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_CHECKLIST;
// 非搜索模式:使用原来的逻辑
if (mCurrentFolderId == Notes.ID_ROOT_FOLDER) {
if (mIsChecklistMode) {
// 根文件夹下的清单模式:只显示清单类型的笔记
selection = "(" + NoteColumns.TYPE + "=" + Notes.TYPE_CHECKLIST + " AND " + NoteColumns.PARENT_ID + "=?)" +
" OR (" + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + NoteColumns.NOTES_COUNT + ">0)";
} else {
// 根文件夹下的笔记模式:显示文件夹、普通笔记和非空通话记录文件夹
selection = "(" + NoteColumns.TYPE + "<>" + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" +
" OR (" + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + NoteColumns.NOTES_COUNT + ">0)";
}
} else {
// 普通文件夹下的笔记模式:只显示普通笔记
selection = NoteColumns.PARENT_ID + "=? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
if (mIsChecklistMode) {
// 普通文件夹下的清单模式:只显示清单类型的笔记
selection = NoteColumns.PARENT_ID + "=? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_CHECKLIST;
} else {
// 普通文件夹下的笔记模式:只显示普通笔记
selection = NoteColumns.PARENT_ID + "=? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
}
}
}
// 添加搜索过滤条件
if (mIsSearchMode && !TextUtils.isEmpty(mSearchQuery)) {
// 搜索过滤需要使用子查询因为内容存储在data表中
String searchFilter = " AND " + NoteColumns.ID + " IN (" +
"SELECT " + Notes.DataColumns.NOTE_ID +
" FROM " + NotesDatabaseHelper.TABLE.DATA +
" WHERE (" + Notes.DataColumns.MIME_TYPE + "=?" +
" AND " + Notes.DataColumns.CONTENT + " LIKE ?" +
") OR (" + Notes.DataColumns.MIME_TYPE + "=?" +
" AND " + Notes.DataColumns.CONTENT + " LIKE ?" +
"))";
selection += searchFilter;
}
// 添加标签过滤条件
if (mCurrentFilterTag != null) {
// 标签过滤需要使用子查询因为标签存储在data表中
String tagFilter = " AND " + NoteColumns.ID + " IN (" +
"SELECT " + Notes.DataColumns.NOTE_ID +
" FROM " + NotesDatabaseHelper.TABLE.DATA +
" WHERE " + Notes.DataColumns.MIME_TYPE + "=?" +
" AND " + Notes.DataColumns.CONTENT + "=?" +
")";
selection += tagFilter;
}
// 准备选择参数
ArrayList<String> argsList = new ArrayList<>();
argsList.add(String.valueOf(mCurrentFolderId));
// 添加搜索参数
if (mIsSearchMode && !TextUtils.isEmpty(mSearchQuery)) {
String searchPattern = "%" + mSearchQuery + "%";
// 搜索普通文本内容
argsList.add(Notes.DataConstants.NOTE);
argsList.add(searchPattern);
// 搜索标签
argsList.add(Notes.DataConstants.TAG);
argsList.add(searchPattern);
}
// 添加标签参数
if (mCurrentFilterTag != null) {
argsList.add(Notes.DataConstants.TAG);
argsList.add(mCurrentFilterTag);
}
selectionArgs = argsList.toArray(new String[argsList.size()]);
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, selectionArgs,
NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
}
/**
*
*/
private void loadTagCloud() {
// 清空现有标签(保留"全部笔记"标签)
while (mTagCloudContainer.getChildCount() > 1) {
mTagCloudContainer.removeViewAt(1);
}
// 查询所有标签,按使用次数排序
String tagQuery = "SELECT " + Notes.DataColumns.CONTENT +
" FROM " + NotesDatabaseHelper.TABLE.DATA +
" WHERE " + Notes.DataColumns.MIME_TYPE + "=?" +
" GROUP BY " + Notes.DataColumns.CONTENT +
" ORDER BY COUNT(*) DESC";
Cursor cursor = mContentResolver.query(
Notes.CONTENT_DATA_URI,
new String[]{Notes.DataColumns.CONTENT},
Notes.DataColumns.MIME_TYPE + "=?",
new String[]{Notes.DataConstants.TAG},
Notes.DataColumns.CONTENT + " ASC");
if (cursor != null) {
while (cursor.moveToNext()) {
String tagName = cursor.getString(0);
if (!TextUtils.isEmpty(tagName)) {
// 创建标签按钮
Button tagButton = new Button(this);
tagButton.setText(tagName);
tagButton.setBackgroundResource(R.drawable.bg_btn_set_color);
tagButton.setTextColor(Color.WHITE);
tagButton.setTextSize(14);
tagButton.setSingleLine(true);
tagButton.setTag(tagName);
// tagButton.setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// onTagClick(v);
// }
// });
// 设置标准化布局参数
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, 36);
params.setMargins(0, 0, 8, 0);
params.gravity = Gravity.CENTER_VERTICAL;
tagButton.setLayoutParams(params);
// 设置标准化内边距
tagButton.setPadding(12, 0, 12, 0);
// 添加到标签云容器
mTagCloudContainer.addView(tagButton);
}
}
cursor.close();
}
}
// 标签云功能已移除onTagClick方法已删除
// public void onTagClick(View v) {
// if (v.getId() == R.id.tag_all_notes) {
// // 显示全部笔记
// mCurrentFilterTag = null;
// mAllNotesTag.setTextColor(Color.WHITE);
// mAllNotesTag.setBackgroundResource(R.drawable.bg_btn_set_color);
// } else {
// // 显示特定标签的笔记
// mCurrentFilterTag = (String) v.getTag();
// mAllNotesTag.setTextColor(Color.BLACK);
// mAllNotesTag.setBackgroundResource(android.R.drawable.btn_default);
// }
//
// // 更新其他标签的样式
// for (int i = 1; i < mTagCloudContainer.getChildCount(); i++) {
// Button tagButton = (Button) mTagCloudContainer.getChildAt(i);
// if (tagButton.getTag().equals(mCurrentFilterTag)) {
// tagButton.setTextColor(Color.WHITE);
// tagButton.setBackgroundResource(R.drawable.bg_btn_set_color);
// } else {
// tagButton.setTextColor(Color.BLACK);
// tagButton.setBackgroundResource(android.R.drawable.btn_default);
// }
// }
//
// // 重新查询笔记列表
// startAsyncNotesListQuery();
// }
/**
* -
*/
@ -615,7 +864,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
final EditText etPassword = (EditText) view.findViewById(R.id.et_foler_name);
etPassword.setHint(R.string.password_hint);
etPassword.setInputType(android.text.InputType.TYPE_CLASS_TEXT |
etPassword.setInputType(android.text.InputType.TYPE_CLASS_TEXT |
android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD);
builder.setTitle(R.string.password_set_dialog_title);
builder.setView(view);
@ -630,14 +879,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
final Dialog dialog = builder.create();
dialog.show();
final Button positive = (Button) dialog.findViewById(android.R.id.button1);
positive.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String password = etPassword.getText().toString();
if (TextUtils.isEmpty(password)) {
Toast.makeText(NotesListActivity.this,
Toast.makeText(NotesListActivity.this,
R.string.password_empty, Toast.LENGTH_SHORT).show();
return;
}
@ -1175,12 +1424,67 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
startActivity(intent);
break;
}
case R.id.menu_exit_search:
// 退出搜索模式
exitSearchMode();
return true;
default:
break;
}
return true;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// 处理搜索意图
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
if (!TextUtils.isEmpty(query)) {
setSearchMode(true, query);
// 添加到搜索历史
saveSearchHistory(query);
// 显示软键盘
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(mSearchEditText, InputMethodManager.SHOW_IMPLICIT);
}
}
}
}
/**
*
* @param isSearchMode
* @param searchQuery
*/
private void setSearchMode(boolean isSearchMode, String searchQuery) {
mIsSearchMode = isSearchMode;
mSearchQuery = searchQuery;
startAsyncNotesListQuery();
// 更新UI显示或隐藏搜索相关控件
if (isSearchMode) {
// 搜索模式下显示搜索栏
mSearchBar.setVisibility(View.VISIBLE);
// 设置搜索查询文本
mSearchEditText.setText(searchQuery);
// 将光标定位到文本末尾
mSearchEditText.setSelection(searchQuery.length());
} else {
// 退出搜索模式,隐藏搜索栏
mSearchBar.setVisibility(View.GONE);
}
}
/**
* 退
*/
public void exitSearchMode() {
setSearchMode(false, null);
}
@Override
public boolean onSearchRequested() {
startSearch(null, false, null /* appData */, false);
@ -1192,8 +1496,85 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
* OMO
*/
public void handleSearchClick(View view) {
// 调用系统搜索方法
onSearchRequested();
// 显示搜索栏并聚焦到搜索输入框
setSearchMode(true, mSearchQuery != null ? mSearchQuery : "");
mSearchEditText.requestFocus();
// 显示软键盘
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(mSearchEditText, InputMethodManager.SHOW_IMPLICIT);
}
}
/**
*
* @param query
*/
private void saveSearchHistory(String query) {
if (TextUtils.isEmpty(query)) {
return;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Set<String> historySet = prefs.getStringSet(PREFERENCE_SEARCH_HISTORY, new HashSet<String>());
// 创建新的集合以支持修改
Set<String> newHistorySet = new LinkedHashSet<String>(historySet);
// 如果已存在,先移除,然后添加到开头
newHistorySet.remove(query);
// 创建有序集合以保持插入顺序
LinkedHashSet<String> orderedHistorySet = new LinkedHashSet<String>();
orderedHistorySet.add(query);
orderedHistorySet.addAll(newHistorySet);
// 限制历史记录数量
if (orderedHistorySet.size() > MAX_SEARCH_HISTORY) {
// 移除最旧的记录
String[] historyArray = orderedHistorySet.toArray(new String[0]);
for (int i = MAX_SEARCH_HISTORY; i < historyArray.length; i++) {
orderedHistorySet.remove(historyArray[i]);
}
}
// 保存到偏好设置
prefs.edit().putStringSet(PREFERENCE_SEARCH_HISTORY, orderedHistorySet).apply();
}
/**
*
* @return
*/
private Set<String> getSearchHistory() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
return prefs.getStringSet(PREFERENCE_SEARCH_HISTORY, new HashSet<String>());
}
/**
*
*/
private void clearSearchHistory() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit().remove(PREFERENCE_SEARCH_HISTORY).apply();
}
/**
* 退
* @param menu
* @return
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.note_list_options, menu);
// 在搜索模式下添加退出搜索菜单项
if (mIsSearchMode) {
MenuItem exitSearchItem = menu.add(Menu.NONE, R.id.menu_exit_search, Menu.NONE, "退出搜索");
exitSearchItem.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
exitSearchItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
return true;
}
private void exportNoteToText() {
final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);

@ -27,6 +27,7 @@ import android.widget.CursorAdapter;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.ui.NoteEditActivity;
import java.util.Collection;
import java.util.HashMap;

@ -28,6 +28,7 @@ import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.tool.PasswordUtils;
import net.micode.notes.ui.NoteEditActivity;
/**
* Activity

Loading…
Cancel
Save