diff --git a/README.md b/README.md
deleted file mode 100644
index 1a6caa9..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# git
-
diff --git a/res/color/primary_text_dark.xml b/res/color/primary_text_dark.xml
new file mode 100644
index 0000000..4fef9ab
--- /dev/null
+++ b/res/color/primary_text_dark.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/color/secondary_text_dark.xml b/res/color/secondary_text_dark.xml
new file mode 100644
index 0000000..eee5cdc
--- /dev/null
+++ b/res/color/secondary_text_dark.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable-hdpi/bg_btn_set_color.png b/res/drawable-hdpi/bg_btn_set_color.png
new file mode 100644
index 0000000..5eb5d44
Binary files /dev/null and b/res/drawable-hdpi/bg_btn_set_color.png differ
diff --git a/res/drawable-hdpi/bg_color_btn_mask.png b/res/drawable-hdpi/bg_color_btn_mask.png
new file mode 100644
index 0000000..100db77
Binary files /dev/null and b/res/drawable-hdpi/bg_color_btn_mask.png differ
diff --git a/res/drawable-hdpi/call_record.png b/res/drawable-hdpi/call_record.png
new file mode 100644
index 0000000..fb88ca4
Binary files /dev/null and b/res/drawable-hdpi/call_record.png differ
diff --git a/res/drawable-hdpi/clock.png b/res/drawable-hdpi/clock.png
new file mode 100644
index 0000000..5f2ae9a
Binary files /dev/null and b/res/drawable-hdpi/clock.png differ
diff --git a/res/drawable-hdpi/dropdown_icon.9.png b/res/drawable-hdpi/dropdown_icon.9.png
new file mode 100644
index 0000000..5525025
Binary files /dev/null and b/res/drawable-hdpi/dropdown_icon.9.png differ
diff --git a/res/drawable-hdpi/edit_blue.9.png b/res/drawable-hdpi/edit_blue.9.png
new file mode 100644
index 0000000..55a1856
Binary files /dev/null and b/res/drawable-hdpi/edit_blue.9.png differ
diff --git a/res/drawable-hdpi/edit_green.9.png b/res/drawable-hdpi/edit_green.9.png
new file mode 100644
index 0000000..2cb2d60
Binary files /dev/null and b/res/drawable-hdpi/edit_green.9.png differ
diff --git a/res/drawable-hdpi/edit_red.9.png b/res/drawable-hdpi/edit_red.9.png
new file mode 100644
index 0000000..bae944a
Binary files /dev/null and b/res/drawable-hdpi/edit_red.9.png differ
diff --git a/res/drawable-hdpi/edit_title_blue.9.png b/res/drawable-hdpi/edit_title_blue.9.png
new file mode 100644
index 0000000..96e6092
Binary files /dev/null and b/res/drawable-hdpi/edit_title_blue.9.png differ
diff --git a/res/drawable-hdpi/edit_title_green.9.png b/res/drawable-hdpi/edit_title_green.9.png
new file mode 100644
index 0000000..08d8644
Binary files /dev/null and b/res/drawable-hdpi/edit_title_green.9.png differ
diff --git a/res/drawable-hdpi/edit_title_red.9.png b/res/drawable-hdpi/edit_title_red.9.png
new file mode 100644
index 0000000..9c430e5
Binary files /dev/null and b/res/drawable-hdpi/edit_title_red.9.png differ
diff --git a/res/drawable-hdpi/edit_title_white.9.png b/res/drawable-hdpi/edit_title_white.9.png
new file mode 100644
index 0000000..19e8d95
Binary files /dev/null and b/res/drawable-hdpi/edit_title_white.9.png differ
diff --git a/res/drawable-hdpi/edit_title_yellow.9.png b/res/drawable-hdpi/edit_title_yellow.9.png
new file mode 100644
index 0000000..bf8f580
Binary files /dev/null and b/res/drawable-hdpi/edit_title_yellow.9.png differ
diff --git a/res/drawable-hdpi/edit_white.9.png b/res/drawable-hdpi/edit_white.9.png
new file mode 100644
index 0000000..918f7a6
Binary files /dev/null and b/res/drawable-hdpi/edit_white.9.png differ
diff --git a/res/drawable-hdpi/edit_yellow.9.png b/res/drawable-hdpi/edit_yellow.9.png
new file mode 100644
index 0000000..10cb642
Binary files /dev/null and b/res/drawable-hdpi/edit_yellow.9.png differ
diff --git a/res/drawable-hdpi/font_large.png b/res/drawable-hdpi/font_large.png
new file mode 100644
index 0000000..78cf2e6
Binary files /dev/null and b/res/drawable-hdpi/font_large.png differ
diff --git a/res/drawable-hdpi/font_normal.png b/res/drawable-hdpi/font_normal.png
new file mode 100644
index 0000000..9de7ced
Binary files /dev/null and b/res/drawable-hdpi/font_normal.png differ
diff --git a/res/drawable-hdpi/font_size_selector_bg.9.png b/res/drawable-hdpi/font_size_selector_bg.9.png
new file mode 100644
index 0000000..be8e64c
Binary files /dev/null and b/res/drawable-hdpi/font_size_selector_bg.9.png differ
diff --git a/res/drawable-hdpi/font_small.png b/res/drawable-hdpi/font_small.png
new file mode 100644
index 0000000..d3ff104
Binary files /dev/null and b/res/drawable-hdpi/font_small.png differ
diff --git a/res/drawable-hdpi/font_super.png b/res/drawable-hdpi/font_super.png
new file mode 100644
index 0000000..85b13a1
Binary files /dev/null and b/res/drawable-hdpi/font_super.png differ
diff --git a/res/drawable-hdpi/icon_app.png b/res/drawable-hdpi/icon_app.png
new file mode 100644
index 0000000..418aadc
Binary files /dev/null and b/res/drawable-hdpi/icon_app.png differ
diff --git a/res/drawable-hdpi/list_background.png b/res/drawable-hdpi/list_background.png
new file mode 100644
index 0000000..087e1f9
Binary files /dev/null and b/res/drawable-hdpi/list_background.png differ
diff --git a/res/drawable-hdpi/list_blue_down.9.png b/res/drawable-hdpi/list_blue_down.9.png
new file mode 100644
index 0000000..b88eebf
Binary files /dev/null and b/res/drawable-hdpi/list_blue_down.9.png differ
diff --git a/res/drawable-hdpi/list_blue_middle.9.png b/res/drawable-hdpi/list_blue_middle.9.png
new file mode 100644
index 0000000..96b1c8b
Binary files /dev/null and b/res/drawable-hdpi/list_blue_middle.9.png differ
diff --git a/res/drawable-hdpi/list_blue_single.9.png b/res/drawable-hdpi/list_blue_single.9.png
new file mode 100644
index 0000000..d7e7206
Binary files /dev/null and b/res/drawable-hdpi/list_blue_single.9.png differ
diff --git a/res/drawable-hdpi/list_blue_up.9.png b/res/drawable-hdpi/list_blue_up.9.png
new file mode 100644
index 0000000..632e88c
Binary files /dev/null and b/res/drawable-hdpi/list_blue_up.9.png differ
diff --git a/res/drawable-hdpi/list_folder.9.png b/res/drawable-hdpi/list_folder.9.png
new file mode 100644
index 0000000..829f61b
Binary files /dev/null and b/res/drawable-hdpi/list_folder.9.png differ
diff --git a/res/drawable-hdpi/list_footer_bg.9.png b/res/drawable-hdpi/list_footer_bg.9.png
new file mode 100644
index 0000000..5325c25
Binary files /dev/null and b/res/drawable-hdpi/list_footer_bg.9.png differ
diff --git a/res/drawable-hdpi/list_green_down.9.png b/res/drawable-hdpi/list_green_down.9.png
new file mode 100644
index 0000000..64a39d9
Binary files /dev/null and b/res/drawable-hdpi/list_green_down.9.png differ
diff --git a/res/drawable-hdpi/list_green_middle.9.png b/res/drawable-hdpi/list_green_middle.9.png
new file mode 100644
index 0000000..897325a
Binary files /dev/null and b/res/drawable-hdpi/list_green_middle.9.png differ
diff --git a/res/drawable-hdpi/list_green_single.9.png b/res/drawable-hdpi/list_green_single.9.png
new file mode 100644
index 0000000..c83405f
Binary files /dev/null and b/res/drawable-hdpi/list_green_single.9.png differ
diff --git a/res/drawable-hdpi/list_green_up.9.png b/res/drawable-hdpi/list_green_up.9.png
new file mode 100644
index 0000000..141f9e1
Binary files /dev/null and b/res/drawable-hdpi/list_green_up.9.png differ
diff --git a/res/drawable-hdpi/list_red_down.9.png b/res/drawable-hdpi/list_red_down.9.png
new file mode 100644
index 0000000..4224309
Binary files /dev/null and b/res/drawable-hdpi/list_red_down.9.png differ
diff --git a/res/drawable-hdpi/list_red_middle.9.png b/res/drawable-hdpi/list_red_middle.9.png
new file mode 100644
index 0000000..9988f17
Binary files /dev/null and b/res/drawable-hdpi/list_red_middle.9.png differ
diff --git a/res/drawable-hdpi/list_red_single.9.png b/res/drawable-hdpi/list_red_single.9.png
new file mode 100644
index 0000000..587c348
Binary files /dev/null and b/res/drawable-hdpi/list_red_single.9.png differ
diff --git a/res/drawable-hdpi/list_red_up.9.png b/res/drawable-hdpi/list_red_up.9.png
new file mode 100644
index 0000000..46b4757
Binary files /dev/null and b/res/drawable-hdpi/list_red_up.9.png differ
diff --git a/res/drawable-hdpi/list_white_down.9.png b/res/drawable-hdpi/list_white_down.9.png
new file mode 100644
index 0000000..29f9d8c
Binary files /dev/null and b/res/drawable-hdpi/list_white_down.9.png differ
diff --git a/res/drawable-hdpi/list_white_middle.9.png b/res/drawable-hdpi/list_white_middle.9.png
new file mode 100644
index 0000000..77a4ab4
Binary files /dev/null and b/res/drawable-hdpi/list_white_middle.9.png differ
diff --git a/res/drawable-hdpi/list_white_single.9.png b/res/drawable-hdpi/list_white_single.9.png
new file mode 100644
index 0000000..3e79189
Binary files /dev/null and b/res/drawable-hdpi/list_white_single.9.png differ
diff --git a/res/drawable-hdpi/list_white_up.9.png b/res/drawable-hdpi/list_white_up.9.png
new file mode 100644
index 0000000..e23cd5c
Binary files /dev/null and b/res/drawable-hdpi/list_white_up.9.png differ
diff --git a/res/drawable-hdpi/list_yellow_down.9.png b/res/drawable-hdpi/list_yellow_down.9.png
new file mode 100644
index 0000000..31cfc1e
Binary files /dev/null and b/res/drawable-hdpi/list_yellow_down.9.png differ
diff --git a/res/drawable-hdpi/list_yellow_middle.9.png b/res/drawable-hdpi/list_yellow_middle.9.png
new file mode 100644
index 0000000..b6549b2
Binary files /dev/null and b/res/drawable-hdpi/list_yellow_middle.9.png differ
diff --git a/res/drawable-hdpi/list_yellow_single.9.png b/res/drawable-hdpi/list_yellow_single.9.png
new file mode 100644
index 0000000..3faf507
Binary files /dev/null and b/res/drawable-hdpi/list_yellow_single.9.png differ
diff --git a/res/drawable-hdpi/list_yellow_up.9.png b/res/drawable-hdpi/list_yellow_up.9.png
new file mode 100644
index 0000000..4ae791c
Binary files /dev/null and b/res/drawable-hdpi/list_yellow_up.9.png differ
diff --git a/res/drawable-hdpi/menu_delete.png b/res/drawable-hdpi/menu_delete.png
new file mode 100644
index 0000000..ccdfc4b
Binary files /dev/null and b/res/drawable-hdpi/menu_delete.png differ
diff --git a/res/drawable-hdpi/menu_move.png b/res/drawable-hdpi/menu_move.png
new file mode 100644
index 0000000..1140b71
Binary files /dev/null and b/res/drawable-hdpi/menu_move.png differ
diff --git a/res/drawable-hdpi/new_note_normal.png b/res/drawable-hdpi/new_note_normal.png
new file mode 100644
index 0000000..e24e0d1
Binary files /dev/null and b/res/drawable-hdpi/new_note_normal.png differ
diff --git a/res/drawable-hdpi/new_note_pressed.png b/res/drawable-hdpi/new_note_pressed.png
new file mode 100644
index 0000000..c748936
Binary files /dev/null and b/res/drawable-hdpi/new_note_pressed.png differ
diff --git a/res/drawable-hdpi/note_edit_color_selector_panel.png b/res/drawable-hdpi/note_edit_color_selector_panel.png
new file mode 100644
index 0000000..fc49552
Binary files /dev/null and b/res/drawable-hdpi/note_edit_color_selector_panel.png differ
diff --git a/res/drawable-hdpi/notification.png b/res/drawable-hdpi/notification.png
new file mode 100644
index 0000000..b13ab4a
Binary files /dev/null and b/res/drawable-hdpi/notification.png differ
diff --git a/res/drawable-hdpi/search_result.png b/res/drawable-hdpi/search_result.png
new file mode 100644
index 0000000..ff2befd
Binary files /dev/null and b/res/drawable-hdpi/search_result.png differ
diff --git a/res/drawable-hdpi/selected.png b/res/drawable-hdpi/selected.png
new file mode 100644
index 0000000..b889bef
Binary files /dev/null and b/res/drawable-hdpi/selected.png differ
diff --git a/res/drawable-hdpi/title_alert.png b/res/drawable-hdpi/title_alert.png
new file mode 100644
index 0000000..544ee9c
Binary files /dev/null and b/res/drawable-hdpi/title_alert.png differ
diff --git a/res/drawable-hdpi/title_bar_bg.9.png b/res/drawable-hdpi/title_bar_bg.9.png
new file mode 100644
index 0000000..eb6bff0
Binary files /dev/null and b/res/drawable-hdpi/title_bar_bg.9.png differ
diff --git a/res/drawable-hdpi/widget_2x_blue.png b/res/drawable-hdpi/widget_2x_blue.png
new file mode 100644
index 0000000..a1707f4
Binary files /dev/null and b/res/drawable-hdpi/widget_2x_blue.png differ
diff --git a/res/drawable-hdpi/widget_2x_green.png b/res/drawable-hdpi/widget_2x_green.png
new file mode 100644
index 0000000..f86886c
Binary files /dev/null and b/res/drawable-hdpi/widget_2x_green.png differ
diff --git a/res/drawable-hdpi/widget_2x_red.png b/res/drawable-hdpi/widget_2x_red.png
new file mode 100644
index 0000000..0e66c29
Binary files /dev/null and b/res/drawable-hdpi/widget_2x_red.png differ
diff --git a/res/drawable-hdpi/widget_2x_white.png b/res/drawable-hdpi/widget_2x_white.png
new file mode 100644
index 0000000..5f0619a
Binary files /dev/null and b/res/drawable-hdpi/widget_2x_white.png differ
diff --git a/res/drawable-hdpi/widget_2x_yellow.png b/res/drawable-hdpi/widget_2x_yellow.png
new file mode 100644
index 0000000..12d1c2b
Binary files /dev/null and b/res/drawable-hdpi/widget_2x_yellow.png differ
diff --git a/res/drawable-hdpi/widget_4x_blue.png b/res/drawable-hdpi/widget_4x_blue.png
new file mode 100644
index 0000000..9183738
Binary files /dev/null and b/res/drawable-hdpi/widget_4x_blue.png differ
diff --git a/res/drawable-hdpi/widget_4x_green.png b/res/drawable-hdpi/widget_4x_green.png
new file mode 100644
index 0000000..fa8b452
Binary files /dev/null and b/res/drawable-hdpi/widget_4x_green.png differ
diff --git a/res/drawable-hdpi/widget_4x_red.png b/res/drawable-hdpi/widget_4x_red.png
new file mode 100644
index 0000000..62de074
Binary files /dev/null and b/res/drawable-hdpi/widget_4x_red.png differ
diff --git a/res/drawable-hdpi/widget_4x_white.png b/res/drawable-hdpi/widget_4x_white.png
new file mode 100644
index 0000000..a37d67c
Binary files /dev/null and b/res/drawable-hdpi/widget_4x_white.png differ
diff --git a/res/drawable-hdpi/widget_4x_yellow.png b/res/drawable-hdpi/widget_4x_yellow.png
new file mode 100644
index 0000000..d7c5fa4
Binary files /dev/null and b/res/drawable-hdpi/widget_4x_yellow.png differ
diff --git a/res/drawable/new_note.xml b/res/drawable/new_note.xml
new file mode 100644
index 0000000..2154ebc
--- /dev/null
+++ b/res/drawable/new_note.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/res/layout/account_dialog_title.xml b/res/layout/account_dialog_title.xml
new file mode 100644
index 0000000..7717112
--- /dev/null
+++ b/res/layout/account_dialog_title.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/add_account_text.xml b/res/layout/add_account_text.xml
new file mode 100644
index 0000000..c799178
--- /dev/null
+++ b/res/layout/add_account_text.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/datetime_picker.xml b/res/layout/datetime_picker.xml
new file mode 100644
index 0000000..f10d592
--- /dev/null
+++ b/res/layout/datetime_picker.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/dialog_edit_text.xml b/res/layout/dialog_edit_text.xml
new file mode 100644
index 0000000..361b39a
--- /dev/null
+++ b/res/layout/dialog_edit_text.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/folder_list_item.xml b/res/layout/folder_list_item.xml
new file mode 100644
index 0000000..77e8148
--- /dev/null
+++ b/res/layout/folder_list_item.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/note_edit.xml b/res/layout/note_edit.xml
new file mode 100644
index 0000000..3ebe56c
--- /dev/null
+++ b/res/layout/note_edit.xml
@@ -0,0 +1,411 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/note_edit_list_item.xml b/res/layout/note_edit_list_item.xml
new file mode 100644
index 0000000..6497c25
--- /dev/null
+++ b/res/layout/note_edit_list_item.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/note_item.xml b/res/layout/note_item.xml
new file mode 100644
index 0000000..eb899ed
--- /dev/null
+++ b/res/layout/note_item.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/note_list.xml b/res/layout/note_list.xml
new file mode 100644
index 0000000..63cf765
--- /dev/null
+++ b/res/layout/note_list.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/note_list_dropdown_menu.xml b/res/layout/note_list_dropdown_menu.xml
new file mode 100644
index 0000000..3fa271d
--- /dev/null
+++ b/res/layout/note_list_dropdown_menu.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/note_list_footer.xml b/res/layout/note_list_footer.xml
new file mode 100644
index 0000000..5ca7b22
--- /dev/null
+++ b/res/layout/note_list_footer.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/settings_header.xml b/res/layout/settings_header.xml
new file mode 100644
index 0000000..5eb8c50
--- /dev/null
+++ b/res/layout/settings_header.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/widget_2x.xml b/res/layout/widget_2x.xml
new file mode 100644
index 0000000..55970ce
--- /dev/null
+++ b/res/layout/widget_2x.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
diff --git a/res/layout/widget_4x.xml b/res/layout/widget_4x.xml
new file mode 100644
index 0000000..dc9bb51
--- /dev/null
+++ b/res/layout/widget_4x.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/res/menu/call_note_edit.xml b/res/menu/call_note_edit.xml
new file mode 100644
index 0000000..02c0528
--- /dev/null
+++ b/res/menu/call_note_edit.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
diff --git a/res/menu/call_record_folder.xml b/res/menu/call_record_folder.xml
new file mode 100644
index 0000000..c664346
--- /dev/null
+++ b/res/menu/call_record_folder.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/res/menu/note_edit.xml b/res/menu/note_edit.xml
new file mode 100644
index 0000000..42440a1
--- /dev/null
+++ b/res/menu/note_edit.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/menu/note_list.xml b/res/menu/note_list.xml
new file mode 100644
index 0000000..42ea736
--- /dev/null
+++ b/res/menu/note_list.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
diff --git a/res/menu/note_list_dropdown.xml b/res/menu/note_list_dropdown.xml
new file mode 100644
index 0000000..7cbaadc
--- /dev/null
+++ b/res/menu/note_list_dropdown.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/menu/note_list_options.xml b/res/menu/note_list_options.xml
new file mode 100644
index 0000000..04a00b9
--- /dev/null
+++ b/res/menu/note_list_options.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/menu/sub_folder.xml b/res/menu/sub_folder.xml
new file mode 100644
index 0000000..b00de26
--- /dev/null
+++ b/res/menu/sub_folder.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/raw-zh-rCN/introduction b/res/raw-zh-rCN/introduction
new file mode 100644
index 0000000..7188359
--- /dev/null
+++ b/res/raw-zh-rCN/introduction
@@ -0,0 +1,7 @@
+欢迎使用MIUI便签!
+
+ 无论从软件中直接添加,还是从桌面拖出widget,MIUI便签能让你快速建立和保存便签;
+
+ 除了调整文字大小、便签背景、文件夹等基础功能外,你会发现MIUI便签也提供了清单模式、便签提醒、软件加密、导出到SD卡、同步google task的高级功能,让你的生活记录更加美好和安全;
+
+ 来分享你的使用体验吧:http://www.miui.com/index.php
diff --git a/res/raw/introduction b/res/raw/introduction
new file mode 100644
index 0000000..269cf7b
--- /dev/null
+++ b/res/raw/introduction
@@ -0,0 +1 @@
+Welcome to use MIUI notes!
\ No newline at end of file
diff --git a/res/values-zh-rCN/arrays.xml b/res/values-zh-rCN/arrays.xml
new file mode 100644
index 0000000..114e52e
--- /dev/null
+++ b/res/values-zh-rCN/arrays.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..07915bb
--- /dev/null
+++ b/res/values-zh-rCN/strings.xml
@@ -0,0 +1,119 @@
+
+
+
+
+
+ 便签
+ 便签2x2
+ 便签4x4
+ 没有关联内容,点击新建便签。
+ 访客模式下,便签内容不可见
+ ...
+ 新建便签
+ 已过期
+ yyyyMMdd
+ MM月dd日 kk:mm
+ 知道了
+ 查看
+ 呼叫电话
+ 发送邮件
+ 浏览网页
+ 打开地图
+
+ 新建文件夹
+ 导出文本
+ 同步
+ 取消同步
+ 设置
+ 搜索
+ 删除
+ 移动到文件夹
+ 选中了 %d 项
+ 没有选中项,操作无效
+ 全选
+ 取消全选
+ 文字大小
+ 小
+ 正常
+ 大
+ 超大
+ 进入清单模式
+ 退出清单模式
+ 查看文件夹
+ 刪除文件夹
+ 修改文件夹名称
+ 文件夹 %1$s 已存在,请重新命名
+ 分享
+ 发送到桌面
+ 提醒我
+ 删除提醒
+ 选择文件夹
+ 上一级文件夹
+ 已添加到桌面
+ 删除
+ 确认要删除所选的 %d 条便签吗?
+ 确认要删除该条便签吗?
+ 确认删除文件夹及所包含的便签吗?
+ 已将所选 %1$d 条便签移到 %2$s 文件夹
+
+ SD卡被占用,不能操作
+ 导出文本时发生错误,请检查SD卡
+ 要查看的便签不存在
+ 不能为空便签设置闹钟提醒
+ 不能将空便签发送到桌面
+ 导出成功
+ 导出失败
+ 已将文本文件(%1$s)输出至SD卡(%2$s)目录
+
+ 同步便签...
+ 同步成功
+ 同步失败
+ 同步已取消
+ 与%1$s同步成功
+ 同步失败,请检查网络和帐号设置
+ 同步失败,发生内部错误
+ 同步已取消
+ 登录%1$s...
+ 正在获取服务器便签列表...
+ 正在同步本地便签...
+
+ 设置
+ 同步账号
+ 与google task同步便签记录
+ 上次同步于 %1$s
+ 添加账号
+ 更换账号
+ 删除账号
+ 取消
+ 立即同步
+ 取消同步
+ 当前帐号 %1$s
+ 如更换同步帐号,过去的帐号同步信息将被清空,再次切换的同时可能会造成数据重复
+ 同步便签
+ 请选择google帐号,便签将与该帐号的google task内容同步。
+ 正在同步中,不能修改同步帐号
+ 同步帐号已设置为%1$s
+ 新建便签背景颜色随机
+ 通话便签
+ 请输入名称
+ 正在搜索便签
+ 搜索便签
+ 便签中的文字
+ 设置
+ 取消
+
+
diff --git a/res/values-zh-rTW/arrays.xml b/res/values-zh-rTW/arrays.xml
new file mode 100644
index 0000000..114e52e
--- /dev/null
+++ b/res/values-zh-rTW/arrays.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..059f157
--- /dev/null
+++ b/res/values-zh-rTW/strings.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+ 便簽
+ 便簽2x2
+ 便簽4x4
+ 沒有關聯內容,點擊新建便簽。
+ 訪客模式下,便籤內容不可見
+ ...
+ 新建便簽
+ 已過期
+ yyyyMMdd
+ MM月dd日 kk:mm
+ 知道了
+ 查看
+ 呼叫電話
+ 發送郵件
+ 浏覽網頁
+ 打開地圖
+ 已將所選 %1$d 便籤移到 %2$s 文件夾
+
+ 新建文件夾
+ 導出文本
+ 同步
+ 取消同步
+ 設置
+ 搜尋
+ 刪除
+ 移動到文件夾
+ 選中了 %d 項
+ 沒有選中項,操作無效
+ 全選
+ 取消全選
+ 文字大小
+ 小
+ 正常
+ 大
+ 超大
+ 進入清單模式
+ 退出清單模式
+ 查看文件夾
+ 刪除文件夾
+ 修改文件夾名稱
+ 文件夾 %1$s 已存在,請重新命名
+ 分享
+ 發送到桌面
+ 提醒我
+ 刪除提醒
+ 選擇文件夾
+ 上一級文件夾
+ 已添加到桌面
+ 刪除
+ 确认要刪除所選的 %d 條便籤嗎?
+ 确认要删除該條便籤嗎?
+ 確認刪除檔夾及所包含的便簽嗎?
+ SD卡被佔用,不能操作
+ 導出TXT時發生錯誤,請檢查SD卡
+ 要查看的便籤不存在
+ 不能爲空便籤設置鬧鐘提醒
+ 不能將空便籤發送到桌面
+ 導出成功
+ 導出失敗
+ 已將文本文件(%1$s)導出至SD(%2$s)目錄
+
+ 同步便簽...
+ 同步成功
+ 同步失敗
+ 同步已取消
+ 與%1$s同步成功
+ 同步失敗,請檢查網絡和帳號設置
+ 同步失敗,發生內部錯誤
+ 同步已取消
+ 登陸%1$s...
+ 正在獲取服務器便籤列表...
+ 正在同步本地便籤...
+
+ 設置
+ 同步賬號
+ 与google task同步便簽記錄
+ 上次同步于 %1$s
+ 添加賬號
+ 更換賬號
+ 刪除賬號
+ 取消
+ 立即同步
+ 取消同步
+ 當前帳號 %1$s
+ 如更換同步帳號,過去的帳號同步信息將被清空,再次切換的同時可能會造成數據重復
+ 同步便簽
+ 請選擇google帳號,便簽將與該帳號的google task內容同步。
+ 正在同步中,不能修改同步帳號
+ 同步帳號已設置為%1$s
+ 新建便籤背景顏色隨機
+
+ 通話便籤
+ 請輸入名稱
+
+ 正在搜索便籤
+ 搜索便籤
+ 便籤中的文字
+ 設置
+ 取消
+
+
diff --git a/res/values-zh/strings.xml b/res/values-zh/strings.xml
new file mode 100644
index 0000000..959840d
--- /dev/null
+++ b/res/values-zh/strings.xml
@@ -0,0 +1,137 @@
+
+
+
+ 便签
+ 便签 2x2
+ 便签 4x4
+
+
+ 未找到关联便签,点击创建关联便签。
+ 隐私模式,无法查看便签内容
+ ...
+ 新建便签
+
+
+ 已过期
+ yyyyMMdd
+ MMMd kk:mm
+ 知道了
+ 查看
+
+
+ 拨号
+ 发送邮件
+ 浏览网页
+ 打开地图
+
+
+ /MIUI/notes/
+ notes_%s.txt
+
+
+ (%d)
+ 新建文件夹
+ 导出文本
+ 同步
+ 取消同步
+ 设置
+ 搜索
+ 置顶
+ 取消置顶
+ 删除
+ 移动到文件夹
+ 已选择 %d 项
+ 未选择任何项,操作无效
+ 全选
+ 取消全选
+ 批量选择
+
+
+ 字体大小
+ 小
+ 中
+ 大
+ 超大
+
+
+ 进入清单模式
+ 退出清单模式
+
+
+ 查看文件夹
+ 删除文件夹
+ 重命名文件夹
+ 文件夹 %1$s 已存在,请重新命名
+
+
+ 分享
+ 发送到桌面
+ 提醒我
+ 删除提醒
+ 插入图片
+ 选择文件夹
+ 父文件夹
+ 便签已添加到桌面
+
+
+ 确认删除文件夹及其包含的便签?
+ 删除选择的便签
+ 确认删除选择的 %d 个便签?
+ 确认删除此便签?
+ 已将选择的 %1$d 个便签移动到 %2$s 文件夹
+
+
+ SD卡正忙,暂不可用
+ 导出失败,请检查SD卡
+ 便签不存在
+ 抱歉,不能为空便签设置提醒
+ 抱歉,不能将空便签发送到桌面
+ 导出成功
+ 导出失败
+ 已将文本文件 (%1$s) 导出到SD卡 (%2$s) 目录
+
+
+ 正在同步便签...
+ 同步成功
+ 同步失败
+ 同步已取消
+ 已成功与账户 %1$s 同步
+ 同步失败,请检查网络和账户设置
+ 同步失败,发生内部错误
+ 同步已取消
+ 正在登录 %1$s...
+ 正在获取远程便签列表...
+ 正在将本地便签与Google Task同步...
+
+
+ 设置
+ 同步账户
+ 将便签与Google Task同步
+ 上次同步时间 %1$s
+ yyyy-MM-dd hh:mm:ss
+ 添加账户
+ 更改同步账户
+ 移除同步账户
+ 取消
+ 立即同步
+ 取消同步
+ 当前账户 %1$s
+ 将删除所有同步相关信息,可能会导致某些项目重复
+ 同步便签
+ 请选择一个Google账户。本地便签将与Google Task同步。
+ 无法更改账户,因为同步正在进行中
+ %1$s 已被设置为同步账户
+ 新便签背景颜色随机
+
+
+ 通话便签
+ 输入名称
+ 搜索便签
+ 搜索便签
+ 便签中的文本
+ 搜索历史
+ 设置
+ 取消
+
+
+
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
new file mode 100644
index 0000000..62336e5
--- /dev/null
+++ b/res/values/arrays.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+ - -%s
+
+
+ - --%s
+
+
+ - --%s
+
+
+ - --%s
+
+
+
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
new file mode 100644
index 0000000..2b72ca2
--- /dev/null
+++ b/res/values/colors.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+ #335b5b5b
+
+
+ #ffffff
+
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
new file mode 100644
index 0000000..fd60fb0
--- /dev/null
+++ b/res/values/dimens.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+ 33sp
+
+
+ 26sp
+
+
+ 20sp
+
+
+ 17sp
+
+
+ 14sp
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..6cc899d
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,135 @@
+
+
+
+ Notes
+ Notes 2x2
+ Notes 4x4
+
+
+ No associated note found, click to create an associated note.
+ Privacy mode, cannot view note content
+ ...
+ New Note
+
+
+ Expired
+ yyyyMMdd
+ MMMd kk:mm
+ OK
+ View
+
+
+ Call
+ Send Email
+ Browse Web
+ Open Map
+
+
+ /MIUI/notes/
+ notes_%s.txt
+
+
+ (%d)
+ New Folder
+ Export Text
+ Sync
+ Cancel Sync
+ Settings
+ Search
+ Pin
+ Unpin
+ Delete
+ Move to Folder
+ Selected %d items
+ No items selected, operation invalid
+ Select All
+ Deselect All
+ Batch Select
+
+
+ Font Size
+ Small
+ Medium
+ Large
+ Extra Large
+
+
+ Enter List Mode
+ Exit List Mode
+
+
+ View Folder
+ Delete Folder
+ Rename Folder
+ Folder %1$s already exists, please rename
+
+
+ Share
+ Send to Desktop
+ Remind Me
+ Remove Reminder
+ Insert Image
+ Select Folder
+ Parent Folder
+ Note added to desktop
+
+
+ Confirm delete folder and its notes?
+ Delete Selected Notes
+ Confirm delete selected %d notes?
+ Confirm delete this note?
+ Moved selected %1$d notes to %2$s folder
+
+
+ SD card is busy, temporarily unavailable
+ Export failed, please check SD card
+ Note does not exist
+ Sorry, cannot set reminder for empty note
+ Sorry, cannot send empty note to desktop
+ Export successful
+ Export failed
+ Exported text file (%1$s) to SD card (%2$s) directory
+
+
+ Syncing notes...
+ Sync successful
+ Sync failed
+ Sync cancelled
+ Successfully synced with account %1$s
+ Sync failed, please check network and account settings
+ Sync failed, internal error occurred
+ Sync cancelled
+ Logging in to %1$s...
+ Retrieving remote notes list...
+ Syncing local notes with Google Task...
+
+
+ Settings
+ Sync Account
+ Sync notes with Google Task
+ Last sync time %1$s
+ yyyy-MM-dd hh:mm:ss
+ Add Account
+ Change Sync Account
+ Remove Sync Account
+ Cancel
+ Sync Now
+ Cancel Sync
+ Current account %1$s
+ All sync-related information will be deleted, which may cause some items to be duplicated
+ Sync Notes
+ Please select a Google account. Local notes will be synced with Google Task.
+ Cannot change account because sync is in progress
+ %1$s has been set as the sync account
+ New note background color random
+
+
+ Call Notes
+ Enter name
+ Search Notes
+ Search notes
+ Text in notes
+ Search History
+ Set
+ Cancel
+
\ No newline at end of file
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100644
index 0000000..eebb6bc
--- /dev/null
+++ b/res/values/styles.xml
@@ -0,0 +1,310 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
new file mode 100644
index 0000000..e139868
--- /dev/null
+++ b/res/xml/preferences.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
new file mode 100644
index 0000000..f2e0bab
--- /dev/null
+++ b/res/xml/searchable.xml
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/widget_2x_info.xml b/res/xml/widget_2x_info.xml
new file mode 100644
index 0000000..b079004
--- /dev/null
+++ b/res/xml/widget_2x_info.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/widget_4x_info.xml b/res/xml/widget_4x_info.xml
new file mode 100644
index 0000000..a827879
--- /dev/null
+++ b/res/xml/widget_4x_info.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/notes/data/Notes.java b/src/notes/data/Notes.java
index 1592d5d..fa5943b 100644
--- a/src/notes/data/Notes.java
+++ b/src/notes/data/Notes.java
@@ -59,7 +59,6 @@ public class Notes {
* {@link Notes#ID_ROOT_FOLDER }:根文件夹(默认文件夹)
* {@link Notes#ID_TEMPARAY_FOLDER }:临时文件夹(存放无归属的笔记)
* {@link Notes#ID_CALL_RECORD_FOLDER}:通话记录文件夹(专门存储通话记录笔记)
- * {@link Notes#ID_TRASH_FOLER}:回收站文件夹(存放被删除的笔记/文件夹)
*/
// 根文件夹ID(默认文件夹,所有无指定文件夹的笔记默认归属此文件夹)
public static final int ID_ROOT_FOLDER = 0;
@@ -67,7 +66,7 @@ public class Notes {
public static final int ID_TEMPARAY_FOLDER = -1;
// 通话记录文件夹ID(专门存储通话记录类型的笔记)
public static final int ID_CALL_RECORD_FOLDER = -2;
- // 回收站文件夹ID(存放被用户删除的笔记或文件夹)
+ // 回收站文件夹ID(已废弃,用于兼容旧代码)
public static final int ID_TRASH_FOLER = -3;
/**
@@ -207,6 +206,12 @@ public class Notes {
* 数据类型: INTEGER
*/
public static final String TYPE = "type";
+
+ /**
+ * 笔记是否置顶(0:不置顶,1:置顶)
+ * 数据类型: INTEGER
+ */
+ public static final String PINNED = "pinned";
/**
* 最后一次同步的ID(用于GTask同步,标记同步状态)
@@ -220,6 +225,8 @@ public class Notes {
*/
public static final String LOCAL_MODIFIED = "local_modified";
+
+
/**
* 移动到临时文件夹前的原始父级ID(用于恢复笔记的原始归属文件夹)
* 数据类型: INTEGER (long)
@@ -381,4 +388,6 @@ public class Notes {
*/
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
}
+
+
}
\ No newline at end of file
diff --git a/src/notes/data/NotesDatabaseHelper.java b/src/notes/data/NotesDatabaseHelper.java
index 516988f..743abac 100644
--- a/src/notes/data/NotesDatabaseHelper.java
+++ b/src/notes/data/NotesDatabaseHelper.java
@@ -45,12 +45,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
/**
- * 数据库版本号,用于版本升级控制(当前为4)
+ * 数据库版本号,用于版本升级控制(当前为6,增加了标签功能)
*/
- private static final int DB_VERSION = 4;
+ private static final int DB_VERSION = 6;
/**
- * 数据表名称接口,定义note表和data表的名称常量,提高代码可读性
+ * 数据表名称接口,定义note表、data表、标签表和便签-标签关联表的名称常量
*/
public interface TABLE {
// 笔记/文件夹表名称
@@ -90,6 +90,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + // 文件夹下的笔记数量
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + // 文件夹名称/笔记摘要
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + // 类型(笔记/文件夹/系统)
+ NoteColumns.PINNED + " INTEGER NOT NULL DEFAULT 0," + // 是否置顶(0:不置顶,1:置顶)
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + // 关联的Widget ID
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + // 关联的Widget类型
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + // 同步ID(GTask)
@@ -122,10 +123,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
* 创建data表的NOTE_ID索引的SQL语句
* 索引用于提升根据NOTE_ID查询data表的性能(频繁关联查询场景)
*/
- private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
- "CREATE INDEX IF NOT EXISTS note_id_index ON " +
+ private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
+ "CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
+
+
// ====================== 数据库触发器SQL语句(note表) ======================
/**
* 触发器:更新笔记的父级ID时,增加新文件夹的笔记数量
@@ -255,20 +258,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
- /**
- * 触发器:将文件夹移至回收站时,同步移动该文件夹下的所有笔记至回收站
- * 触发时机:note表的PARENT_ID更新为回收站ID后
- * 逻辑:将该文件夹下的所有笔记的PARENT_ID设为回收站ID
- */
- private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
- "CREATE TRIGGER folder_move_notes_on_trash " +
- " AFTER UPDATE ON " + TABLE.NOTE +
- " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
- " BEGIN" +
- " UPDATE " + TABLE.NOTE +
- " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
- " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
- " END";
+
/**
* 构造方法,调用父类SQLiteOpenHelper的构造方法初始化数据库
@@ -308,7 +298,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete");
- db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash");
// 创建新触发器
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
@@ -317,7 +306,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
- db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
/**
@@ -352,13 +340,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
- /**
- * 4. 回收站文件夹:存储被删除的笔记和文件夹
- */
- values.clear();
- values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
- values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
- db.insert(TABLE.NOTE, null, values);
+
}
/**
@@ -376,6 +358,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
Log.d(TAG, "data table has been created");
}
+
+
/**
* 重新创建data表的所有触发器(先删除旧触发器,再创建新触发器)
*
@@ -454,6 +438,16 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
upgradeToV4(db);
oldVersion++;
}
+
+ // 从版本4升级到版本5
+ if (oldVersion == 4) {
+ // 为note表添加pinned字段(用于置顶功能)
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.PINNED
+ + " INTEGER NOT NULL DEFAULT 0");
+ oldVersion++;
+ }
+
+
// 如果需要,重建触发器
if (reCreateTriggers) {
@@ -468,6 +462,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
}
}
+
+
/**
* 从版本1升级到版本2的逻辑
* 删除旧表,重新创建新表(全量重建,会丢失数据,适用于早期版本)
@@ -486,8 +482,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* 从版本2升级到版本3的逻辑
* 1. 删除无用的触发器;
- * 2. 为note表添加GTASK_ID列;
- * 3. 新增回收站系统文件夹。
+ * 2. 为note表添加GTASK_ID列。
*
* @param db SQLiteDatabase对象
*/
@@ -499,11 +494,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
// 为note表添加GTASK_ID列(用于GTask同步)
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
+ " TEXT NOT NULL DEFAULT ''");
- // 新增回收站系统文件夹
- ContentValues values = new ContentValues();
- values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
- values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
- db.insert(TABLE.NOTE, null, values);
}
/**
diff --git a/src/notes/data/NotesProvider.java b/src/notes/data/NotesProvider.java
index e0c01d2..392cae6 100644
--- a/src/notes/data/NotesProvider.java
+++ b/src/notes/data/NotesProvider.java
@@ -30,6 +30,7 @@ import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.R;
+import net.micode.notes.tool.SearchHistoryManager;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
@@ -91,6 +92,7 @@ public class NotesProvider extends ContentProvider {
*/
private static final int URI_SEARCH_SUGGEST = 6;
+
/**
* 静态代码块:初始化UriMatcher,添加Uri匹配规则
* 规则格式:authority(授权名) + path(路径) -> 匹配类型常量
@@ -112,6 +114,7 @@ public class NotesProvider extends ContentProvider {
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
// 匹配搜索建议(带关键词):content://micode_notes/suggestions/query/关键词 -> URI_SEARCH_SUGGEST
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
+
}
/**
@@ -217,22 +220,81 @@ public class NotesProvider extends ContentProvider {
searchString = uri.getQueryParameter("pattern");
}
- // 关键词为空时返回null
- if (TextUtils.isEmpty(searchString)) {
- return null;
- }
-
- try {
- // 拼接SQL的LIKE关键词(%表示任意字符,如%笔记%)
- searchString = String.format("%%%s%%", searchString);
- // 执行原生SQL查询,获取搜索结果
- c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
- new String[] { searchString });
- } catch (IllegalStateException ex) {
- // 捕获异常,输出错误日志
- Log.e(TAG, "got exception: " + ex.toString());
+ // 如果是搜索建议类型,且搜索关键词不为空,返回合并结果
+ if (mMatcher.match(uri) == URI_SEARCH_SUGGEST && !TextUtils.isEmpty(searchString)) {
+ try {
+ // 1. 获取搜索历史记录
+ SearchHistoryManager historyManager = SearchHistoryManager.getInstance(getContext());
+ java.util.List historyList = historyManager.getSearchHistoryList();
+
+ // 2. 获取便签搜索结果
+ String likeSearchString = String.format("%%%s%%", searchString);
+ Cursor noteCursor = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, new String[] { likeSearchString });
+
+ // 3. 创建矩阵游标,用于合并结果
+ String[] columns = { NoteColumns.ID, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
+ SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_TEXT_2,
+ SearchManager.SUGGEST_COLUMN_ICON_1, SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
+ SearchManager.SUGGEST_COLUMN_INTENT_DATA };
+ android.database.MatrixCursor matrixCursor = new android.database.MatrixCursor(columns);
+
+ // 4. 添加搜索历史记录(只添加匹配的历史)
+ for (String history : historyList) {
+ if (history.toLowerCase().contains(searchString.toLowerCase())) {
+ matrixCursor.addRow(new Object[] {
+ -1, // ID为-1表示是历史记录
+ history, // 历史记录作为Intent Extra数据
+ history, // 显示的文本1
+ getContext().getString(R.string.search_history), // 显示的文本2
+ R.drawable.search_result, // 图标
+ Intent.ACTION_SEARCH, // Intent动作
+ Notes.TextNote.CONTENT_TYPE // Intent数据类型
+ });
+ }
+ }
+
+ // 5. 添加便签搜索结果
+ if (noteCursor != null && noteCursor.moveToFirst()) {
+ do {
+ // 从便签搜索结果中获取列数据
+ long noteId = noteCursor.getLong(noteCursor.getColumnIndexOrThrow(NoteColumns.ID));
+ String extraData = noteCursor.getString(noteCursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA));
+ String text1 = noteCursor.getString(noteCursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1));
+ String text2 = noteCursor.getString(noteCursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_2));
+ int icon = noteCursor.getInt(noteCursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_ICON_1));
+ String action = noteCursor.getString(noteCursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_INTENT_ACTION));
+ String data = noteCursor.getString(noteCursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_INTENT_DATA));
+
+ matrixCursor.addRow(new Object[] { noteId, extraData, text1, text2, icon, action, data });
+ } while (noteCursor.moveToNext());
+ }
+
+ // 6. 关闭便签搜索结果游标
+ if (noteCursor != null) {
+ noteCursor.close();
+ }
+
+ // 7. 设置矩阵游标为结果
+ c = matrixCursor;
+ } catch (IllegalStateException ex) {
+ // 捕获异常,输出错误日志
+ Log.e(TAG, "got exception: " + ex.toString());
+ }
+ } else if (!TextUtils.isEmpty(searchString)) {
+ // 普通搜索或搜索建议但关键词为空,只返回便签搜索结果
+ try {
+ // 拼接SQL的LIKE关键词(%表示任意字符,如%笔记%)
+ searchString = String.format("%%%s%%", searchString);
+ // 执行原生SQL查询,获取搜索结果
+ c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
+ new String[] { searchString });
+ } catch (IllegalStateException ex) {
+ // 捕获异常,输出错误日志
+ Log.e(TAG, "got exception: " + ex.toString());
+ }
}
break;
+
default:
// 未知Uri,抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
@@ -275,6 +337,7 @@ public class NotesProvider extends ContentProvider {
// 插入data表,获取插入的ID
insertedId = dataId = db.insert(TABLE.DATA, null, values);
break;
+
default:
// 未知Uri,抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
@@ -292,6 +355,8 @@ public class NotesProvider extends ContentProvider {
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
+
+
// 返回包含插入ID的新Uri
return ContentUris.withAppendedId(uri, insertedId);
}
@@ -311,11 +376,12 @@ public class NotesProvider extends ContentProvider {
// 获取可写的SQLiteDatabase对象
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false; // 标记是否删除的是data表数据
+ long noteId = 0; // 用于存储便签ID,以便发送通知
// 根据Uri匹配的类型执行删除逻辑
switch (mMatcher.match(uri)) {
case URI_NOTE:
- // 删除note表数据,条件:传入的selection + ID>0(排除系统文件夹)
+ // 直接删除便签,条件:传入的selection + ID>0(排除系统文件夹)
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
@@ -325,13 +391,12 @@ public class NotesProvider extends ContentProvider {
/**
* ID小于等于0的是系统文件夹,不允许删除
*/
- long noteId = Long.valueOf(id);
+ noteId = Long.valueOf(id);
if (noteId <= 0) {
break;
}
- // 删除note表单条数据,条件:ID=id + 传入的selection
- count = db.delete(TABLE.NOTE,
- NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
+ // 直接删除便签,条件:ID=id + 传入的selection
+ count = db.delete(TABLE.NOTE, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break;
case URI_DATA:
// 删除data表数据
@@ -345,6 +410,9 @@ public class NotesProvider extends ContentProvider {
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
break;
+
+
+
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
@@ -355,6 +423,11 @@ public class NotesProvider extends ContentProvider {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
+ // 如果是便签相关操作,通知对应的便签Uri
+ if (noteId > 0) {
+ getContext().getContentResolver().notifyChange(
+ ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
+ }
// 通知当前Uri的数据变更
getContext().getContentResolver().notifyChange(uri, null);
}
@@ -377,6 +450,7 @@ public class NotesProvider extends ContentProvider {
// 获取可写的SQLiteDatabase对象
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false; // 标记是否更新的是data表数据
+ long noteId = 0; // 用于存储便签ID,以便发送通知
// 根据Uri匹配的类型执行更新逻辑
switch (mMatcher.match(uri)) {
@@ -405,6 +479,9 @@ public class NotesProvider extends ContentProvider {
+ parseSelection(selection), selectionArgs);
updateData = true;
break;
+
+
+
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
@@ -415,6 +492,11 @@ public class NotesProvider extends ContentProvider {
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
+ // 如果是便签相关操作,通知对应的便签Uri
+ if (noteId > 0) {
+ getContext().getContentResolver().notifyChange(
+ ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
+ }
// 通知当前Uri的数据变更
getContext().getContentResolver().notifyChange(uri, null);
}
diff --git a/src/notes/model/WorkingNote.java b/src/notes/model/WorkingNote.java
index be081e4..a8e6b7b 100644
--- a/src/notes/model/WorkingNote.java
+++ b/src/notes/model/WorkingNote.java
@@ -29,6 +29,7 @@ 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.TextNote;
+
import net.micode.notes.tool.ResourceParser.NoteBgResources;
@@ -188,6 +189,19 @@ public class WorkingNote {
}
public synchronized boolean saveNote() {
+ if (mIsDeleted && existInDatabase()) {
+ // 如果便签已被标记为删除且存在于数据库中,则执行删除操作
+ int rows = mContext.getContentResolver().delete(
+ ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId),
+ null, null);
+ if (rows > 0) {
+ Log.d(TAG, "Deleted empty note with id:" + mNoteId);
+ } else {
+ Log.e(TAG, "Failed to delete empty note with id:" + mNoteId);
+ }
+ return true;
+ }
+
if (isWorthSaving()) {
if (!existInDatabase()) {
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
@@ -195,8 +209,12 @@ public class WorkingNote {
return false;
}
}
-
- mNote.syncNote(mContext, mNoteId);
+
+ // 更新便签数据
+ mNote.setTextData(DataColumns.CONTENT, mContent);
+
+ // 同步到数据库
+ boolean result = mNote.syncNote(mContext, mNoteId);
/**
* Update widget content if there exist any widget of this note
@@ -206,7 +224,7 @@ public class WorkingNote {
&& mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
- return true;
+ return result;
} else {
return false;
}
@@ -217,12 +235,24 @@ public class WorkingNote {
}
private boolean isWorthSaving() {
- if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
- || (existInDatabase() && !mNote.isLocalModified())) {
+ if (mIsDeleted) {
+ return false;
+ }
+ // 如果便签不存在于数据库且内容为空,则不值得保存
+ if (!existInDatabase() && TextUtils.isEmpty(mContent)) {
+ return false;
+ }
+ // 如果便签已存在于数据库但内容为空,则需要删除它
+ if (existInDatabase() && TextUtils.isEmpty(mContent)) {
+ // 标记为需要删除
+ mIsDeleted = true;
+ return false;
+ }
+ // 如果便签已存在于数据库但未被修改,则不需要保存
+ if (existInDatabase() && !mNote.isLocalModified()) {
return false;
- } else {
- return true;
}
+ return true;
}
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
@@ -341,6 +371,8 @@ public class WorkingNote {
public int getWidgetType() {
return mWidgetType;
}
+
+
public interface NoteSettingChangedListener {
/**
diff --git a/src/notes/tool/BackupUtils.java b/src/notes/tool/BackupUtils.java
index b9f0b86..bc1dfff 100644
--- a/src/notes/tool/BackupUtils.java
+++ b/src/notes/tool/BackupUtils.java
@@ -355,8 +355,7 @@ public class BackupUtils {
Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI, // 便签表
NOTE_PROJECTION, // 查询字段
- "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
- + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
+ "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + ") OR "
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER,
null, // 查询参数
null // 排序
diff --git a/src/notes/tool/DataUtils.java b/src/notes/tool/DataUtils.java
index 4c6ecdd..9eec99f 100644
--- a/src/notes/tool/DataUtils.java
+++ b/src/notes/tool/DataUtils.java
@@ -181,13 +181,12 @@ public class DataUtils {
* @return 用户文件夹数量
*/
public static int getUserFolderCount(ContentResolver resolver) {
- // 查询条件:类型为文件夹 且 不在回收站中
+ // 查询条件:类型为文件夹
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { "COUNT(*)" }, // 只查询数量
- NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", // 查询条件
+ NoteColumns.TYPE + "=?", // 查询条件
new String[] {
- String.valueOf(Notes.TYPE_FOLDER), // 参数1:文件夹类型
- String.valueOf(Notes.ID_TRASH_FOLER) // 参数2:排除回收站
+ String.valueOf(Notes.TYPE_FOLDER) // 参数1:文件夹类型
},
null);
@@ -218,7 +217,7 @@ public class DataUtils {
// 查询指定便签
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, // 查询所有列
- NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
+ NoteColumns.TYPE + "=?",
new String [] {String.valueOf(type)}, // 类型参数
null);
@@ -284,10 +283,9 @@ public class DataUtils {
* @return true: 已存在; false: 不存在
*/
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
- // 查询条件:文件夹类型 且 不在回收站 且 名称匹配
+ // 查询条件:文件夹类型 且 名称匹配
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
- " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?", // SNIPPET字段存储文件夹名称
new String[] { name }, null);
diff --git a/src/notes/tool/ResourceParser.java b/src/notes/tool/ResourceParser.java
index 13b5cdb..af9099f 100644
--- a/src/notes/tool/ResourceParser.java
+++ b/src/notes/tool/ResourceParser.java
@@ -115,7 +115,7 @@ public class ResourceParser {
*/
public static int getDefaultBgId(Context context) {
// 从偏好设置读取是否启用随机背景颜色
- if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
+ if (context.getSharedPreferences(NotesPreferenceActivity.PREFERENCE_NAME, Context.MODE_PRIVATE).getBoolean(
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, // 偏好设置键名
false)) { // 默认值为false(不随机)
// 随机选择一种颜色
diff --git a/src/notes/tool/SearchHistoryManager.java b/src/notes/tool/SearchHistoryManager.java
new file mode 100644
index 0000000..d33a004
--- /dev/null
+++ b/src/notes/tool/SearchHistoryManager.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.micode.notes.tool;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * SearchHistoryManager - 搜索历史记录管理类
+ * 使用SharedPreferences存储搜索历史记录
+ */
+public class SearchHistoryManager {
+ private static final String TAG = "SearchHistoryManager";
+
+ // SharedPreferences文件名
+ private static final String PREFERENCE_NAME = "search_history";
+
+ // 搜索历史键
+ private static final String KEY_SEARCH_HISTORY = "search_history";
+
+ // 最大历史记录数量
+ private static final int MAX_HISTORY_COUNT = 10;
+
+ // 单例实例
+ private static SearchHistoryManager sInstance;
+
+ // SharedPreferences实例
+ private SharedPreferences mSharedPreferences;
+
+ /**
+ * 私有构造函数
+ * @param context 上下文
+ */
+ private SearchHistoryManager(Context context) {
+ mSharedPreferences = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * 获取单例实例
+ * @param context 上下文
+ * @return SearchHistoryManager实例
+ */
+ public static synchronized SearchHistoryManager getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new SearchHistoryManager(context.getApplicationContext());
+ }
+ return sInstance;
+ }
+
+ /**
+ * 保存搜索关键词到历史记录
+ * @param keyword 搜索关键词
+ */
+ public void saveSearchKeyword(String keyword) {
+ if (TextUtils.isEmpty(keyword)) {
+ return;
+ }
+
+ // 获取现有历史记录
+ List historyList = getSearchHistoryList();
+
+ // 如果已存在,移除旧的位置
+ if (historyList.contains(keyword)) {
+ historyList.remove(keyword);
+ }
+
+ // 添加到最前面
+ historyList.add(0, keyword);
+
+ // 限制历史记录数量
+ if (historyList.size() > MAX_HISTORY_COUNT) {
+ historyList = historyList.subList(0, MAX_HISTORY_COUNT);
+ }
+
+ // 保存到SharedPreferences
+ saveHistoryList(historyList);
+ }
+
+ /**
+ * 获取搜索历史记录列表
+ * @return 搜索历史记录列表
+ */
+ public List getSearchHistoryList() {
+ List historyList = new ArrayList<>();
+
+ try {
+ String historyJson = mSharedPreferences.getString(KEY_SEARCH_HISTORY, "[]");
+ JSONArray jsonArray = new JSONArray(historyJson);
+
+ for (int i = 0; i < jsonArray.length(); i++) {
+ historyList.add(jsonArray.getString(i));
+ }
+ } catch (JSONException e) {
+ Log.e(TAG, "Failed to parse search history: " + e.getMessage());
+ }
+
+ return historyList;
+ }
+
+ /**
+ * 清除所有搜索历史记录
+ */
+ public void clearSearchHistory() {
+ mSharedPreferences.edit().remove(KEY_SEARCH_HISTORY).apply();
+ }
+
+ /**
+ * 保存历史记录列表到SharedPreferences
+ * @param historyList 历史记录列表
+ */
+ private void saveHistoryList(List historyList) {
+ try {
+ JSONArray jsonArray = new JSONArray(historyList);
+ mSharedPreferences.edit().putString(KEY_SEARCH_HISTORY, jsonArray.toString()).apply();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to save search history: " + e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/notes/ui/NoteEditActivity.java b/src/notes/ui/NoteEditActivity.java
index 0f28da1..03fedc5 100644
--- a/src/notes/ui/NoteEditActivity.java
+++ b/src/notes/ui/NoteEditActivity.java
@@ -35,11 +35,15 @@ import android.graphics.Paint; // 画笔,用于文本样式
import android.os.Bundle; // 状态保存
import android.preference.PreferenceManager; // 偏好设置管理器
// Android文本处理
+import android.text.Editable; // 可编辑文本
import android.text.Spannable; // 可设置样式的文本
import android.text.SpannableString; // 可设置样式的字符串
import android.text.TextUtils; // 文本工具
+import android.text.TextWatcher; // 文本变化监听
import android.text.format.DateUtils; // 日期工具
import android.text.style.BackgroundColorSpan; // 背景色样式
+// Android网络
+import android.net.Uri; // URI工具
import android.util.Log; // 日志工具
// Android视图
import android.view.LayoutInflater; // 布局加载器
@@ -71,6 +75,8 @@ import net.micode.notes.model.WorkingNote.NoteSettingChangedListener; // 便签
import net.micode.notes.tool.DataUtils; // 数据工具
import net.micode.notes.tool.ResourceParser; // 资源解析器
import net.micode.notes.tool.ResourceParser.TextAppearanceResources; // 文本外观资源
+import net.micode.notes.tool.SearchHistoryManager; // 搜索历史管理器
+
// 应用对话框
import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener; // 日期时间设置监听
// 应用自定义控件
@@ -82,6 +88,7 @@ import net.micode.notes.widget.NoteWidgetProvider_4x; // 4x小部件
// Java集合
import java.util.HashMap; // 哈希映射
import java.util.HashSet; // 哈希集合
+import java.util.List; // 列表接口
import java.util.Map; // 映射接口
// Java正则表达式
import java.util.regex.Matcher; // 正则匹配器
@@ -181,6 +188,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private EditText mNoteEditor; // 便签编辑器
private View mNoteEditorPanel; // 编辑器面板
private LinearLayout mEditTextList; // 列表模式编辑容器
+ private TextView mWordCountView; // 字数统计视图
// 业务模型
private WorkingNote mWorkingNote; // 工作便签模型
@@ -196,6 +204,9 @@ 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 static final int REQUEST_CODE_IMAGE_SELECTION = 1;
// 搜索高亮相关
private String mUserQuery; // 用户搜索关键词
@@ -263,6 +274,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) {
noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY);
+
+ // 保存搜索关键词到历史记录
+ SearchHistoryManager.getInstance(this).saveSearchKeyword(mUserQuery);
}
// 检查便签是否存在
@@ -387,6 +401,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
// 显示提醒信息
showAlertHeader();
+
+ // 更新字数统计
+ updateWordCount();
}
/**
@@ -498,6 +515,25 @@ public class NoteEditActivity extends Activity implements OnClickListener,
// 编辑视图
mNoteEditor = (EditText) findViewById(R.id.note_edit_view);
mNoteEditorPanel = findViewById(R.id.sv_note_edit);
+
+ // 字数统计视图
+ mWordCountView = (TextView) findViewById(R.id.tv_word_count);
+
+ // 设置文本变化监听
+ mNoteEditor.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) {
+ updateWordCount();
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
// 背景选择器
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);
@@ -514,7 +550,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
};
// 偏好设置
- mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mSharedPrefs = getSharedPreferences(NotesPreferenceActivity.PREFERENCE_NAME, Context.MODE_PRIVATE);
mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE);
// 修复字体大小ID可能越界的bug
@@ -541,6 +577,25 @@ public class NoteEditActivity extends Activity implements OnClickListener,
clearSettingState();
}
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE_IMAGE_SELECTION && resultCode == RESULT_OK) {
+ if (data != null && data.getData() != null) {
+ // 获取选中图片的Uri
+ Uri imageUri = data.getData();
+ // 将图片Uri插入到当前编辑位置
+ String imageTag = "[IMAGE:" + imageUri.toString() + "]";
+ int currentPosition = mNoteEditor.getSelectionStart();
+ Editable text = mNoteEditor.getText();
+ text.insert(currentPosition, imageTag);
+ // 保存便签内容
+ getWorkingText();
+ }
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
// ======================= 小部件更新 =======================
/**
@@ -732,6 +787,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
setReminder();
} else if (itemId == R.id.menu_delete_remind) {
mWorkingNote.setAlertDate(0, false);
+ } else if (itemId == R.id.menu_insert_image) {
+ // 启动图片选择器
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("image/*");
+ startActivityForResult(intent, REQUEST_CODE_IMAGE_SELECTION);
} else {
// 默认分支(原default)
}
@@ -781,6 +841,16 @@ public class NoteEditActivity extends Activity implements OnClickListener,
startActivity(intent);
}
+
+
+
+
+ /**
+ * 显示Toast消息
+ * @param resId 字符串资源ID
+ */
+ // 已删除重复的showToast方法,使用第1383行定义的更灵活的方法
+
/**
* 删除当前便签
*/
@@ -793,15 +863,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} 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");
- }
+ // 统一使用永久删除方式
+ if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) {
+ Log.e(TAG, "Delete Note error");
}
}
mWorkingNote.markDeleted(true);
@@ -1006,6 +1070,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE);
}
+ // 更新字数统计
+ updateWordCount();
}
// ======================= 清单模式变化回调 =======================
@@ -1027,6 +1093,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mEditTextList.setVisibility(View.GONE);
mNoteEditor.setVisibility(View.VISIBLE);
}
+ // 更新字数统计
+ updateWordCount();
}
// ======================= 获取工作文本 =======================
@@ -1063,6 +1131,28 @@ public class NoteEditActivity extends Activity implements OnClickListener,
// ======================= 保存便签 =======================
+ /**
+ * 更新字数统计
+ * 根据当前模式计算并显示字数
+ */
+ private void updateWordCount() {
+ int wordCount = 0;
+ if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
+ // 清单模式:计算所有列表项的字数
+ StringBuilder content = new StringBuilder();
+ for (int i = 0; i < mEditTextList.getChildCount(); i++) {
+ View view = mEditTextList.getChildAt(i);
+ NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
+ content.append(edit.getText().toString());
+ }
+ wordCount = content.length();
+ } else {
+ // 普通模式:直接计算文本长度
+ wordCount = mNoteEditor.getText().length();
+ }
+ mWordCountView.setText(String.valueOf(wordCount));
+ }
+
/**
* 保存便签
* @return true: 保存成功; false: 保存失败
diff --git a/src/notes/ui/NoteEditText.java b/src/notes/ui/NoteEditText.java
index d07dbe2..c63a751 100644
--- a/src/notes/ui/NoteEditText.java
+++ b/src/notes/ui/NoteEditText.java
@@ -21,6 +21,7 @@ package net.micode.notes.ui;
// ======================= 导入区域 =======================
// Android基础
import android.content.Context; // 上下文
+import android.content.ContentResolver; // 内容解析器
import android.graphics.Rect; // 矩形区域
// Android文本处理
import android.text.Layout; // 文本布局
@@ -36,8 +37,22 @@ import android.view.KeyEvent; // 按键事件
import android.view.MenuItem; // 菜单项
import android.view.MenuItem.OnMenuItemClickListener; // 菜单项点击监听
import android.view.MotionEvent; // 触摸事件
+// Android文本处理
+import android.text.InputType; // 输入类型
+import android.text.Spannable; // 可设置样式的文本
+import android.text.SpannableStringBuilder; // 可设置样式的字符串构建器
+import android.text.style.ImageSpan; // 图片样式
+// Android输入法
+import android.view.inputmethod.EditorInfo; // 输入法编辑器信息
// Android控件
-import android.widget.EditText; // 编辑文本控件基类
+import android.widget.EditText; // 编辑文本控件基类
+import android.widget.ImageView; // 图片视图
+// Android图形
+import android.graphics.Bitmap; // 位图
+import android.graphics.BitmapFactory; // 位图工厂
+import android.graphics.drawable.Drawable; // 可绘制对象
+// Android网络
+import android.net.Uri; // URI工具
// 应用内部资源
import net.micode.notes.R; // 资源文件R类
@@ -127,7 +142,7 @@ public class NoteEditText extends EditText {
* @param context 上下文
*/
public NoteEditText(Context context) {
- super(context, null);
+ this(context, null);
mIndex = 0; // 默认索引为0
}
@@ -137,7 +152,7 @@ public class NoteEditText extends EditText {
* @param attrs 属性集
*/
public NoteEditText(Context context, AttributeSet attrs) {
- super(context, attrs, android.R.attr.editTextStyle);
+ this(context, attrs, android.R.attr.editTextStyle);
}
/**
@@ -148,7 +163,98 @@ public class NoteEditText extends EditText {
*/
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- // TODO: 可在此处添加额外初始化代码
+ // 确保输入法支持中文输入
+ setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
+ setImeOptions(EditorInfo.IME_ACTION_NONE);
+ }
+
+ /**
+ * 从URI加载图片
+ * @param uri 图片URI
+ * @return 加载的Bitmap对象
+ */
+ private Bitmap loadImageFromUri(Uri uri) {
+ try {
+ ContentResolver resolver = getContext().getContentResolver();
+ Bitmap bitmap = BitmapFactory.decodeStream(resolver.openInputStream(uri));
+ if (bitmap != null) {
+ // 调整图片大小以适应编辑框
+ int maxWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
+ if (bitmap.getWidth() > maxWidth) {
+ float scale = (float) maxWidth / bitmap.getWidth();
+ int newHeight = (int) (bitmap.getHeight() * scale);
+ bitmap = Bitmap.createScaledBitmap(bitmap, maxWidth, newHeight, true);
+ }
+ }
+ return bitmap;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to load image from URI: " + uri, e);
+ return null;
+ }
+ }
+
+ /**
+ * 解析文本中的[IMAGE:uri]标签并替换为图片
+ * @param text 包含图片标签的文本
+ * @return 处理后的SpannableStringBuilder,包含图片
+ */
+ private SpannableStringBuilder parseImageTags(CharSequence text) {
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ String content = text.toString();
+ int startIndex = 0;
+
+ while (true) {
+ startIndex = content.indexOf("[IMAGE:", startIndex);
+ if (startIndex == -1) break;
+
+ int endIndex = content.indexOf("]", startIndex);
+ if (endIndex == -1) break;
+
+ String imageTag = content.substring(startIndex, endIndex + 1);
+ String imageUriStr = imageTag.substring(7, imageTag.length() - 1); // 去掉[IMAGE:和]
+
+ try {
+ Uri imageUri = Uri.parse(imageUriStr);
+ Bitmap bitmap = loadImageFromUri(imageUri);
+
+ if (bitmap != null) {
+ // 创建一个占位符文本,用于放置图片
+ String placeholder = "[图片]";
+ int placeholderLength = placeholder.length();
+
+ // 替换图片标签为占位符
+ builder.replace(startIndex, endIndex + 1, placeholder);
+
+ // 创建ImageSpan并添加到占位符位置
+ ImageSpan imageSpan = new ImageSpan(getContext(), bitmap);
+ builder.setSpan(imageSpan, startIndex, startIndex + placeholderLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ // 更新content和startIndex以继续处理
+ content = builder.toString();
+ startIndex += placeholderLength;
+ } else {
+ startIndex = endIndex + 1;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to parse image URI: " + imageUriStr, e);
+ startIndex = endIndex + 1;
+ }
+ }
+
+ return builder;
+ }
+
+ /**
+ * 重写setText方法,解析图片标签并显示图片
+ */
+ @Override
+ public void setText(CharSequence text, BufferType type) {
+ if (text != null) {
+ SpannableStringBuilder builder = parseImageTags(text);
+ super.setText(builder, BufferType.SPANNABLE);
+ } else {
+ super.setText(text, type);
+ }
}
// ======================= 设置方法 =======================
diff --git a/src/notes/ui/NoteItemData.java b/src/notes/ui/NoteItemData.java
index 2b970e5..c3c56f2 100644
--- a/src/notes/ui/NoteItemData.java
+++ b/src/notes/ui/NoteItemData.java
@@ -58,6 +58,7 @@ public class NoteItemData {
NoteColumns.TYPE, // 9 - 便签类型
NoteColumns.WIDGET_ID, // 10 - 小部件ID
NoteColumns.WIDGET_TYPE, // 11 - 小部件类型
+ NoteColumns.PINNED // 12 - 是否置顶
};
// ======================= 字段索引常量 =======================
@@ -75,6 +76,7 @@ public class NoteItemData {
private static final int TYPE_COLUMN = 9; // 类型字段索引
private static final int WIDGET_ID_COLUMN = 10; // 小部件ID字段索引
private static final int WIDGET_TYPE_COLUMN = 11; // 小部件类型字段索引
+ private static final int PINNED_COLUMN = 12; // 是否置顶字段索引
// ======================= 数据成员 =======================
@@ -91,6 +93,7 @@ public class NoteItemData {
private int mType; // 便签类型
private int mWidgetId; // 小部件ID
private int mWidgetType; // 小部件类型
+ private boolean mPinned; // 是否置顶
// 通话记录相关
private String mName; // 联系人姓名
@@ -131,6 +134,7 @@ public class NoteItemData {
mType = cursor.getInt(TYPE_COLUMN);
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN);
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN);
+ mPinned = (cursor.getInt(PINNED_COLUMN) > 0) ? true : false;
// 2. 清理摘要中的清单标记
// 移除已勾选(√)和未勾选(□)标记,只显示纯文本
@@ -356,6 +360,16 @@ public class NoteItemData {
public int getWidgetType() {
return mWidgetType;
}
+
+ /**
+ * 获取便签是否置顶
+ * @return true: 置顶, false: 不置顶
+ */
+ public boolean isPinned() {
+ return mPinned;
+ }
+
+
/**
* 获取小部件ID
diff --git a/src/notes/ui/NotesListActivity.java b/src/notes/ui/NotesListActivity.java
index 0081235..a5349ff 100644
--- a/src/notes/ui/NotesListActivity.java
+++ b/src/notes/ui/NotesListActivity.java
@@ -62,6 +62,7 @@ import android.widget.AdapterView.OnItemClickListener; // 列表项点击监听
import android.widget.AdapterView.OnItemLongClickListener; // 列表项长按监听
import android.widget.Button; // 按钮
import android.widget.EditText; // 编辑框
+import android.widget.ImageView; // 图片视图
import android.widget.ListView; // 列表视图
import android.widget.PopupMenu; // 弹出菜单
import android.widget.TextView; // 文本视图
@@ -72,6 +73,7 @@ import net.micode.notes.R; // 资源文件R类
// 应用数据模型
import net.micode.notes.data.Notes; // Notes主类
import net.micode.notes.data.Notes.NoteColumns; // 便签表列定义
+import net.micode.notes.data.NotesDatabaseHelper; // 数据库帮助类
// 应用同步服务
import net.micode.notes.gtask.remote.GTaskSyncService; // Google任务同步服务
// 应用业务模型
@@ -79,6 +81,7 @@ import net.micode.notes.model.WorkingNote; // 工作便签模型
// 应用工具
import net.micode.notes.tool.BackupUtils; // 备份工具
import net.micode.notes.tool.DataUtils; // 数据工具
+
import net.micode.notes.tool.ResourceParser; // 资源解析器
// 应用适配器
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; // 小部件属性
@@ -93,6 +96,8 @@ import java.io.InputStream; // 输入流
import java.io.InputStreamReader; // 输入流读取器
// Java集合
import java.util.HashSet; // 哈希集合
+import java.util.List; // 列表接口
+import java.util.Map; // 映射接口
// ======================= 便签列表主Activity =======================
/**
@@ -113,11 +118,17 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
/** 文件夹列表查询令牌 - 查询所有文件夹(用于移动操作) */
private static final int FOLDER_LIST_QUERY_TOKEN = 1;
- // ======================= 上下文菜单项ID常量 =======================
+ // ======================= 文件夹上下文菜单常量 =======================
private static final int MENU_FOLDER_DELETE = 0; // 删除文件夹
private static final int MENU_FOLDER_VIEW = 1; // 查看文件夹
private static final int MENU_FOLDER_CHANGE_NAME = 2; // 重命名文件夹
+
+ // ======================= 便签上下文菜单常量 =======================
+
+ private static final int MENU_NOTE_PIN = 3; // 置顶便签
+ private static final int MENU_NOTE_UNPIN = 4; // 取消置顶便签
+ private static final int MENU_NOTE_BATCH_SELECT = 5; // 批量选择
// ======================= 偏好设置常量 =======================
@@ -183,6 +194,9 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
/** 当前焦点便签数据项 - 用于上下文菜单和长按操作 */
private NoteItemData mFocusNoteDataItem;
+ /** 当前选中的标签ID - 用于按标签筛选便签,-1表示不筛选 */
+
+
// ======================= 数据库查询条件常量 =======================
/** 普通文件夹查询条件 - 查询指定父文件夹下的便签 */
@@ -243,7 +257,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
* 首次启动时从R.raw.introduction读取介绍文本并创建便签
*/
private void setAppInfoFromRawRes() {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ SharedPreferences sp = getSharedPreferences(NotesPreferenceActivity.PREFERENCE_NAME, Context.MODE_PRIVATE);
// 检查是否已添加过介绍
if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
StringBuilder sb = new StringBuilder();
@@ -326,8 +340,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mDispatchY = 0;
mOriginY = 0;
mTitleBar = (TextView) findViewById(R.id.tv_title_bar);
+
mState = ListEditState.NOTE_LIST; // 初始状态为便签列表
mModeCallBack = new ModeCallback(); // 创建多选模式回调
+
+ // 更新标题栏
+ updateTitleBar();
}
// ======================= 多选模式回调类 =======================
@@ -358,6 +376,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mMoveMenu.setVisible(true);
mMoveMenu.setOnMenuItemClickListener(this);
}
+
+ // 设置置顶和取消置顶菜单项的点击监听器
+ MenuItem pinMenuItem = menu.findItem(R.id.pin);
+ MenuItem unpinMenuItem = menu.findItem(R.id.unpin);
+ pinMenuItem.setOnMenuItemClickListener(this);
+ unpinMenuItem.setOnMenuItemClickListener(this);
+
mActionMode = mode;
mNotesListAdapter.setChoiceMode(true); // 进入选择模式
mNotesListView.setLongClickable(false); // 禁用长按
@@ -473,6 +498,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else if (itemId == R.id.move) {
// 查询目标文件夹
startQueryDestinationFolders();
+ } else if (itemId == R.id.pin) {
+ // 批量置顶选中的便签
+ batchPinNotes(true);
+ } else if (itemId == R.id.unpin) {
+ // 批量取消置顶选中的便签
+ batchPinNotes(false);
} else {
return false;
}
@@ -554,10 +585,11 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private void startAsyncNotesListQuery() {
String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION
: NORMAL_SELECTION;
+ String[] selectionArgs = { String.valueOf(mCurrentFolderId) };
+
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.PINNED + " DESC," + NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
}
/**
@@ -640,21 +672,60 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
protected HashSet doInBackground(Void... unused) {
// 获取选中便签关联的小部件
HashSet widgets = mNotesListAdapter.getSelectedWidget();
- if (!isSyncMode()) {
- // 非同步模式:直接删除
- if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter
- .getSelectedItemIds())) {
- // 删除成功
- } else {
- Log.e(TAG, "Delete notes error, should not happens");
+
+ // 统一使用永久删除方式
+ if (!DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter.getSelectedItemIds())) {
+ Log.e(TAG, "Delete notes error, should not happens");
+ }
+
+ return widgets;
+ }
+
+ @Override
+ protected void onPostExecute(HashSet widgets) {
+ // 更新关联的小部件
+ if (widgets != null) {
+ for (AppWidgetAttribute widget : widgets) {
+ if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
+ && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
+ updateWidget(widget.widgetId, widget.widgetType);
+ }
}
- } else {
- // 同步模式:移动到回收站
- if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
- .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) {
- Log.e(TAG, "Move notes to trash folder error, should not happens");
+ }
+ mModeCallBack.finishActionMode();
+ }
+ }.execute();
+ }
+
+ /**
+ * 批量设置便签置顶状态
+ * @param pin true: 置顶, false: 取消置顶
+ */
+ private void batchPinNotes(final boolean pin) {
+ new AsyncTask>() {
+ protected HashSet doInBackground(Void... unused) {
+ // 获取选中便签关联的小部件
+ HashSet widgets = mNotesListAdapter.getSelectedWidget();
+
+ // 批量设置置顶状态
+ ContentValues values = new ContentValues();
+ values.put(NoteColumns.PINNED, pin ? 1 : 0);
+ values.put(NoteColumns.LOCAL_MODIFIED, 1);
+
+ StringBuffer selection = new StringBuffer();
+ HashSet ids = mNotesListAdapter.getSelectedItemIds();
+ String[] selectionArgs = new String[ids.size()];
+ int i = 0;
+ for (Long id : ids) {
+ if (i > 0) {
+ selection.append(" OR ");
}
+ selection.append(NoteColumns.ID + "=?");
+ selectionArgs[i++] = String.valueOf(id);
}
+
+ mContentResolver.update(Notes.CONTENT_NOTE_URI, values, selection.toString(), selectionArgs);
+
return widgets;
}
@@ -676,6 +747,50 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
// ======================= 删除文件夹 =======================
+ /**
+ * 切换便签置顶状态
+ * @param noteId 便签ID
+ * @param currentPinned 当前置顶状态
+ */
+ private void togglePinNote(long noteId, boolean currentPinned) {
+ ContentValues values = new ContentValues();
+ values.put(NoteColumns.PINNED, currentPinned ? 0 : 1);
+ values.put(NoteColumns.LOCAL_MODIFIED, 1);
+ mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID + "=?",
+ new String[] { String.valueOf(noteId) });
+ }
+
+ /**
+ * 显示标签筛选对话框
+ */
+
+
+ /**
+ * 更新标题栏,显示当前文件夹和筛选状态
+ */
+ private void updateTitleBar() {
+ String title = getString(R.string.app_name);
+
+ // 如果不是根文件夹,显示文件夹名称
+ if (mCurrentFolderId != Notes.ID_ROOT_FOLDER) {
+ Cursor cursor = mContentResolver.query(Notes.CONTENT_NOTE_URI,
+ new String[] { NoteColumns.SNIPPET },
+ NoteColumns.ID + "=?",
+ new String[] { String.valueOf(mCurrentFolderId) },
+ null);
+
+ if (cursor != null && cursor.moveToFirst()) {
+ title = cursor.getString(0);
+ cursor.close();
+ }
+ }
+
+ mTitleBar.setText(title);
+ mTitleBar.setVisibility(View.VISIBLE);
+ }
+
+
+
/**
* 删除文件夹
* @param folderId 文件夹ID
@@ -946,6 +1061,22 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
};
+
+ private final OnCreateContextMenuListener mNoteOnCreateContextMenuListener = new OnCreateContextMenuListener() {
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ if (mFocusNoteDataItem != null) {
+ menu.setHeaderTitle(R.string.app_name);
+ // 根据当前置顶状态添加不同的菜单项
+ if (mFocusNoteDataItem.isPinned()) {
+ menu.add(0, MENU_NOTE_UNPIN, 0, R.string.menu_unpin);
+ } else {
+ menu.add(0, MENU_NOTE_PIN, 0, R.string.menu_pin);
+ }
+ // 添加批量选择菜单项
+ menu.add(0, MENU_NOTE_BATCH_SELECT, 1, R.string.menu_batch_select);
+ }
+ }
+ };
/**
* 上下文菜单关闭
@@ -985,7 +1116,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
builder.show();
} else if (itemId == MENU_FOLDER_CHANGE_NAME) {
showCreateOrModifyFolderDialog(false);
+ } else if (itemId == MENU_NOTE_PIN) {
+ togglePinNote(mFocusNoteDataItem.getId(), false);
+ } else if (itemId == MENU_NOTE_UNPIN) {
+ togglePinNote(mFocusNoteDataItem.getId(), true);
+ } else if (itemId == MENU_NOTE_BATCH_SELECT) {
+ // 进入批量选择模式
+ // 启动多选模式
+ mModeCallBack = new ModeCallback();
+ mNotesListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+ mNotesListView.setMultiChoiceModeListener(mModeCallBack);
}
+
return true;
}
@@ -1202,14 +1344,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
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()) {
- if (mNotesListView.startActionMode(mModeCallBack) != null) {
- mModeCallBack.onItemCheckedStateChanged(null, position, id, true);
- mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- } else {
- Log.e(TAG, "startActionMode fails");
- }
+
+ if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE) {
+ // 便签长按:显示上下文菜单
+ mNotesListView.setOnCreateContextMenuListener(mNoteOnCreateContextMenuListener);
} else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) {
// 文件夹长按:显示上下文菜单
mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener);
diff --git a/src/notes/ui/NotesListItem.java b/src/notes/ui/NotesListItem.java
index 342f1f5..ab1ba72 100644
--- a/src/notes/ui/NotesListItem.java
+++ b/src/notes/ui/NotesListItem.java
@@ -53,6 +53,9 @@ public class NotesListItem extends LinearLayout {
/** 提醒图标 - 显示便签是否有提醒 */
private ImageView mAlert;
+ /** 置顶图标 - 显示便签是否置顶 */
+ private ImageView mPinned;
+
/** 标题文本 - 显示便签摘要或文件夹名称 */
private TextView mTitle;
@@ -84,6 +87,7 @@ public class NotesListItem extends LinearLayout {
// 2. 查找并保存子视图引用
mAlert = (ImageView) findViewById(R.id.iv_alert_icon);
+ mPinned = (ImageView) findViewById(R.id.iv_pinned_icon);
mTitle = (TextView) findViewById(R.id.tv_title);
mTime = (TextView) findViewById(R.id.tv_time);
mCallName = (TextView) findViewById(R.id.tv_name);
@@ -216,6 +220,12 @@ public class NotesListItem extends LinearLayout {
} else {
mAlert.setVisibility(View.GONE);
}
+ // 根据是否置顶设置置顶图标
+ if (data.isPinned()) {
+ mPinned.setVisibility(View.VISIBLE);
+ } else {
+ mPinned.setVisibility(View.GONE);
+ }
}
}
diff --git a/src/notes/ui/NotesPreferenceActivity.java b/src/notes/ui/NotesPreferenceActivity.java
index 8be7b04..48373b2 100644
--- a/src/notes/ui/NotesPreferenceActivity.java
+++ b/src/notes/ui/NotesPreferenceActivity.java
@@ -41,6 +41,7 @@ import android.preference.Preference; // 偏好设置项
import android.preference.Preference.OnPreferenceClickListener; // 偏好设置点击监听
import android.preference.PreferenceActivity; // 偏好设置Activity基类
import android.preference.PreferenceCategory; // 偏好设置分类
+import android.preference.PreferenceManager; // 偏好设置管理器
// Android工具
import android.text.TextUtils; // 文本工具
import android.text.format.DateFormat; // 日期格式化
@@ -49,6 +50,7 @@ import android.view.LayoutInflater; // 布局加载器
import android.view.Menu; // 菜单
import android.view.MenuItem; // 菜单项
import android.view.View; // 视图基类
+import android.widget.ListView; // 列表视图
// Android控件
import android.widget.Button; // 按钮
import android.widget.TextView; // 文本视图
@@ -61,6 +63,8 @@ import net.micode.notes.data.Notes; // Notes主类
import net.micode.notes.data.Notes.NoteColumns; // 便签表列定义
// 应用同步服务
import net.micode.notes.gtask.remote.GTaskSyncService; // Google任务同步服务
+// 应用工具
+import net.micode.notes.tool.SearchHistoryManager; // 搜索历史管理器
// ======================= 便签设置Activity =======================
/**
@@ -114,14 +118,25 @@ public class NotesPreferenceActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
-
- /* 使用应用图标作为导航按钮 */
- getActionBar().setDisplayHomeAsUpEnabled(true);
-
// 从XML加载偏好设置
addPreferencesFromResource(R.xml.preferences);
+
// 获取账户设置分类
mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
+
+ // 设置清除搜索历史按钮的点击事件
+ Preference clearSearchHistoryPref = findPreference("pref_key_clear_search_history");
+ if (clearSearchHistoryPref != null) {
+ clearSearchHistoryPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference preference) {
+ // 清除搜索历史
+ SearchHistoryManager.getInstance(NotesPreferenceActivity.this).clearSearchHistory();
+ Toast.makeText(NotesPreferenceActivity.this,
+ "Search history cleared", Toast.LENGTH_SHORT).show();
+ return true;
+ }
+ });
+ }
// 创建并注册同步广播接收器
mReceiver = new GTaskReceiver();
IntentFilter filter = new IntentFilter();
@@ -131,7 +146,16 @@ public class NotesPreferenceActivity extends PreferenceActivity {
mOriAccounts = null; // 初始化原始账户列表
// 添加设置界面头部
View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
- getListView().addHeaderView(header, null, true);
+ ListView listView = getListView();
+ if (listView != null) {
+ listView.addHeaderView(header, null, true);
+ }
+
+ /* 使用应用图标作为导航按钮 */
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
}
/**
diff --git a/小米便签开源代码的泛读报告.docx b/小米便签开源代码的泛读报告.docx
deleted file mode 100644
index 0004881..0000000
Binary files a/小米便签开源代码的泛读报告.docx and /dev/null differ
diff --git a/开源软件泛读文档(1).docx b/开源软件泛读文档(1).docx
deleted file mode 100644
index 5f36a19..0000000
Binary files a/开源软件泛读文档(1).docx and /dev/null differ