liqiushi_branch
LQS 10 months ago
parent 75744d31e2
commit 0cccb8880c

@ -1,26 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.micode.notes"
android:versionCode="1"
android:versionName="0.1" >
android:versionName="0.1">
<uses-sdk android:minSdkVersion="14" />
<uses-sdk android:minSdkVersion="21" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
@ -33,8 +17,17 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon_app"
android:label="@string/app_name" >
android:icon="@drawable/icon_app_new"
android:label="@string/app_name">
<activity
android:name=".ui.SplashActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/Theme.Note.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.NotesListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
@ -44,34 +37,32 @@
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/NoteTheme" >
android:theme="@style/NoteTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<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.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<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>
@ -81,13 +72,13 @@
</activity>
<provider
android:name="net.micode.notes.data.NotesProvider"
android:name=".data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true" />
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2" >
android:label="@string/app_widget2x2">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
@ -100,8 +91,7 @@
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4" >
android:label="@string/app_widget4x4">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
@ -112,39 +102,32 @@
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
</receiver>
<receiver android:name=".ui.AlarmInitReceiver" >
<receiver android:name=".ui.AlarmInitReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
android:name=".ui.AlarmReceiver"
android:process=":remote"></receiver>
<activity
android:name=".ui.AlarmAlertActivity"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"></activity>
<activity
android:name="net.micode.notes.ui.NotesPreferenceActivity"
android:name=".ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light" >
</activity>
android:theme="@android:style/Theme.Holo.Light"></activity>
<service
android:name="net.micode.notes.gtask.remote.GTaskSyncService"
android:exported="false" >
</service>
android:name=".gtask.remote.GTaskSyncService"
android:exported="false"></service>
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
</application>
</manifest>
</manifest>

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/fullscreenBackgroundColor"
android:theme="@style/ThemeOverlay.Note.FullscreenContainer"
tools:context=".ui.SplashActivity">
<!-- The primary full-screen view. This can be replaced with whatever view
is needed to present your content, e.g. VideoView, SurfaceView,
TextureView, etc. -->
<TextView
android:id="@+id/fullscreen_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/splash"
android:gravity="center"
android:keepScreenOn="true"
android:text="@string/dummy_content"
android:textColor="?attr/fullscreenTextColor"
android:textSize="50sp"
android:textStyle="bold" />
<!-- This FrameLayout insets its children based on system windows using
android:fitsSystemWindows. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:id="@+id/fullscreen_content_controls"
style="@style/Widget.Theme.Note.ButtonBar.Fullscreen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:orientation="horizontal"
tools:ignore="UselessParent">
<Button
android:id="@+id/dummy_button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dummy_button" />
</LinearLayout>
</FrameLayout>
</FrameLayout>

@ -31,6 +31,17 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/translate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#2196F3"
android:text="翻译" />
<ImageButton
android:id="@+id/add_img_btn"
android:layout_width="45dp"
android:layout_height="match_parent"
android:src="@android:drawable/ic_menu_gallery" />
<TextView
android:id="@+id/tv_modified_date"
android:layout_width="0dip"
@ -107,6 +118,7 @@
android:layout_marginLeft="-10dip"
android:visibility="gone" />
</LinearLayout>
</ScrollView>
<ImageView

@ -18,8 +18,9 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/list_background">
android:layout_height="fill_parent">
<!-- android:background="@drawable/list_background"> -->
<LinearLayout
android:layout_width="fill_parent"

@ -49,4 +49,13 @@
<item
android:id="@+id/menu_delete_remind"
android:title="@string/menu_remove_remind" />
<item
android:id="@+id/menu_font_setting"
android:title="@string/menu_font_setting"/> />
<item
android:id="@+id/menu_revoke"
android:title="@string/menu_revoke"/>
<item
android:id="@+id/menu_voice_speech"
android:title="@string/menu_voice_speech" />
</menu>

@ -32,8 +32,18 @@
<item
android:id="@+id/menu_setting"
android:title="@string/menu_setting" />
<item
android:id="@+id/menu_search"
android:title="@string/menu_search"/>
<!-- Background image switching -->
<item
android:id="@+id/menu_switch_to_picture1"
android:title="@string/menu_switch_to_picture1"/>
<item
android:id="@+id/menu_switch_to_picture2"
android:title="@string/menu_switch_to_picture2"/>
<item
android:id="@+id/menu_switch_to_picture3"
android:title="@string/menu_switch_to_picture3"/>
</menu>

@ -0,0 +1,7 @@
<resources>
<style name="ThemeOverlay.Note.FullscreenContainer" parent="">
<item name="fullscreenBackgroundColor">@color/light_blue_900</item>
<item name="fullscreenTextColor">@color/light_blue_A400</item>
</style>
</resources>

@ -122,5 +122,11 @@
<plurals name="search_results_title">
<item quantity="other"><xliff:g id="NUMBER">%1$s</xliff:g> 条符合“<xliff:g id="SEARCH">%2$s</xliff:g>”的搜索结果</item>
</plurals>
<string name="menu_revoke">撤销</string>
//中文
<string name="tips_of_revoke">提示</string>
<string name="can_not_revoke">您不能再执行撤销了</string>
<string name="have_not_input_anything">您还没有输入任何内容</string>
<string name="menu_voice_speech">朗读</string>
<string name="menu_font_setting">设置字体</string>
</resources>

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)

@ -0,0 +1,6 @@
<resources>
<declare-styleable name="FullscreenAttrs">
<attr name="fullscreenBackgroundColor" format="color" />
<attr name="fullscreenTextColor" format="color" />
</declare-styleable>
</resources>

@ -17,4 +17,9 @@
<resources>
<color name="user_query_highlight">#335b5b5b</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
<color name="light_blue_A200">#FF40C4FF</color>
<color name="light_blue_A400">#FF00B0FF</color>
<color name="black_overlay">#66000000</color>
</resources>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="translate" type="id" />
<item name="num_word" type="id" />
<item name="iatBtn" type="id" />
</resources>

@ -15,8 +15,7 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Notes</string>
<string name="app_widget2x2">Notes 2x2</string>
<string name="app_widget4x4">Notes 4x4</string>
@ -39,6 +38,12 @@
<string name="file_path">/MIUI/notes/</string>
<string name="file_name_txt_format">notes_%s.txt</string>
<!-- notes list string -->
<!-- Background Switch -->
<string name="menu_switch_to_picture1">Switch_to_picture1</string>
<string name="menu_switch_to_picture2">Switch_to_picture2</string>
<string name="menu_switch_to_picture3">Switch_to_picture3</string>
<string name="format_folder_files_count">(%d)</string>
<string name="menu_create_folder">New Folder</string>
<string name="menu_export_text">Export text</string>
@ -127,9 +132,22 @@
<string name="datetime_dialog_ok">set</string>
<string name="datetime_dialog_cancel">cancel</string>
<plurals name="search_results_title">
<item quantity="one"><xliff:g id="number" example="1">%1$s</xliff:g> result for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
<item quantity="one"><xliff:g example="1" id="number">%1$s</xliff:g> result for \"<xliff:g example="???" id="search">%2$s</xliff:g>\"</item>
<!-- Case of 0 or 2 or more results. -->
<item quantity="other"><xliff:g id="number" example="15">%1$s</xliff:g> results for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
<item quantity="other"><xliff:g example="15" id="number">%1$s</xliff:g> results for \"<xliff:g example="???" id="search">%2$s</xliff:g>\"</item>
</plurals>
<string name="title_activity_fullscneen">FullscreenActivity</string>
<string name="dumny_button">Dummy Button</string>
<string name="dummy_content">写下你的快乐</string>
<string name="title_activity_splash">SplashActivity</string>
<string name="dummy_button" />
<string name="menu_revoke">Revoke</string>
<string name="menu_font_setting">Set font</string>
<string name="menu_voice_speech">voice speech</string>
<string name="tips_of_revoke">Tips</string>
<string name="can_not_revoke">You can not revoke any more</string>
<string name="have_not_input_anything">You haven not input anything</string>
</resources>

@ -16,18 +16,22 @@
-->
<resources>
<style name="TextAppearanceSuper">
<item name="android:textSize">@dimen/text_font_size_super</item>
<item name="android:textColorLink">#0000ff</item>
<item name="android:textColorLink">#002AFF</item>
</style>
<style name="TextAppearanceLarge">
<item name="android:textSize">@dimen/text_font_size_large</item>
<item name="android:textColorLink">#0000ff</item>
<item name="android:textColorLink">#B90000FF</item>
</style>
<style name="TextAppearanceMedium">
<item name="android:textSize">@dimen/text_font_size_medium</item>
<item name="android:textColorLink">#0000ff</item>
</style>
<style name="TextAppearanceNormal">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColorLink">#0000ff</item>
@ -35,7 +39,7 @@
<style name="TextAppearancePrimaryItem">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColor">@color/primary_text_dark</item>
<item name="android:textColor">@color/secondary_text_dark</item>
</style>
<style name="TextAppearanceSecondaryItem">
@ -49,7 +53,7 @@
</style>
<style name="HighlightTextAppearancePrimary">
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textSize">@dimen/text_font_size_normal</item>
<item name="android:textColor">@color/primary_text_dark</item>
</style>
@ -64,6 +68,15 @@
<style name="NoteActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid">
<item name="android:displayOptions" />
<item name="android:visibility">gone</item>
<item name="android:visibility">visible</item>
</style>
<style name="Widget.Theme.Note.ActionBar.Fullscreen" parent="Widget.AppCompat.ActionBar">
<item name="android:background">@color/black_overlay</item>
</style>
<style name="Widget.Theme.Note.ButtonBar.Fullscreen" parent="">
<item name="android:background">@color/black_overlay</item>
<item name="android:buttonBarStyle">?android:attr/buttonBarStyle</item>
</style>
</resources>

@ -0,0 +1,15 @@
<resources>
<style name="Theme.Note" parent="Theme.AppCompat.Light" />
<style name="Theme.Note.Fullscreen" parent="Theme.Note">
<item name="android:actionBarStyle">@style/Widget.Theme.Note.ActionBar.Fullscreen</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowBackground">@null</item>
</style>
<style name="ThemeOverlay.Note.FullscreenContainer" parent="">
<item name="fullscreenBackgroundColor">@color/light_blue_600</item>
<item name="fullscreenTextColor">@color/light_blue_A200</item>
</style>
</resources>

@ -36,19 +36,18 @@ import java.util.HashMap;
*/
public class Contact {
private static HashMap<String, String> sContactCache;//定义了一个静态的HashMap变量sContactCache
private static final String TAG = "Contact";//定义了一个静态的字符串常量TAG
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id "
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
/*
*CALLER_ID_SELECTION,
*使PHONE_NUMBERS_EQUAL,使ID.
*/
*/
/**
* getContact,

@ -53,168 +53,168 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static NotesDatabaseHelper mInstance;
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";//这是用于创建便签表的SQL语句定义了便签表的结构包含便签各种属性和字段存储了用户创建的所有便签的信息。
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";//这是用于创建便签表的SQL语句定义了便签表的结构包含便签各种属性和字段存储了用户创建的所有便签的信息。
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA1 + " INTEGER," +
DataColumns.DATA2 + " INTEGER," +
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")";//这是用于定义数据表结构的SQL语句存储了与便签相关的数据信息包括了各种附加数据用来扩展便签功能。
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA1 + " INTEGER," +
DataColumns.DATA2 + " INTEGER," +
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")";//这是用于定义数据表结构的SQL语句存储了与便签相关的数据信息包括了各种附加数据用来扩展便签功能。
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
/**
* 便便
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
"CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* 便便
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_update " +
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" END";
"CREATE TRIGGER decrease_folder_count_on_update " +
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" END";
/**
* 便便
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_insert " +
" AFTER INSERT ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
"CREATE TRIGGER increase_folder_count_on_insert " +
" AFTER INSERT ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* 便便
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END";
"CREATE TRIGGER decrease_folder_count_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END";
/**
* 便{@link DataConstants#NOTE}
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " +
" AFTER INSERT ON " + TABLE.DATA +
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
"CREATE TRIGGER update_note_content_on_insert " +
" AFTER INSERT ON " + TABLE.DATA +
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has changed
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER update_note_content_on_update " +
" AFTER UPDATE ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
"CREATE TRIGGER update_note_content_on_update " +
" AFTER UPDATE ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
"CREATE TRIGGER update_note_content_on_delete " +
" AFTER delete ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";
"CREATE TRIGGER update_note_content_on_delete " +
" AFTER delete ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";
/**
* 便
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.DATA +
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END";
"CREATE TRIGGER delete_data_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.DATA +
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* 便
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.NOTE +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
"CREATE TRIGGER folder_delete_notes_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.NOTE +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* 便
*/
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";
"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";
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);

@ -29,22 +29,14 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.R;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
import net.micode.notes.R;//包含了应用程序的资源文件(如布局、图片等)
import net.micode.notes.data.Notes.DataColumns;//定义了一些常量,表示数据库表的列名。
import net.micode.notes.data.Notes.NoteColumns;//定义了一些常量,表示笔记表的列名。
import net.micode.notes.data.NotesDatabaseHelper.TABLE;//定义了一个枚举类型,表示数据库表的名称。
/**
* @Package: net.micode.notes.data
* @ClassName: NotesProvider
* @Description:
* ContentProvider,便,
*
* @Author: Dong Jiaqi
* @CreateDate: 12/23/2023 2327 PM
*/
public class NotesProvider extends ContentProvider {
private static final UriMatcher mMatcher;
public class NotesProvider extends ContentProvider {//android中的ContentProvider类
private static final UriMatcher mMatcher;//riMatcher是Android中的一个类用于匹配URI。
private NotesDatabaseHelper mHelper;
@ -58,70 +50,54 @@ public class NotesProvider extends ContentProvider {
private static final int URI_SEARCH = 5;
private static final int URI_SEARCH_SUGGEST = 6;
/**
* UriMatcher
* addURI()mMatcherUriMatcher
*/
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);//
//创建一个UriMatcher对象mMatcher初始值为UriMatcher.NO_MATCH表示没有任何匹配规则。
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
//第一个参数是authority授权第二个参数是路径第三个参数是匹配的URI类型。
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
}
}//根据不同的URI路径确定应该调用哪个处理程序来处理请求
//例如,当用户访问"http://example.com/note"时mMatcher会匹配到第一个规则
/**
* x'0A' represents the '\n' character in sqlite. For title and content in the search result,
* we will trim '\n' and white space in order to show more information.
*/
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + ","
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + ","
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
//用于搜索笔记的投影字段列表。这个投影字段列表可以用于构建SQL查询语句以便在数据库中搜索和检索相关笔记。
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE
+ " FROM " + TABLE.NOTE//从名为TABLE.NOTE的表中检索数据
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
/**
* onCreate()
* @return true
*/
//是一个SQL查询语句用于从数据库中检索与给定搜索条件匹配的笔记
@Override
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
/**
* query(),URI,
* @param uri URI
* @param projection
* @param selection
* @param selectionArgs selection
* @param sortOrder
* @return (Cursor)(c)
*/
@Override
//查询uri在数据库的位置
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null;
//获取可读数据库
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
/**
* switchURI
* 3URIURIILLegalArgumentExceptionURI
* URIURIAndroid ContentProvider
*/
switch (mMatcher.match(uri)) {
//匹配数据库中相应条目
case URI_NOTE:
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
@ -143,6 +119,7 @@ public class NotesProvider extends ContentProvider {
case URI_SEARCH:
case URI_SEARCH_SUGGEST:
if (sortOrder != null || projection != null) {
//异常情况
throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
}
@ -160,11 +137,6 @@ public class NotesProvider extends ContentProvider {
return null;
}
/**
* URI_SEARCH URI_SEARCH_SUGGEST rawQuery Cursor
* IllegalStateException Log.e() 便
*
*/
try {
searchString = String.format("%%%s%%", searchString);
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
@ -182,17 +154,13 @@ public class NotesProvider extends ContentProvider {
return c;
}
/**
* URI
* @param uri URI
* @param values
* @return URIContentUris.withAppendedId(uri, insertedId)
*/
@Override
//插入uri
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0;
SQLiteDatabase db = mHelper.getWritableDatabase();//获取可写的数据库
long dataId = 0, noteId = 0, insertedId = 0;//初始化
switch (mMatcher.match(uri)) {
//新增条目
case URI_NOTE:
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
@ -208,6 +176,7 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
//通知Android系统中的Notes应用程序某个笔记或数据已经发生了变化
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
@ -218,18 +187,15 @@ public class NotesProvider extends ContentProvider {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
//它通过调用getContentResolver().notifyChange()方法来实现这个功能。
//在这段代码中首先检查noteId和dataId是否大于0以确保它们是有效的ID。然后使用ContentUris.withAppendedId()方法来构建对应的URI
// 其中Notes.CONTENT_NOTE_URI和Notes.CONTENT_DATA_URI分别表示笔记和数据的URI。
// 最后调用getContext().getContentResolver().notifyChange()方法并传入构建好的URI以通知系统该URI所对应的资源已经发生了变化。
return ContentUris.withAppendedId(uri, insertedId);
}
/**
* URI
* @param uri URI
* @param selection
* @param selectionArgs selection
* @return
*/
@Override
//删除一个uri操作与上面差不多
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
@ -266,6 +232,7 @@ public class NotesProvider extends ContentProvider {
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
//通知系统相关数据已经发生变化,以便进行相应的更新或处理。
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
@ -275,25 +242,13 @@ public class NotesProvider extends ContentProvider {
return count;
}
/**
* URI
* @param uri URI
* @param values
* @param selection
* @param selectionArgs selection
* @return
*/
@Override
//更新uri
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false;
/**
* URIUniform Resource Identifier
* URI URI
* switch-case URI
*/
switch (mMatcher.match(uri)) {
case URI_NOTE:
increaseNoteVersion(-1, selection, selectionArgs);
@ -328,23 +283,13 @@ public class NotesProvider extends ContentProvider {
return count;
}
/**
* SQLWHERE
* @param selection
* @return
*/
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
/**
* 便
* @param id 便ID
* @param selection 便
* @param selectionArgs
*/
//这段代码是一个私有方法,用于增加笔记的版本号。
// 它接受三个参数id笔记的ID、selection查询条件和selectionArgs查询条件的参数
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120);
StringBuilder sql = new StringBuilder(120);//sql对象构建SQL语句
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
sql.append(" SET ");
@ -352,12 +297,14 @@ public class NotesProvider extends ContentProvider {
sql.append("=" + NoteColumns.VERSION + "+1 ");
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
sql.append(" WHERE ");//那么在WHERE子句中添加相应的条件
}
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
////将笔记ID等于给定id的条件添加到WHERE子句中
}
if (!TextUtils.isEmpty(selection)) {
//那么将解析后的查询条件添加到WHERE子句中。
String selectString = id > 0 ? parseSelection(selection) : selection;
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
@ -368,10 +315,6 @@ public class NotesProvider extends ContentProvider {
mHelper.getWritableDatabase().execSQL(sql.toString());
}
/**
*
* @param uri URI
*/
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub

@ -24,33 +24,13 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @Package: net.micode.notes.gtask.data
* @ClassName: MetaData
* @Description:
* MetaData Task
* GID JSON
* 访使
* @Author: Dong Jiaqi
* @CreateDate: 12/24/2023 9:53 AM
*/
public class MetaData extends Task {
private final static String TAG = MetaData.class.getSimpleName();
private String mRelatedGid = null;
/**
* GID
* @param gid Global Task ID
* @param metaInfo JSONObject
*/
public void setMeta(String gid, JSONObject metaInfo) {
/**
* metaInfo JSONObject GTaskStringUtils.META_HEAD_GTASK_ID gid
* 使 try-catch JSONException
*
* Java JSONObject put JSONException put 使 try-catch
*/
try {
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
@ -60,29 +40,19 @@ public class MetaData extends Task {
setName(GTaskStringUtils.META_NOTE_NAME);
}
//作用是获取任务的相关 GID并返回其字符串形式。
public String getRelatedGid() {
return mRelatedGid;//返回值是一个字符串类型的变量 mRelatedGid表示相关 GIDGlobal Task ID。mRelatedGid 是一个成员变量,它保存了在任务的元数据信息中提取出来的相关 GID。
return mRelatedGid;
}
//作用是判断任务是否值得保存。它通过检查任务的注释信息是否为null来确定任务是否值得保存。
@Override
public boolean isWorthSaving() {
return getNotes() != null;//如果注释信息不为null则返回true表示任务值得保存反之如果注释信息为null则返回false表示任务不值得保存。
return getNotes() != null;
}
/**
* JSON Task
* @param js JSONObject
*/
@Override
public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js);
if (getNotes() != null) {
/**
* GID mRelatedGid
* 使try-catch
*/
try {
JSONObject metaInfo = new JSONObject(getNotes().trim());
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
@ -96,7 +66,7 @@ public class MetaData extends Task {
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");//抛出一个IllegalAccessError异常并且提供异常的详细描述信息
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
}
@Override

@ -20,33 +20,24 @@ import android.database.Cursor;
import org.json.JSONObject;
/**
* @Package: net.micode.notes.gtask.data
* @ClassName: Node
* @Description:
* Node
* *
* @Author: Dong Jiaqi
* @CreateDate: 12/24/2023 10:23 AM
*/
public abstract class Node {
public static final int SYNC_ACTION_NONE = 0;//表示没有同步操作。
public static final int SYNC_ACTION_NONE = 0;
public static final int SYNC_ACTION_ADD_REMOTE = 1;//表示远程添加操作。
public static final int SYNC_ACTION_ADD_REMOTE = 1;
public static final int SYNC_ACTION_ADD_LOCAL = 2;//表示本地添加操作。
public static final int SYNC_ACTION_ADD_LOCAL = 2;
public static final int SYNC_ACTION_DEL_REMOTE = 3;//表示远程删除操作。
public static final int SYNC_ACTION_DEL_REMOTE = 3;
public static final int SYNC_ACTION_DEL_LOCAL = 4;//表示本地删除操作。
public static final int SYNC_ACTION_DEL_LOCAL = 4;
public static final int SYNC_ACTION_UPDATE_REMOTE = 5;//表示远程更新操作。
public static final int SYNC_ACTION_UPDATE_REMOTE = 5;
public static final int SYNC_ACTION_UPDATE_LOCAL = 6;//表示本地更新操作。
public static final int SYNC_ACTION_UPDATE_LOCAL = 6;
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;//表示更新冲突操作。
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;
public static final int SYNC_ACTION_ERROR = 8;//表示同步错误操作。
public static final int SYNC_ACTION_ERROR = 8;
private String mGid;
@ -75,66 +66,34 @@ public abstract class Node {
public abstract int getSyncAction(Cursor c);
/**
* gid
* @param gid
*/
public void setGid(String gid) {
this.mGid = gid;
}
/**
* name mName
* @param name
*/
public void setName(String name) {
this.mName = name;
}
/**
* lastModified mLastModified
* @param lastModified
*/
public void setLastModified(long lastModified) {
this.mLastModified = lastModified;
}
/**
* deleted mDeleted
* @param deleted true false
*/
public void setDeleted(boolean deleted) {
this.mDeleted = deleted;
}
/**
* gid mGid
* @return this.mGid
*/
public String getGid() {
return this.mGid;
}
/**
* mName
* @return this.mName
*/
public String getName() {
return this.mName;
}
/**
* mLastModified
* @return this.mLastModified
*/
public long getLastModified() {
return this.mLastModified;
}
/**
* mDeleted
* @return true false
*/
public boolean getDeleted() {
return this.mDeleted;
}

@ -34,33 +34,26 @@ import net.micode.notes.gtask.exception.ActionFailureException;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @Package: net.micode.notes.gtask.data
* @ClassName: SqlData
* @Description:
*
* @Author: Dong Jiaqi
* @CreateDate: 12/24/2023 10:58 AM
*/
public class SqlData {
private static final String TAG = SqlData.class.getSimpleName();
private static final int INVALID_ID = -99999;//定义了一个名为 INVALID_ID 的私有静态整型常量,并赋值为 -99999被用来表示无效的 ID 值。
private static final int INVALID_ID = -99999;
public static final String[] PROJECTION_DATA = new String[] {
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA3
};//定义了一个名为 PROJECTION_DATA 的字符串数组,其中包含了一组列名
};
public static final int DATA_ID_COLUMN = 0;//表示数据的 ID 在数据列中的索引位置,即第一列。
public static final int DATA_ID_COLUMN = 0;
public static final int DATA_MIME_TYPE_COLUMN = 1;//表示数据的 MIME 类型在数据列中的索引位置,即第二列。
public static final int DATA_MIME_TYPE_COLUMN = 1;
public static final int DATA_CONTENT_COLUMN = 2;//表示数据的内容在数据列中的索引位置,即第三列。
public static final int DATA_CONTENT_COLUMN = 2;
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;//表示数据的内容数据1在数据列中的索引位置即第四列。
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;//表示数据的内容数据3在数据列中的索引位置即第五列。
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
private ContentResolver mContentResolver;
@ -78,54 +71,36 @@ public class SqlData {
private ContentValues mDiffDataValues;
/**
* Context
* @param context 便
*/
public SqlData(Context context) {
mContentResolver = context.getContentResolver();//这是构造方法的定义,表明这是一个公共的构造方法,并且接受一个 Context 类型的参数。
mContentResolver = context.getContentResolver();
mIsCreate = true;
mDataId = INVALID_ID;
mDataMimeType = DataConstants.NOTE;
mDataContent = "";//成员变量初始化
mDataContent = "";
mDataContentData1 = 0;
mDataContentData3 = "";
mDiffDataValues = new ContentValues();//创建新的ContentValues对象
mDiffDataValues = new ContentValues();
}
/**
* ContextCursorCursor
* @param context 便
* @param c Cursor
*/
public SqlData(Context context, Cursor c) {
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);//调用 loadFromCursor() 方法,将传入的 Cursor 对象作为参数,以从 Cursor 对象中加载数据库中的数据到 SqlData 对象的成员变量中。
loadFromCursor(c);
mDiffDataValues = new ContentValues();
}
/**
* Cursor SqlData
* @param c Cursor
*/
private void loadFromCursor(Cursor c) {
mDataId = c.getLong(DATA_ID_COLUMN);//从 Cursor 对象中获取指定列索引为 DATA_ID_COLUMN 的长整型数据,并赋值给 mDataId 成员变量。
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);//从 Cursor 对象中获取指定列索引为 DATA_MIME_TYPE_COLUMN 的字符串数据,并赋值给 mDataMimeType 成员变量。
mDataId = c.getLong(DATA_ID_COLUMN);
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
mDataContent = c.getString(DATA_CONTENT_COLUMN);
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
}
/**
* JSONJSONmDiffDataValues
* @param js JSONObject
* @throws JSONException
*/
public void setContent(JSONObject js) throws JSONException {
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;//检查 JSON 对象 js 中是否包含名为 DataColumns.ID 的字段,如果包含则将其转换为 long 类型并赋给 dataId否则将 INVALID_ID 赋给 dataId。
if (mIsCreate || mDataId != dataId) {//检查是否正在创建新数据mIsCreate 为 true或者已有数据的 dataId 是否与新获取的 dataId 不同。
mDiffDataValues.put(DataColumns.ID, dataId);//如果满足条件,则将 DataColumns.ID 和对应的 dataId 放入 mDiffDataValues 中。
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;
if (mIsCreate || mDataId != dataId) {
mDiffDataValues.put(DataColumns.ID, dataId);
}
mDataId = dataId;
@ -155,53 +130,42 @@ public class SqlData {
mDataContentData3 = dataContentData3;
}
/**
* JSON
* @return JSONObject SqlData 使 null
* @throws JSONException
*/
public JSONObject getContent() throws JSONException {
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
JSONObject js = new JSONObject();
js.put(DataColumns.ID, mDataId);//将类的成员变量 mDataId 的值存储到 js 对象中,使用键名 DataColumns.ID。
js.put(DataColumns.MIME_TYPE, mDataMimeType);//将类的成员变量 mDataMimeType 的值存储到 js 对象中,使用键名 DataColumns.MIME_TYPE
js.put(DataColumns.ID, mDataId);
js.put(DataColumns.MIME_TYPE, mDataMimeType);
js.put(DataColumns.CONTENT, mDataContent);
js.put(DataColumns.DATA1, mDataContentData1);
js.put(DataColumns.DATA3, mDataContentData3);
return js;
}
/**
* IDmDiffDataValues
* @param noteId 便ID便ID
* @param validateVersion
* @param version
*/
public void commit(long noteId, boolean validateVersion, long version) {
if (mIsCreate) {//如果数据是新创建的
if (mIsCreate) {
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID);
}
mDiffDataValues.put(DataColumns.NOTE_ID, noteId); //设置便签的ID
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);//向数据库中插入数据
mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try {
mDataId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
} else {//如果不是新创建的数据
} else {
if (mDiffDataValues.size() > 0) {
int result = 0;
if (!validateVersion) {//如果不用验证版本,直接更新数据
if (!validateVersion) {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);
} else {//如果要验证版本,根据版本号更新数据
} else {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues,
" ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
@ -215,14 +179,10 @@ public class SqlData {
}
}
mDiffDataValues.clear();//提交后清空数据
mDiffDataValues.clear();
mIsCreate = false;
}
/**
* mDataId
* @return ID
*/
public long getId() {
return mDataId;
}

@ -37,14 +37,7 @@ import org.json.JSONObject;
import java.util.ArrayList;
/**
* @Package: net.micode.notes.gtask.data
* @ClassName: SqlNote
* @Description:
* SqlNote便便
* @Author: Dong Jiaqi
* @CreateDate: 12/24/2023 1718 PM
*/
public class SqlNote {
private static final String TAG = SqlNote.class.getSimpleName();
@ -59,9 +52,9 @@ public class SqlNote {
NoteColumns.VERSION
};
public static final int ID_COLUMN = 0;//便签的ID列的索引为0
public static final int ID_COLUMN = 0;
public static final int ALERTED_DATE_COLUMN = 1;//提醒日期列的索引为1
public static final int ALERTED_DATE_COLUMN = 1;
public static final int BG_COLOR_ID_COLUMN = 2;
@ -127,12 +120,8 @@ public class SqlNote {
private ContentValues mDiffNoteValues;
private ArrayList<SqlData> mDataList;//用Java中的ArrayList类定义了一个SqlData对象 mDataList用于存储从数据库查询中返回的便签数据
private ArrayList<SqlData> mDataList;
/**
* SqlNote SqlNote
* @param context 使
*/
public SqlNote(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
@ -154,50 +143,33 @@ public class SqlNote {
mDataList = new ArrayList<SqlData>();
}
/**
* SqlNote Cursor
* @param context 使
* @param c
*/
public SqlNote(Context context, Cursor c) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
if (mType == Notes.TYPE_NOTE) {
loadDataContent();
}
mDiffNoteValues = new ContentValues();
}
/**
* SqlNote ID
* @param context 使
* @param id 便ID
*/
public SqlNote(Context context, long id) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(id);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
if (mType == Notes.TYPE_NOTE) {
loadDataContent();
}
mDiffNoteValues = new ContentValues();
}
/**
* ID 便 SqlNote
* @param id 便 ID
*/
private void loadFromCursor(long id) {
Cursor c = null;
/**
* try-finally
*
* finally
*/
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] {
@ -210,15 +182,12 @@ public class SqlNote {
Log.w(TAG, "loadFromCursor: cursor = null");
}
} finally {
if (c != null)
if (c != null) {
c.close();
}
}
}
/**
* 便 SqlNote
* @param c
*/
private void loadFromCursor(Cursor c) {
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
@ -234,17 +203,9 @@ public class SqlNote {
mVersion = c.getLong(VERSION_COLUMN);
}
/**
* ID
* 便
*/
private void loadDataContent() {
Cursor c = null;
mDataList.clear();
/**
* ID mDataList
*
*/
try {
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
@ -263,24 +224,13 @@ public class SqlNote {
Log.w(TAG, "loadDataContent: cursor = null");
}
} finally {
if (c != null)
if (c != null) {
c.close();
}
}
}
/**
* JSONObject
* JSONObjectmDiffNoteValues
* @param js JSONObject
* @return truefalse
*/
public boolean setContent(JSONObject js) {
/**
* tryJSONJSONExceptioncatch
* catchfalse
*
*/
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
@ -291,14 +241,14 @@ public class SqlNote {
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
}//判断是否需要更新笔记的摘要snippet。它通过比较当前对象的mSnippet属性和传入的参数snippet如果两者不相等则将新的摘要值存储在mDiffNoteValues中。
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}//检查是否正在创建新的笔记mIsCreate为true或者当前笔记的类型与传入的类型值不相等mType != type。如果满足其中一个条件就会将新的类型值存储在mDiffNoteValues中。
}
mType = type;
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
@ -413,10 +363,6 @@ public class SqlNote {
return true;
}
/**
* JSON
* @return JSONObject
*/
public JSONObject getContent() {
try {
JSONObject js = new JSONObject();
@ -465,74 +411,39 @@ public class SqlNote {
return null;
}
/**
* IDmDiffNoteValues
* @param id longID
*/
public void setParentId(long id) {
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
}
/**
* Google TasksIDgidmDiffNoteValues便
* @param gid Google TasksID
*/
public void setGtaskId(String gid) {
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
}
/**
* IDsyncIdmDiffNoteValues便
* @param syncId longID
*/
public void setSyncId(long syncId) {
mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);
}
/**
*
*/
public void resetLocalModified() {
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
}
/**
* ID
* @return ID
*/
public long getId() {
return mId;
}
/**
* ID
* @return ID
*/
public long getParentId() {
return mParentId;
}
/**
*
* @return
*/
public String getSnippet() {
return mSnippet;
}
/**
* 便
* @return 便便truefalse
*/
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE;
}
/**
*
* @param validateVersion true
*/
public void commit(boolean validateVersion) {
if (mIsCreate) {
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
@ -589,8 +500,9 @@ public class SqlNote {
// refresh local info
loadFromCursor(mId);
if (mType == Notes.TYPE_NOTE)
if (mType == Notes.TYPE_NOTE) {
loadDataContent();
}
mDiffNoteValues.clear();
mIsCreate = false;

@ -31,16 +31,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @Package: net.micode.notes.gtask.data
* @ClassName: Task
* @Description:
* TaskNodeGoogle使
*
* JSON便Google
* @Author: Dong Jiaqi
* @CreateDate: 12/24/2023 1948 PM
*/
public class Task extends Node {
private static final String TAG = Task.class.getSimpleName();
@ -54,27 +45,17 @@ public class Task extends Node {
private TaskList mParent;
/**
*
* null
*/
public Task() {
super();//调用父类Node的构造方法确保父类的属性得到正确初始化
mCompleted = false;//任务完成状态设置为未完成
mNotes = null;//暂时没有便签笔记
mPriorSibling = null;//当前任务没有前节点
mParent = null;//当前任务没有父节点
mMetaInfo = null;//当前任务没有元数据信息
super();
mCompleted = false;
mNotes = null;
mPriorSibling = null;
mParent = null;
mMetaInfo = null;
}
/**
* JSON
* JSONActionFailureException
* @param actionId
* @return JSONObject
*/
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();//创建一个空的JSONObject对象。
JSONObject js = new JSONObject();
try {
// action_type
@ -116,17 +97,12 @@ public class Task extends Node {
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-create jsonobject");//抛出异常
throw new ActionFailureException("fail to generate task-create jsonobject");
}
return js;
}
/**
* JSON
* @param actionId
* @return JSONObject
*/
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
@ -159,11 +135,6 @@ public class Task extends Node {
return js;
}
/**
* JSONObject
* JSON
* @param js JSONObject
*/
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
@ -204,25 +175,17 @@ public class Task extends Node {
}
}
/**
* JSONObject
* @param js
*/
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
/**
* JSONObject
* 便便
*/
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {//检查便签类型是不是普通便签
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
Log.e(TAG, "invalid type");
return;
}
@ -241,11 +204,6 @@ public class Task extends Node {
}
}
/**
* JSONObject
* @return JSONObjectjs
* mMetaInfo
*/
public JSONObject getLocalJSONFromContent() {
String name = getName();
try {
@ -289,10 +247,6 @@ public class Task extends Node {
}
}
/**
*
* @param metaData MetaData
*/
public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) {
try {
@ -304,16 +258,6 @@ public class Task extends Node {
}
}
/**
* Cursor
* @param c Cursorc
* @return
* SYNC_ACTION_NONE
* SYNC_ACTION_UPDATE_LOCAL
* SYNC_ACTION_UPDATE_REMOTE
* SYNC_ACTION_UPDATE_CONFLICT
* SYNC_ACTION_ERROR
*/
public int getSyncAction(Cursor c) {
try {
JSONObject noteInfo = null;
@ -367,80 +311,39 @@ public class Task extends Node {
return SYNC_ACTION_ERROR;
}
/**
*
* @return booleantruefalse
*/
public boolean isWorthSaving() {
return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
|| (getNotes() != null && getNotes().trim().length() > 0);
}
/**
*
* 便
* @param completed boolean
*/
public void setCompleted(boolean completed) {
this.mCompleted = completed;
}
/**
*
* 便
* @param notes String
*/
public void setNotes(String notes) {
this.mNotes = notes;
}
/**
*
*
* @param priorSibling Task
*/
public void setPriorSibling(Task priorSibling) {
this.mPriorSibling = priorSibling;
}
/**
*
*
* @param parent TaskList
*/
public void setParent(TaskList parent) {
this.mParent = parent;
}
/**
*
* 便
* @return booleantruefalse
*/
public boolean getCompleted() {
return this.mCompleted;
}
/**
*
* @return String
*/
public String getNotes() {
return this.mNotes;
}
/**
*
* @return Tasknull
*/
public Task getPriorSibling() {
return this.mPriorSibling;
}
/**
*
* @return TaskListnull
*/
public TaskList getParent() {
return this.mParent;
}

@ -30,36 +30,19 @@ import org.json.JSONObject;
import java.util.ArrayList;
/**
* @Package: net.micode.notes.gtask.data
* @ClassName: TaskList
* @Description:
* TaskListNode
* JSON
* @Author: Dong Jiaqi
* @CreateDate: 12/24/2023 2048 PM
*/
public class TaskList extends Node {
private static final String TAG = TaskList.class.getSimpleName();//私有静态常量,用于在日志和调试中标识类名。
private static final String TAG = TaskList.class.getSimpleName();
private int mIndex;//私有整型变量,表示任务列表的索引。
private int mIndex;
private ArrayList<Task> mChildren;//私有ArrayList存储Task对象表示该任务列表下的子任务列表。
private ArrayList<Task> mChildren;
/**
* mChildrenTaskmIndex1
*/
public TaskList() {
super();
mChildren = new ArrayList<Task>();
mIndex = 1;
}
/**
* actionIdJSONObject
* @param actionId ID
* @return JSONObject
*/
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
@ -91,11 +74,6 @@ public class TaskList extends Node {
return js;
}
/**
* actionIdJSONObject
* @param actionId ID
* @return JSONObject
*/
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
@ -125,10 +103,6 @@ public class TaskList extends Node {
return js;
}
/**
* JSON
* @param js JSONObject
*/
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
@ -155,10 +129,6 @@ public class TaskList extends Node {
}
}
/**
* JSON
* @param js JSONObject
*/
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
@ -171,13 +141,14 @@ public class TaskList extends Node {
String name = folder.getString(NoteColumns.SNIPPET);
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name);
} else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER)
if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) {
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT);
else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER)
} else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) {
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE);
else
} else {
Log.e(TAG, "invalid system folder");
}
} else {
Log.e(TAG, "error type");
}
@ -187,10 +158,6 @@ public class TaskList extends Node {
}
}
/**
* JSON
* @return JSONObject
*/
public JSONObject getLocalJSONFromContent() {
try {
JSONObject js = new JSONObject();
@ -217,17 +184,6 @@ public class TaskList extends Node {
}
}
/**
*
* @param c Cursor
* @return
* SYNC_ACTION_NONE
* SYNC_ACTION_UPDATE_LOCAL
* SYNC_ACTION_ERROR
* SYNC_ACTION_UPDATE_REMOTEID,
* SYNC_ACTION_UPDATE_REMOTEID,
* SYNC_ACTION_ERROR
*/
public int getSyncAction(Cursor c) {
try {
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
@ -261,19 +217,10 @@ public class TaskList extends Node {
return SYNC_ACTION_ERROR;
}
/**
*
* @return
*/
public int getChildTaskCount() {
return mChildren.size();
}
/**
*
* @param task
* @return boolean:truefalse
*/
public boolean addChildTask(Task task) {
boolean ret = false;
if (task != null && !mChildren.contains(task)) {
@ -288,12 +235,6 @@ public class TaskList extends Node {
return ret;
}
/**
*
* @param task
* @param index 0
* @return boolean:truefalse
*/
public boolean addChildTask(Task task, int index) {
if (index < 0 || index > mChildren.size()) {
Log.e(TAG, "add child task: invalid index");
@ -320,11 +261,6 @@ public class TaskList extends Node {
return true;
}
/**
*
* @param task
* @return boolean:truefalse
*/
public boolean removeChildTask(Task task) {
boolean ret = false;
int index = mChildren.indexOf(task);
@ -346,12 +282,6 @@ public class TaskList extends Node {
return ret;
}
/**
*
* @param task
* @param index 0
* @return boolean:truefalse
*/
public boolean moveChildTask(Task task, int index) {
if (index < 0 || index >= mChildren.size()) {
@ -370,11 +300,6 @@ public class TaskList extends Node {
return (removeChildTask(task) && addChildTask(task, index));
}
/**
*
* @param gid gid()
* @return Taskgidnull
*/
public Task findChildTaskByGid(String gid) {
for (int i = 0; i < mChildren.size(); i++) {
Task t = mChildren.get(i);
@ -385,20 +310,10 @@ public class TaskList extends Node {
return null;
}
/**
*
* @param task
* @return int:0-1
*/
public int getChildTaskIndex(Task task) {
return mChildren.indexOf(task);
}
/**
*
* @param index 0
* @return Tasknull
*/
public Task getChildTaskByIndex(int index) {
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "getTaskByIndex: invalid index");
@ -407,11 +322,6 @@ public class TaskList extends Node {
return mChildren.get(index);
}
/**
*
* @param gid gid
* @return Taskgidnull
*/
public Task getChilTaskByGid(String gid) {
for (Task task : mChildren) {
if (task.getGid().equals(gid))
@ -420,26 +330,14 @@ public class TaskList extends Node {
return null;
}
/**
*
* @return ArrayList<Task>ArrayList
*/
public ArrayList<Task> getChildTaskList() {
return this.mChildren;
}
/**
*
* @param index
*/
public void setIndex(int index) {
this.mIndex = index;
}
/**
*
* @return
*/
public int getIndex() {
return this.mIndex;
}

@ -352,9 +352,9 @@ public class GTaskClient {
}
InputStream input = entity.getContent();
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
if (contentEncoding != null && "gzip".equalsIgnoreCase(contentEncoding)) {
input = new GZIPInputStream(entity.getContent());
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
} else if (contentEncoding != null && "deflate".equalsIgnoreCase(contentEncoding)) {
Inflater inflater = new Inflater(true);
input = new InflaterInputStream(entity.getContent(), inflater);
}
@ -520,8 +520,9 @@ public class GTaskClient {
commitUpdate();
}
if (mUpdateArray == null)
if (mUpdateArray == null) {
mUpdateArray = new JSONArray();
}
mUpdateArray.put(node.getUpdateAction(getActionId()));
}
}

@ -206,8 +206,9 @@ public class GTaskManager {
*@return void
*/
private void initGTaskList() throws NetworkFailureException {
if (mCancelled)
if (mCancelled) {
return;
}
//getInstance即为创建一个实例client应指远端客户机用于与远程服务器进行通信
GTaskClient client = GTaskClient.getInstance();
try {
@ -461,8 +462,9 @@ public class GTaskManager {
mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid);
// for system folder, only update remote name if necessary
if (!node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT))
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) {
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
}
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
@ -494,8 +496,9 @@ public class GTaskManager {
// necessary
if (!node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE))
+ GTaskStringUtils.FOLDER_CALL_NOTE)) {
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
}
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
@ -558,8 +561,9 @@ public class GTaskManager {
}
}
if (!mCancelled)
if (!mCancelled) {
GTaskClient.getInstance().commitUpdate();
}
}
/**
@ -769,12 +773,13 @@ public class GTaskManager {
// we need to skip folder if it has already existed
String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX;
if (sqlNote.getId() == Notes.ID_ROOT_FOLDER)
if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) {
folderName += GTaskStringUtils.FOLDER_DEFAULT;
else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER)
} else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) {
folderName += GTaskStringUtils.FOLDER_CALL_NOTE;
else
} else {
folderName += sqlNote.getSnippet();
}
//iterator迭代器通过统一的接口迭代所有的map元素
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();

@ -280,7 +280,9 @@ public class WorkingNote {
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
}
public void setmContent(String text){
mContent = text;
}
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {
mContent = text;

@ -0,0 +1,24 @@
package net.micode.notes.translate;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
//源URL https://fanyi-api.baidu.com/api/trans/vip/translate
//参数如下
// String q 英文单词/中文
// String from 原始语种 zh中文/eh英文
// String to 目标语种 zh中文/eh英文
// String from zh中文/eh英文
// String appid 你的appid
// String salt 随机数(整形转字符串)
// String sign 签名 32位字母小写MD5编码的 appid+q+salt+密钥
public interface BaiduTranslateService {
//翻译接口
//表示提交表单数据,@Field注解键名
//适用于数据量少的情况
@POST("translate")
@FormUrlEncoded
Call<RespondBean> translate(@Field("q") String q, @Field("from") String from, @Field("to") String to, @Field("appid") String appid, @Field("salt") String salt,
@Field("sign") String sign);
}

@ -0,0 +1,35 @@
package net.micode.notes.translate;
import java.security.MessageDigest;
/**
* () MD5
*/
public class MD5Utils {
/**
* MD5使
*
* @param info String
* @return String
*/
public static String getMD5Code(String info) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(info.getBytes("utf-8"));//设置编码格式
byte[] encryption = md5.digest();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < encryption.length; i++) {
if (Integer.toHexString(0xff & encryption[i]).length() == 1) {
stringBuffer.append("0").append(Integer.toHexString(0xff & encryption[i]));
} else {
stringBuffer.append(Integer.toHexString(0xff & encryption[i]));
}
}
return stringBuffer.toString();
} catch (Exception e) {
return "MD5加密异常";
}
}
}

@ -0,0 +1,65 @@
package net.micode.notes.translate;
import java.util.List;
public class RespondBean {
/**
* from : zh
* to : en
* trans_result : [{"src":"你好","dst":"Hello"}]
*/
private String from;
private String to;
private List<TransResultBean> trans_result;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public List<TransResultBean> getTrans_result() {
return trans_result;
}
public void setTrans_result(List<TransResultBean> trans_result) {
this.trans_result = trans_result;
}
public static class TransResultBean {
/**
* src :
* dst : Hello
*/
private String src;
private String dst;
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getDst() {
return dst;
}
public void setDst(String dst) {
this.dst = dst;
}
}
}

@ -39,77 +39,36 @@ import net.micode.notes.tool.DataUtils;
import java.io.IOException;
/**
*
* @ProjectName:
* @Package: net.micode.notes.ui
* @ClassName: AlarmAlertActivity
* @Description: AlarmAlertActivity
* 便AlarmAlertActivity
*
*
* @Author: xumingyang
* @CreateDate: 2023-12-24 10:33
* @UpdateUser:
* @UpdateDate: 2023-12-24 10:33
* @UpdateRemark:
* @Version: 1.0
*/
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private long mNoteId; //文本在数据库存储中的ID号
private String mSnippet; //闹钟提示时出现的文本片段
private long mNoteId;
private String mSnippet;
private static final int SNIPPET_PREW_MAX_LEN = 60;
MediaPlayer mPlayer;
/**
* @method onCreate
* @description :
*
*
* Intent便ID
* 使便ID便
* MediaPlayer
* 便便
* 便
* 便
* @date: 2023-12-24 10:41
* @author: xumingyang
* @param
* @return
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Bundle类型的数据与Map类型的数据相似都是以key-value的形式存储数据的
//onsaveInstanceState方法是用来保存Activity的状态的
//能从onCreate的参数savedInsanceState中获得状态数
requestWindowFeature(Window.FEATURE_NO_TITLE);
//界面显示——无标题
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
//保持窗体点亮
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
//将窗体点亮
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
//允许窗体点亮时锁屏
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}//在手机锁屏后如果到了闹钟提示时间,点亮屏幕
}
Intent intent = getIntent();
try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
//根据ID从数据库中获取标签的内容
//getContentResolver是实现数据共享实例存储。
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
: mSnippet;
//判断标签片段是否达到符合长度
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
@ -118,41 +77,20 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
mPlayer = new MediaPlayer();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog();
//弹出对话框
playAlarmSound();
//闹钟提示音激发
} else {
finish();
//完成闹钟动作
}
}
/**
* @method isScreenOn
* @description
* @date: 2023-12-24 10:45
* @author: xumingyang
* @param
* @return bool
*/
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
/**
* @method playAlarmSound
* @description:
*
*
* @date: 2023-12-24 10:47
* @author: xumingyang
* @param
* @return
*/
private void playAlarmSound() {
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
//调用系统的铃声管理URI得到闹钟提示音
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
@ -163,19 +101,12 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
try {
mPlayer.setDataSource(this, url);
//方法setDataSource(Context context, Uri uri)
//解释:无返回值,设置多媒体数据来源【根据 Uri】
mPlayer.prepare();
//准备同步
mPlayer.setLooping(true);
//设置是否循环播放
mPlayer.start();
//开始播放
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
//e.printStackTrace()函数功能是抛出异常, 还将显示出更深的调用信息
//System.out.println(e),这个方法打印出异常,并且输出在哪里出现的异常
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@ -188,99 +119,39 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
}
/**
* @method showActionDialog
* @description
* AlertDialog.BuilderR.string.app_name
* mSnippet
* Positive ButtonR.string.notealert_ok
* isScreenOn()Negative ButtonR.string.notealert_enter
* dialog.show().setOnDismissListener(this)
* @date: 2023-12-24 10:51
* @author: xumingyang
* @param
* @return
*/
private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
/*
* AlertDialogProtected
* newAlertDialogAlertDialog
* AlertDialogAlertDialog.Buildercreate()
* dialogAlertDialog
*/
dialog.setTitle(R.string.app_name);
//为对话框设置标题
dialog.setMessage(mSnippet);
//为对话框设置内容
dialog.setPositiveButton(R.string.notealert_ok, this);
//给对话框添加"Yes"按钮
if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);
}//对话框添加"No"按钮
}
dialog.show().setOnDismissListener(this);
}
/**
* @method onClick
* @description :
*
* 便idActivity
* @date: 2023-12-24 10:55
* @author: xumingyang
* @param
* @return
*/
public void onClick(DialogInterface dialog, int which) {
switch (which) {
//用which来选择click后下一步的操作
case DialogInterface.BUTTON_NEGATIVE:
//这是取消操作
Intent intent = new Intent(this, NoteEditActivity.class);
//实现两个类间的数据传输
intent.setAction(Intent.ACTION_VIEW);
//设置动作属性
intent.putExtra(Intent.EXTRA_UID, mNoteId);
//实现key-value对
//EXTRA_UID为keymNoteId为键
startActivity(intent);
//开始动作
break;
default:
//这是确定操作'
break;
}
}
/**
* @method onDismiss
* @description Activity
* @date: 2023-12-24 10:57
* @author: xumingyang
* @param
* @return
*/
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
//停止闹钟声音
finish();
//完成该动作
}
/**
* @method stopAlarmSound
* @description
* @date: 2023-12-24 10:58
* @author: xumingyang
* @param
* @return
*/
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
//停止播放
mPlayer.release();
//释放MediaPlayer对象
mPlayer = null;
}
}

@ -27,21 +27,6 @@ import android.database.Cursor;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/**
*
* @ProjectName:
* @Package: net.micode.notes.ui
* @ClassName: AlarmInitReceiver
* @Description: AlarmInitReceiver便广BroadcastReceiver
* 广
* @Author: xumingyang
* @CreateDate: 2023-12-24 11:11
* @UpdateUser:
* @UpdateDate: 2023-12-24 11:11
* @UpdateRemark:
* @Version: 1.0
*/
public class AlarmInitReceiver extends BroadcastReceiver {
@ -49,35 +34,19 @@ public class AlarmInitReceiver extends BroadcastReceiver {
NoteColumns.ID,
NoteColumns.ALERTED_DATE
};
//对数据库的操作调用标签ID和闹钟时间
private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1;
/**
* @method onReceive
* @description
* 便
* @date: 2023-12-24 11:26
* @author: xumingyang
* @param *Cursor
* alertDate
* Intentsender广AlarmReceiver
* PendingIntent使getBroadcast()广PendingIntentpendingIntent
* @return Cursorc
*/
@Override
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis();
//System.currentTimeMillis()产生一个当前的毫秒
//这个毫秒其实就是自1970年1月1日0时起的毫秒数
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) },
//将long变量currentDate转化为字符串
null);
//Cursor在这里的作用是通过查找数据库中的标签内容找到和当前系统时间相等的标签
if (c != null) {
if (c.moveToFirst()) {
do {
@ -93,9 +62,4 @@ public class AlarmInitReceiver extends BroadcastReceiver {
c.close();
}
}
/*
*
* IntentPendingIntentAlarmManager
*
*/
}

@ -20,37 +20,11 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
*
* @ProjectName:
* @Package: net.micode.notes.ui
* @ClassName: AlarmReceiver
* @Description: AlarmReceiver便
*
* @Author: xumingyang
* @CreateDate: 2023-12-24 12:46
* @UpdateUser:
* @UpdateDate: 2023-12-24 12:46
* @UpdateRemark:
* @Version: 1.0
*/
/**
* @method
* @description 广AlarmAlertActivity
* @param *Context contextIntent intentcontextintent广
* @return
*/
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//重写了onReceive()方法,该方法在接收到广播时会被调用
intent.setClass(context, AlarmAlertActivity.class);
////启动AlarmAlertActivity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
////activity要存在于activity的栈中而非activity的途径启动activity时必然不存在一个activity的栈
//所以要新起一个栈装入启动的activity
context.startActivity(intent);
}
}

@ -28,23 +28,8 @@ import android.view.View;
import android.widget.FrameLayout;
import android.widget.NumberPicker;
/**
*
* @ProjectName:
* @Package: net.micode.notes.ui
* @ClassName: DateTimePicker
* @Description:
* 使NumberPicker便
* @Author: xumingyang
* @CreateDate: 2023-12-24 12:58
* @UpdateUser:
* @UpdateDate: 2023-12-24 12:58
* @UpdateRemark:
* @Version: 1.0
*/
public class DateTimePicker extends FrameLayout {
//FrameLayout是布局模板之一
//所有的子元素全部在屏幕的右上方
private static final boolean DEFAULT_ENABLE_STATE = true;
private static final int HOURS_IN_HALF_DAY = 12;
@ -60,15 +45,13 @@ public class DateTimePicker extends FrameLayout {
private static final int MINUT_SPINNER_MAX_VAL = 59;
private static final int AMPM_SPINNER_MIN_VAL = 0;
private static final int AMPM_SPINNER_MAX_VAL = 1;
//初始化控件
private final NumberPicker mDateSpinner;
private final NumberPicker mHourSpinner;
private final NumberPicker mMinuteSpinner;
private final NumberPicker mAmPmSpinner;
//NumberPicker是数字选择器
//这里定义的四个变量全部是在设置闹钟时需要选择的变量(如日期、时、分、上午或者下午)
private Calendar mDate;
//定义了Calendar类型的变量mDate用于操作时间
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
private boolean mIsAm;
@ -89,22 +72,8 @@ public class DateTimePicker extends FrameLayout {
onDateTimeChanged();
}
};
//OnValueChangeListener这是时间改变监听器这里主要是对日期的监听
//将现在日期的值传递给mDateupdateDateControl是同步操作
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
//这里是对 小时Hour 的监听
/**
* @method onValueChange
* @description NumberPicker
*
* 24
* @date: 2023-12-24 13:03
* @author: xumingyang
* @param *Calendarcal便
* @return isdateChanged bool
*/
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean isDateChanged = false;
@ -114,33 +83,29 @@ public class DateTimePicker extends FrameLayout {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
//这里是对于12小时制时晚上11点和12点交替时对日期的更改
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}//这里是对于12小时制时晚上11点和12点交替时对日期的更改
}
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
mIsAm = !mIsAm;
updateAmPmControl();
}//这里是对于12小时制时中午11点和12点交替时对AM和PM的更改
}
} else {
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
//这里是对于24小时制时晚上11点和12点交替时对日期的更改
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
}//这里是对于12小时制时凌晨11点和12点交替时对日期的更改
}
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
//通过数字选择器对newHour的赋值
mDate.set(Calendar.HOUR_OF_DAY, newHour);
//通过set函数将新的Hour值传给mDate
onDateTimeChanged();
if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR));
@ -151,25 +116,16 @@ public class DateTimePicker extends FrameLayout {
};
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
/**
* @method onValueChange
* @description NumberPicker
*
* @param *picker NumberPicker oldVal newVal
*/
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0;
//设置offset作为小时改变的一个记录数据
if (oldVal == maxValue && newVal == minValue) {
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) {
offset -= 1;
}
//如果原值为59新值为0则offset加1
//如果原值为0新值为59则offset减1
if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset);
mHourSpinner.setValue(getCurrentHour());
@ -189,15 +145,9 @@ public class DateTimePicker extends FrameLayout {
};
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
/**
* @method onValueChange
* @description NumberPicker
* /
*/
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mIsAm = !mIsAm;
//对AM和PM的监听
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
} else {
@ -216,25 +166,18 @@ public class DateTimePicker extends FrameLayout {
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
}
//通过对数据库的访问,获取当前的系统时间
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}
//上面函数的得到的是一个天文数字1970至今的秒数需要DateFormat将其变得有意义
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
//获取系统时间
mDate = Calendar.getInstance();
mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this);
/*
* Activitylayoutlayout
* layoutinflate()layout
* findViewById()
*/
mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
@ -271,28 +214,17 @@ public class DateTimePicker extends FrameLayout {
mInitialising = false;
}
/**
* @method setEnabled
* @description
* @param * enabled
* @return mIsEnabled enabled
*/
@Override
public void setEnabled(boolean enabled) {
if (mIsEnabled == enabled) {
return;
}
/*
* enabled mIsEnabled
*
*/
super.setEnabled(enabled);
mDateSpinner.setEnabled(enabled);
mMinuteSpinner.setEnabled(enabled);
mHourSpinner.setEnabled(enabled);
mAmPmSpinner.setEnabled(enabled);
mIsEnabled = enabled;
//将 mIsEnabled 的值更新为传入的 enabled以保持状态同步
}
@Override
@ -307,7 +239,7 @@ public class DateTimePicker extends FrameLayout {
*/
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
}//实现函数——得到当前的秒数
}
/**
* Set the current date
@ -319,7 +251,7 @@ public class DateTimePicker extends FrameLayout {
cal.setTimeInMillis(date);
setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
}//实现函数功能——设置当前的时间参数是date
}
/**
* Set the current date
@ -337,14 +269,13 @@ public class DateTimePicker extends FrameLayout {
setCurrentDay(dayOfMonth);
setCurrentHour(hourOfDay);
setCurrentMinute(minute);
}//实现函数功能——设置当前的时间,参数是各详细的变量
}
/**
* Get current year
*
* @return The current year
*/
//下面是得到year、month、day等值
public int getCurrentYear() {
return mDate.get(Calendar.YEAR);
}
@ -515,7 +446,7 @@ public class DateTimePicker extends FrameLayout {
mDateSpinner.setDisplayedValues(mDateDisplayValues);
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);
mDateSpinner.invalidate();
}// 对于星期几的算法
}
private void updateAmPmControl() {
if (mIs24HourView) {
@ -525,7 +456,7 @@ public class DateTimePicker extends FrameLayout {
mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE);
}
}// 对于上下午操作的算法
}
private void updateHourControl() {
if (mIs24HourView) {
@ -535,7 +466,7 @@ public class DateTimePicker extends FrameLayout {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
}
}// 对与小时的算法
}
/**
* Set the callback that indicates the 'Set' button has been pressed.

@ -29,43 +29,21 @@ import android.content.DialogInterface.OnClickListener;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
/**
*
* @ProjectName: DateTimePickerDialog
* @Package: net.micode.notes.ui
* @ClassName: DateTimePickerDialog
* @Description: DateTimePickerDialog
* 便
* DateTimePickerDialog 便使便
* @Author: xumingyang
* @CreateDate: 2023-12-24 13:52
* @UpdateUser:
* @UpdateDate: 2023-12-24 13:52
* @UpdateRemark:
* @Version: 1.0
*/
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
private Calendar mDate = Calendar.getInstance();
//创建一个Calendar类型的变量 mDate方便时间的操作
private boolean mIs24HourView;
private OnDateTimeSetListener mOnDateTimeSetListener;
//声明一个时间日期滚动选择控件 mOnDateTimeSetListener
private DateTimePicker mDateTimePicker;
//DateTimePicker控件控件一般用于让用户可以从日期列表中选择单个值。
//运行时,单击控件边上的下拉箭头,会显示为两个部分:一个下拉列表,一个用于选择日期的
public interface OnDateTimeSetListener {
void OnDateTimeSet(AlertDialog dialog, long date);
}
public DateTimePickerDialog(Context context, long date) {
//对该界面对话框的实例化
super(context);
//对数据库的操作
mDateTimePicker = new DateTimePicker(context);
setView(mDateTimePicker);
//添加一个子视图
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
@ -74,21 +52,15 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
mDate.set(Calendar.MINUTE, minute);
//将视图中的各选项设置为系统当前时间
updateTitle(mDate.getTimeInMillis());
}
});
mDate.setTimeInMillis(date);
//得到系统时间
mDate.set(Calendar.SECOND, 0);
//将秒数设置为0 对日期时间进行标准化处理
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
//将日期时间选择器设置为当前设置的日期时间。
setButton(context.getString(R.string.datetime_dialog_ok), this);
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
//设置按钮
set24HourView(DateFormat.is24HourFormat(this.getContext()));
//时间标准化打印
updateTitle(mDate.getTimeInMillis());
}
@ -98,7 +70,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack;
}//将时间日期滚动选择控件实例化
}
private void updateTitle(long date) {
int flag =
@ -107,13 +79,12 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
DateUtils.FORMAT_SHOW_TIME;
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
}//android开发中常见日期管理工具类API——DateUtils按照上下午显示时间
}
public void onClick(DialogInterface arg0, int arg1) {
if (mOnDateTimeSetListener != null) {
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
}
}//第一个参数arg0是接收到点击事件的对话框
//第二个参数arg1是该对话框上的按钮
}
}

@ -27,38 +27,17 @@ import android.widget.PopupMenu.OnMenuItemClickListener;
import net.micode.notes.R;
/**
*
* @ProjectName:
* @Package: net.micode.notes.ui
* @ClassName: DropdownMenu
* @Description: DropdownMenu
* DropdownMenu
* 1.使DropdownMenu便
* 2.使DropdownMenu
* 3.使DropdownMenu
* @Author: xumingyang
* @CreateDate: 2023-12-24 13:57
* @UpdateUser:
* @UpdateDate: 2023-12-24 13:57
* @UpdateRemark:
* @Version: 1.0
*/
public class DropdownMenu {
private Button mButton;
private PopupMenu mPopupMenu;
//声明一个下拉菜单
private Menu mMenu;
public DropdownMenu(Context context, Button button, int menuId) {
mButton = button;
mButton.setBackgroundResource(R.drawable.dropdown_icon);
//设置这个view的背景
mPopupMenu = new PopupMenu(context, mButton);
mMenu = mPopupMenu.getMenu();
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
//MenuInflater是用来实例化Menu目录下的Menu布局文件
//根据ID来确认menu的内容选项
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show();
@ -70,13 +49,13 @@ public class DropdownMenu {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener);
}
}//设置菜单的监听
}
public MenuItem findItem(int id) {
return mMenu.findItem(id);
}
//对于菜单选项的初始化,根据索引搜索菜单需要的选项
public void setTitle(CharSequence title) {
mButton.setText(title);
}
}//布局文件,设置标题
}

@ -28,54 +28,25 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/**
*
* @ProjectName:
* @Package: net.micode.notes.ui
* @ClassName: FoldersListAdapter
* @Description: FoldersListAdapter
* @Author: xumingyang
* @CreateDate: 2023-12-24 14:05
* @UpdateUser:
* @UpdateDate: 2023-12-24 14:05
* @UpdateRemark:
* @Version: 1.0
*/
public class FoldersListAdapter extends CursorAdapter {
/*
* CursorAdapterCursorListView
* FoldersListAdapterCursorAdapter
* 便
* folder
*/
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
};//调用数据库中便签的ID和片段
};
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
/**
* @method FoldersListAdapter
* @description FoldersListAdapter
* @param context
* c Cursor
*/
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}//数据库操作
}
/**
* @method newView
* @description
* @return 使
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new FolderListItem(context);
}//创建一个文件夹,对于各文件夹中子标签的初始化
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
@ -84,23 +55,20 @@ public class FoldersListAdapter extends CursorAdapter {
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName);
}
}//将各个布局文件绑定起来
}
public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}//根据数据库中标签的ID得到标签的各项内容
}
private class FolderListItem extends LinearLayout {
private TextView mName;
public FolderListItem(Context context) {
super(context);
//操作数据库
inflate(context, R.layout.folder_list_item, this);
//根据布局文件的名字等信息将其找出来
mName = (TextView) findViewById(R.id.tv_folder_name);
}

@ -19,22 +19,38 @@ package net.micode.notes.ui;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.speech.tts.TextToSpeech;
import android.support.annotation.RequiresApi;
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;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@ -43,10 +59,12 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -65,15 +83,32 @@ import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.micode.notes.translate.BaiduTranslateService;
import net.micode.notes.translate.RespondBean;
import net.micode.notes.translate.MD5Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import android.speech.tts.TextToSpeech.OnInitListener;
public class NoteEditActivity extends Activity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener {
public static void setmChanged(Stack mChanged) {
NoteEditActivity.mChanged = mChanged;
}
private class HeadViewHolder {
public TextView tvModified;
@ -149,22 +184,338 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery;
private Pattern mPattern;
private CharSequence restore_translate = null;
private boolean mIsRvoke = false;
private TextToSpeech mTTS;
private static Stack mChanged;
private final int PHOTO_REQUEST = 1;
private Dialog alertDialog2;
Context context;
private static final int MAX_TIME_OF_RVOKE_TIME=100;
private final int MAX_OF_RVOKE_TIME=100;
public void translateChtoEn() {
//准备请求百度翻译接口需要的参数
final EditText editable = findViewById(R.id.note_edit_view);
String word = editable.getText().toString();
word = word.replaceAll("\\n","//");
String from = "auto";//源语种 en 英语 zh 中文
//String中英文占用一个字节中文占用两个字节
//利用String的这个存储特性可以用来判断String中有没有中文。
// to = "zh"; //没有汉字 英译中
String to = "en";//含有汉字 中译英
String appid = "20240103001929054";//appid 管理控制台有
String salt = (int) (Math.random() * 100 + 1) + "";//随机数这里范围是[0,100]整数无强制要求
String key = "Xa_yB5ihrTIaG8Nlv4S6";//密钥 管理控制台有
String secretKey = appid + word + salt + key;// secretKey = appid+q+salt+密钥
String sign = MD5Utils.getMD5Code(secretKey);// 签名 = secretKey 的MD5加密32位字母小写
Log.d(TAG, "secretKey" + secretKey);
Log.d(TAG, "sign: " + sign);
Retrofit retrofitBaidu = new Retrofit.Builder()
.baseUrl("https://fanyi-api.baidu.com/api/trans/vip/")
.addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
.build();
BaiduTranslateService baiduTranslateService =retrofitBaidu.create(BaiduTranslateService.class);
retrofit2.Call<RespondBean> call = baiduTranslateService.translate(word, from, to, appid, salt, sign);
call.enqueue(new Callback<RespondBean>() {
@Override
public void onResponse(Call<RespondBean> call, Response<RespondBean> response) {
//请求成功
Log.d(TAG, "onResponse: 请求成功");
RespondBean respondBean = response.body();//返回的JSON字符串对应的对象
String result = respondBean.getTrans_result().get(0).getDst();//获取翻译的字符串String
editable.setText(result);
Log.d(TAG, "中译英结果" + result);
}
@Override
public void onFailure(Call<RespondBean> call, Throwable t) {
//请求失败 打印异常
Log.d(TAG, "onResponse: 请求失败 " + t);
}
});
}
public void translateEntoCh() {
//准备请求百度翻译接口需要的参数
final EditText editable = findViewById(R.id.note_edit_view);
String word = editable.getText().toString();
word = word.replaceAll("\\n","//");
Log.d(TAG, word);
String from = "auto";//源语种 en 英语 zh 中文
//String中英文占用一个字节中文占用两个字节
//利用String的这个存储特性可以用来判断String中有没有中文。
// to = "zh"; //没有汉字 英译中
String to = "zh";//含有汉字 英译中
String appid = "20240103001929054";//appid 管理控制台有
String salt = (int) (Math.random() * 100 + 1) + "";//随机数这里范围是[0,100]整数无强制要求
String key = "Xa_yB5ihrTIaG8Nlv4S6";//密钥 管理控制台有
String secretKey = appid + word + salt + key;// secretKey = appid+q+salt+密钥
String sign = MD5Utils.getMD5Code(secretKey);// 签名 = secretKey 的MD5加密32位字母小写
Log.d(TAG, "secretKey" + secretKey);
Log.d(TAG, "sign: " + sign);
Retrofit retrofitBaidu = new Retrofit.Builder()
.baseUrl("https://fanyi-api.baidu.com/api/trans/vip/")
.addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
.build();
BaiduTranslateService baiduTranslateService =retrofitBaidu.create(BaiduTranslateService.class);
retrofit2.Call<RespondBean> call = baiduTranslateService.translate(word, from, to, appid, salt, sign);
call.enqueue(new Callback<RespondBean>() {
@Override
public void onResponse(Call<RespondBean> call, Response<RespondBean> response) {
//请求成功
Log.d(TAG, "onResponse: 请求成功");
RespondBean respondBean = response.body();//返回的JSON字符串对应的对象
String result = respondBean.getTrans_result().get(0).getDst();//获取翻译的字符串String
editable.setText(result);
Log.d(TAG, "英译中结果" + result);
}
@Override
public void onFailure(Call<RespondBean> call, Throwable t) {
//请求失败 打印异常
Log.d(TAG, "onResponse: 请求失败 " + t);
}
});
}
public void doTranslate(){
final EditText editable = findViewById(R.id.note_edit_view);
final Button get_local = findViewById(R.id.translate); //R.id.translate是定义在界面左上角的按钮
get_local.setOnClickListener(new OnClickListener() { //如果点击按钮,则触发
@Override
public void onClick(final View v) {
Button trans1 = new Button(NoteEditActivity.this); //三个功能的按钮
Button trans2 = new Button(NoteEditActivity.this);
Button trans3 = new Button(NoteEditActivity.this);
trans1.setText("中文翻译为英文");
trans2.setText("英文翻译为中文");
trans3.setText("还原");
LinearLayout linear = new LinearLayout(NoteEditActivity.this); //定义线性表结构
linear.setOrientation(LinearLayout.VERTICAL); //设置为垂直结构
linear.addView(trans1); //将三个按钮添加到线性表中
linear.addView(trans2);
linear.addView(trans3);
AlertDialog.Builder builder = new AlertDialog.Builder(NoteEditActivity.this); //定义一个AlertDialog生成器
builder.setView(linear); //附上线性表结构
builder.setTitle("请选择翻译模式"); //提示语句
AlertDialog choose_trans = builder.create(); //生成一个AlertDialog的对话框
choose_trans.show(); //展示
trans1.setOnClickListener(new OnClickListener() { //如果点击第一个按钮,则触发
@Override
public void onClick(View v) {
restore_translate = editable.getText();
Log.d(TAG, "666" + restore_translate);
choose_trans.dismiss();
if(restore_translate == null){
Toast.makeText(NoteEditActivity.this, "当前无可翻译内容", Toast.LENGTH_SHORT).show();
}
else{
translateChtoEn();
Toast.makeText(NoteEditActivity.this, "中文翻译为英文", Toast.LENGTH_SHORT).show();
}
}
});
trans2.setOnClickListener(new OnClickListener(){ //如果点击第二个按钮,则触发
@Override
public void onClick(View v) {
restore_translate = editable.getText();
Log.d(TAG, "666" + restore_translate);
choose_trans.dismiss();
if(restore_translate == null){
Toast.makeText(NoteEditActivity.this, "当前无可翻译内容", Toast.LENGTH_SHORT).show();
}
else{
translateEntoCh();
Toast.makeText(NoteEditActivity.this, "英文翻译为中文", Toast.LENGTH_SHORT).show();
}
}
});
trans3.setOnClickListener(new OnClickListener() { //如果点击第三个按钮,则触发
@Override
public void onClick(View v) {
choose_trans.dismiss();
Log.d(TAG, "666" + restore_translate);
if (restore_translate == null ||
restore_translate.toString().equals(editable.getText().toString())) {
Toast.makeText(NoteEditActivity.this, "无可还原内容", Toast.LENGTH_SHORT).show();
} else {
editable.setText(restore_translate);
Toast.makeText(NoteEditActivity.this, "已还原", Toast.LENGTH_SHORT).show();//功能语句
}
}
});
}
});
}
//图片地址转换为图片
private void convertToImage() {
NoteEditText noteEditText = (NoteEditText) findViewById(R.id.note_edit_view);
Editable editable = noteEditText.getText();
String noteText = editable.toString();
int length = editable.length();
for (int i = 0; i < length; i++) {
for (int j = i; j < length; j++) {
String img_fragment = noteText.substring(i, j + 1);
if (img_fragment.length() > 15 && img_fragment.endsWith("[/local]") && img_fragment.startsWith("[local]")) {
int limit = 7;
int len = img_fragment.length() - 15;
String path = img_fragment.substring(limit, limit + len);
Bitmap bitmap = null;
Log.d(TAG, "图片的路径是:" + path);
try {
bitmap = BitmapFactory.decodeFile(path);
} catch (Exception e) {
e.printStackTrace();
}
if (bitmap != null) {
Log.d(TAG, "图片不为null");
ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
String ss = "[local]" + path + "[/local]";
SpannableString spannableString = new SpannableString(ss);
spannableString.setSpan(imageSpan, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Log.d(TAG, "Create spannable string success!");
Editable edit_text = noteEditText.getEditableText();
edit_text.delete(i, i + len + 15);
edit_text.insert(i, spannableString);
}
}
}
}
}
//处理返回的数据,并将图片的路径也写入到数据库
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
ContentResolver resolver = getContentResolver();
switch (requestCode) {
case PHOTO_REQUEST:
Uri originalUri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));//2.解码图片
} catch (FileNotFoundException e) {
Log.d(TAG, "onActivityResult: get file_exception");
e.printStackTrace();
}
if (bitmap != null) {
Log.d(TAG, "onActivityResult: bitmap is not null");
ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
String path = getPath(this, originalUri);
String img_fragment = "[local]" + path + "[/local]";
SpannableString spannableString = new SpannableString(img_fragment);
spannableString.setSpan(imageSpan, 0, img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
NoteEditText e = (NoteEditText) findViewById(R.id.note_edit_view);
int index = e.getSelectionStart();
Log.d(TAG, "Index是: " + index);
Editable edit_text = e.getEditableText();
edit_text.insert(index, spannableString);
mWorkingNote.setmContent(e.getText().toString());
ContentResolver contentResolver = getContentResolver();
ContentValues contentValues = new ContentValues();
final long id = mWorkingNote.getNoteId();
contentValues.put("snippet", mWorkingNote.getContent());
contentResolver.update(Uri.parse("content://micode_notes/note"), contentValues, "_id=?", new String[]{"" + id});
ContentValues contentValues1 = new ContentValues();
contentValues1.put("content", mWorkingNote.getContent());
contentResolver.update(Uri.parse("content://micode_notes/data"), contentValues1, "mime_type=? and note_id=?", new String[]{"vnd.android.cursor.item/text_note", "" + id});
} else {
Toast.makeText(NoteEditActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// Media
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if(cursor != null){
cursor.close();
}
}
return null;
}
public boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.note_edit);
setmChanged(new Stack<>() );
if (savedInstanceState == null && !initActivityState(getIntent())) {
finish();
return;
}
initResources();
final ImageButton add_img_btn = (ImageButton) findViewById(R.id.add_img_btn);
add_img_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "onClick: click add image button");
Intent loadImage = new Intent(Intent.ACTION_GET_CONTENT);
loadImage.addCategory(Intent.CATEGORY_OPENABLE);
loadImage.setType("image/*");
startActivityForResult(loadImage, PHOTO_REQUEST);
}
});
}
/**
* Current activity may be killed when the memory is low. Once it is killed, for another time
* user load this activity, we should restore the former state
*/
//用于在Activity被系统销毁后恢复其状态
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
@ -179,12 +530,14 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
}
//该方法主要用于初始化Activity的状态根据传入的Intent的不同动作action执行不同的操作。
private boolean initActivityState(Intent intent) {
/**
* If the user specified the {@link Intent#ACTION_VIEW} but not provided with id,
* then jump to the NotesListActivity
*/
mWorkingNote = null;
//打开某个笔记的操作
if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) {
long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0);
mUserQuery = "";
@ -196,7 +549,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY);
}
//DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE) 是一个方法调用
// 用于检查给定的 noteId 是否存在于笔记数据库中
if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) {
Intent jump = new Intent(this, NotesListActivity.class);
startActivity(jump);
@ -204,6 +558,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
finish();
return false;
} else {
//如果指定的笔记 ID 存在于笔记数据库中,则调用 WorkingNote.load() 方法,根据指定的笔记 ID 加载笔记对象,并将结果赋值给 mWorkingNote
mWorkingNote = WorkingNote.load(this, noteId);
if (mWorkingNote == null) {
Log.e(TAG, "load note failed with note id" + noteId);
@ -215,7 +570,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
} else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) {
//需要创建或编辑一个笔记
// New note
//从 Intent 中获取一些额外的信息,如文件夹 ID、小部件 ID、小部件类型和背景资源 ID。这些信息用于确定新笔记的位置和外观。
long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0);
int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
@ -268,6 +625,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
initNoteScreen();
}
//用于初始化笔记屏幕
private void initNoteScreen() {
mNoteEditor.setTextAppearance(this, TextAppearanceResources
.getTexAppearanceResource(mFontSizeId));
@ -293,6 +651,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* is not ready
*/
showAlertHeader();
convertToImage();
}
private void showAlertHeader() {
@ -362,7 +721,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
return true;
}
//初始化一些资源
private void initResources() {
mHeadViewPanel = findViewById(R.id.note_title);
mNoteHeaderHolder = new HeadViewHolder();
@ -374,11 +733,17 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteEditor = (EditText) findViewById(R.id.note_edit_view);
mNoteEditorPanel = findViewById(R.id.sv_note_edit);
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);
//这段代码的作用是为sBgSelectorBtnsMap中的所有ImageView对象设置点击事件监听器。
// 当某个ImageView被点击时会触发与当前类关联的onClick()方法。
//sBgSelectorBtnsMap是一个Map对象它存储了一些键值对其中每个sBgSelectorBtnsMap是一个Map对象它存储了一些键值对其中每个键对应一个ImageView对象的id每个值则未在这段代码中给出。
// 这种数据结构通常用于在Android应用中存储和操作UI元素例如这里的ImageView。
// 通过键即ImageView的id可以快速找到并操作对应的UI元素。
// 具体来说这段代码遍历了sBgSelectorBtnsMap中的所有键并为每个键对应的ImageView设置了一个点击事件监听器。
for (int id : sBgSelectorBtnsMap.keySet()) {
ImageView iv = (ImageView) findViewById(id);
iv.setOnClickListener(this);
}
mFontSizeSelector = findViewById(R.id.font_size_selector);
for (int id : sFontSizeBtnsMap.keySet()) {
View view = findViewById(id);
@ -391,10 +756,150 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/
//这段代码是用于获取应用程序的字体大小设置
if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) {
mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE;
}
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);
/*
*/
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) {
}
@Override
public void afterTextChanged(Editable s) {//文本更改后
if(!mIsRvoke) {
saveMyChanged();
}else {
mIsRvoke = false;
}
}
});
//翻译
doTranslate();
//朗读
mTTS = new TextToSpeech(this, new OnInitListener() {
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTTS.setLanguage(Locale.CHINESE);
mTTS.setPitch(1.5f);// 设置音调,值越大声音越尖(女生),值越小则变成男声,1.0是常规
mTTS.setSpeechRate(0.5f);
}
}
});
mHeadViewPanel = findViewById(R.id.note_title);
}
private void texttoSpeech(){
mTTS.speak(mNoteEditor.getText().toString(),TextToSpeech.QUEUE_FLUSH,null,null);
}
private void doRevoke(){
int size = mChanged.size();//获取当前栈大小
AlertDialog.Builder dialog = new AlertDialog.Builder(this);//创建一个alertdialog 窗口
dialog.setTitle(R.string.tips_of_revoke);//设置 title 信息
dialog.setCancelable(true);//设置为可取消
dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {//只需要设置一个 OK 键即可
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
mIsRvoke= true;
if(size<=1){//如果栈中元素过少,打印提示信息
dialog.setMessage(R.string.have_not_input_anything);//提示用户您还没有输入任何信息
dialog.show();//显示当前 alertdialog
return;
}
else {
mNoteEditor.setText((CharSequence) mChanged.elementAt(size-2));//在textview 中设置撤销的内容
mNoteEditor.setSelection(mNoteEditor.length());
mChanged.removeElementAt(size-1);//删除元素
if(size==2){
dialog.setMessage(R.string.can_not_revoke);//如果只有一次操作,那么提示用户不能再撤销了
dialog.show();//显示当前 alertdialog
}
}
}
private void saveMyChanged(){
SpannableString text = new SpannableString(mNoteEditor.getText());//用 getText方法获取每次编辑的内容
if(mChanged.size()>=MAX_TIME_OF_RVOKE_TIME){//如果栈中的数据大于最大撤销次数,就把第一次修改的内容删除
mChanged.removeElementAt(0);
}
mChanged.add(text);//然后把本次修改的内容加入栈中
}
public void showSingleAlertDialog(){
final String[] items = {"默认-普通","默认-非衬线","默认-衬线","默认-等宽","仿宋","黑体","楷体","隶书","微软雅黑"};
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this);
alertBuilder.setTitle("请选择字体");
alertBuilder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i) {
case 0:
mNoteEditor.setTypeface(Typeface.DEFAULT);
break;
case 1:
mNoteEditor.setTypeface(Typeface.SANS_SERIF);
break;
case 2:
mNoteEditor.setTypeface(Typeface.SERIF);
break;
case 3:
mNoteEditor.setTypeface(Typeface.MONOSPACE);
break;
case 4:
Typeface typeface0 = Typeface.createFromAsset(getAssets(), "front/simfang.ttf");
mNoteEditor.setTypeface(typeface0);
break;
case 5:
Typeface typeface1 = Typeface.createFromAsset(getAssets(), "front/simhei.ttf");
mNoteEditor.setTypeface(typeface1);
break;
case 6:
Typeface typeface2 = Typeface.createFromAsset(getAssets(), "front/simkai.ttf");
mNoteEditor.setTypeface(typeface2);
break;
case 7:
Typeface typeface3 = Typeface.createFromAsset(getAssets(), "front/SIMLI.TTF");
mNoteEditor.setTypeface(typeface3);
break;
case 8:
Typeface typeface4 = Typeface.createFromAsset(getAssets(), "front/msyh.ttc");
mNoteEditor.setTypeface(typeface4);
break;
}
Toast.makeText(NoteEditActivity.this, items[i],Toast.LENGTH_SHORT).show();
}
});
alertBuilder.setPositiveButton("确定",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
alertDialog2.dismiss();
}
});
alertBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialogInterface, int i) {
alertDialog2.dismiss();
}
});
alertDialog2 = alertBuilder.create();
alertDialog2.show();
}
@Override
@ -424,13 +929,19 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sendBroadcast(intent);
setResult(RESULT_OK, intent);
}
/*
ID
*/
public void onClick(View v) {
int id = v.getId();
//如果按钮ID等于R.id.btn_set_bg_color则表示用户点击了设置背景颜色的按钮。
// 此时,将背景颜色选择器的可见性设置为可见,并显示当前选中的背景颜色对应的控件
if (id == R.id.btn_set_bg_color) {
mNoteBgColorSelector.setVisibility(View.VISIBLE);
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(View.VISIBLE);
} else if (sBgSelectorBtnsMap.containsKey(id)) {
//如果按钮ID在sBgSelectorBtnsMap中存在表示用户点击了某个背景颜色按钮。
// 此时隐藏当前选中的背景颜色对应的控件将工作笔记的背景颜色设置为该按钮对应的ID并将背景颜色选择器的可见性设置为不可见。
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE);
mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id));
@ -444,8 +955,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
getWorkingText();
switchToListMode(mWorkingNote.getContent());
} else {
mNoteEditor.setTextAppearance(this,
TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
mNoteEditor.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
}
mFontSizeSelector.setVisibility(View.GONE);
}
@ -479,6 +989,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId());
}
//该方法的主要作用是根据当前的工作笔记mWorkingNote的属性来准备和更新菜单项。
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (isFinishing()) {
@ -486,6 +997,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
clearSettingState();
menu.clear();
//工作笔记的文件夹ID
if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) {
getMenuInflater().inflate(R.menu.call_note_edit, menu);
} else {
@ -505,7 +1017,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
@Override
//这段代码是一个用于处理菜单项点击事件的方法onOptionsItemSelected(MenuItem item)当用户点击菜单项时会根据菜单项的ID执行相应的操作。以下是对代码的解释
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_new_note) {
@ -524,8 +1035,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
} else if (itemId == R.id.menu_font_size) {//修改字体的大小
mFontSizeSelector.setVisibility(View.VISIBLE);
} else if (itemId == R.id.menu_font_size) {
mFontSizeSelector.setVisibility (View.VISIBLE);
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);
} else if (itemId == R.id.menu_list_mode) {
mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ?
@ -539,24 +1050,20 @@ 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_revoke) {
doRevoke();
}else if(itemId == R.id.menu_voice_speech){
Log.d(TAG,"in");
texttoSpeech();
}else if(itemId == R.id.menu_font_setting){
showSingleAlertDialog();
}
return true;
}
//onOptionsItemSelected方法是一个覆盖方法用于在用户选择某个选项菜单项时被调用。
//
//在这段代码中首先获取选项菜单项的ID即itemId = item.getItemId()。
//
//然后使用if-else语句对不同的菜单项进行处理。
//
//若itemId等于R.id.menu_new_note则调用createNewNote()方法。
//若itemId等于R.id.menu_delete则创建一个AlertDialog对话框设置标题、图标和消息并添加确定按钮和取消按钮的点击事件监听器点击确定按钮时调用deleteCurrentNote()方法并结束当前活动。
//若itemId等于R.id.menu_font_size则设置字体大小选择器显示并根据当前选中的字体大小ID找到对应的视图并设置其可见性为可见。
//若itemId等于R.id.menu_list_mode则切换工作笔记的清单模式若当前为0则切换为检查清单模式否则切换为普通文本模式
//若itemId等于R.id.menu_share则获取当前工作笔记的文本内容并将其发送到指定目标。
//若itemId等于R.id.menu_send_to_desktop则发送笔记到桌面。
//若itemId等于R.id.menu_alert则设置提醒事项。
//若itemId等于R.id.menu_delete_remind则将工作笔记的提醒日期设置为0表示删除提醒。
//最后返回值为true表示已经处理了选择的菜单项。
private void setReminder() {
DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis());
d.setOnDateTimeSetListener(new OnDateTimeSetListener() {
@ -566,15 +1073,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
});
d.show();
}
//这段代码定义了一个名为setReminder的私有方法用于设置笔记的提醒时间。
//
//在方法内部首先创建一个DateTimePickerDialog对象d并将当前时间作为默认时间传递给该对象。
//
//接着为d设置一个OnDateTimeSetListener监听器当用户设置时间时会调用该监听器的OnDateTimeSet方法。在该方法中调用正在编辑的笔记对象mWorkingNote的setAlertDate方法将用户设置的时间转换成毫秒值并将其设置为笔记的提醒时间。
//
//最后显示d对话框让用户选择提醒时间。
//
//因此,这段代码用于弹出一个日期时间选择对话框,让用户设置笔记的提醒时间,并将设置的时间保存到正在编辑的笔记对象中。
/**
* Share note to apps that support {@link Intent#ACTION_SEND} action
* and {@text/plain} type
@ -585,49 +1084,50 @@ public class NoteEditActivity extends Activity implements OnClickListener,
intent.setType("text/plain");
context.startActivity(intent);
}
//这段代码是一个私有方法sendTo用于使用系统默认的分享功能将指定的文本信息发送给其他应用程序。
//
//在方法内部首先创建一个新的Intent对象并将其动作设置为Intent.ACTION_SEND表示发送内容。
//
//接着通过putExtra方法将要分享的文本信息info放入Intent中使用Intent.EXTRA_TEXT作为键。
//
//然后使用setType方法将要分享的内容的MIME类型设置为"text/plain",表示纯文本类型。
//
//最后通过context.startActivity(intent)启动该Intent将文本信息发送给其他应用程序进行处理。
//
//因此这段代码用于在给定的Context上下文环境中利用系统默认的分享功能将特定的文本信息发送给其他应用程序。
private void createNewNote() {//新建便签
private void createNewNote() {
// Firstly, save current editing notes
//保存当前便签
saveNote();
// For safety, start a new NoteEditActivity
finish();
//设置链接器
Intent intent = new Intent(this, NoteEditActivity.class);
//将该活动定义为创建或编辑
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
//将运行便签的id添加到INTENT_EXTRA_FOLDER_ID标记中
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId());
//开始活动并链接
startActivity(intent);
}
private void deleteCurrentNote() {//删除便签
private void deleteCurrentNote() {
//假如当前运行的便签内存有数据
if (mWorkingNote.existInDatabase()) {
HashSet<Long> ids = new HashSet<Long>();
long id = mWorkingNote.getNoteId();
//如果不是头文件夹建立一个hash表把便签id存起来
if (id != Notes.ID_ROOT_FOLDER) {
ids.add(id);
} 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");
}
}
}
//将这些标签的删除标记置为true
mWorkingNote.markDeleted(true);
}
@ -827,15 +1327,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
return hasChecked;
}
//段代码是一个私有方法getWorkingText用于获取工作笔记的文本内容并根据是否为待办事项模式进行相应处理。同时该方法返回一个布尔值表示在待办事项模式下是否有选中的项目。
//
//在方法内部首先检查当前工作笔记mWorkingNote是否为待办事项模式。如果是就遍历所有子视图view其中包含每个待办事项的复选框和文本编辑框。对于每个非空的文本编辑框如果其相应的复选框被选中则将文本内容作为已选中的待办事项添加到字符串缓冲区sb中并将标记hasChecked设置为true否则将文本内容作为未选中的待办事项添加到字符串缓冲区sb中。
//
//最后将字符串缓冲区sb中的内容作为工作笔记的文本内容设置到mWorkingNote对象中。如果不是待办事项模式则将文本编辑器mNoteEditor中的文本内容设置为工作笔记的文本内容。
//
//最终该方法返回一个布尔值hasChecked表示在待办事项模式下是否有选中的项目。
//
//因此,这段代码用于获取工作笔记的文本内容,并根据是否为待办事项模式进行相应处理并返回结果。
private boolean saveNote() {
getWorkingText();
boolean saved = mWorkingNote.saveNote();
@ -851,17 +1343,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
return saved;
}
//这段代码是一个私有方法saveNote用于保存当前正在编辑的笔记。
//
//在方法内部首先调用getWorkingText方法获取当前正在编辑的笔记的文本内容并将其保存到mWorkingNote对象中。
//
//接着调用mWorkingNote.saveNote()方法将笔记保存到数据库中并将保存结果保存到saved变量中。
//
//如果保存成功则调用setResult(RESULT_OK)方法设置当前Activity的返回状态为RESULT_OK。这个状态用于标识从编辑状态返回到列表视图时是创建新笔记还是编辑已有笔记。
//
//最后,返回保存是否成功的布尔值。
//
//因此,这段代码用于将当前正在编辑的笔记保存到数据库中,并设置返回状态。
private void sendToDesktop() {
/**
* Before send message to home, we should make sure that current
@ -896,33 +1378,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
showToast(R.string.error_note_empty_for_send_to_desktop);
}
}
//这段代码定义了一个名为sendToDesktop的私有方法用于将笔记发送到桌面。
//
//在方法内部首先检查当前正在编辑的笔记是否存在于数据库中。如果笔记不存在于数据库中则调用saveNote()方法保存笔记。
//
//接着如果当前正在编辑的笔记具有有效的笔记ID即大于0则执行以下操作
//
//创建一个Intent对象sender用于发送广播。
//
//创建一个Intent对象shortcutIntent指定其目标为NoteEditActivity类并设置动作为Intent.ACTION_VIEW。
//
//将正在编辑的笔记ID作为附加数据放入shortcutIntent中。
//
//将笔记内容生成适合作为快捷方式图标标题的字符串并放入sender中作为附加数据。
//
//将应用程序的图标资源作为快捷方式图标放入sender中。
//
//设置sender的动作为com.android.launcher.action.INSTALL_SHORTCUT表示要安装快捷方式。
//
//弹出一个简短的提示消息,提示用户笔记已经进入桌面。
//
//发送广播,安装快捷方式。
//
//如果当前正在编辑的笔记没有有效的笔记ID则执行以下操作
//
//输出一个错误日志,表示发送到桌面出错。
//
//弹出一个提示消息,提醒用户必须输入一些内容才能发送到桌面。
private String makeShortcutIconTitle(String content) {
content = content.replace(TAG_CHECKED, "");
content = content.replace(TAG_UNCHECKED, "");

@ -79,6 +79,10 @@ import java.io.InputStreamReader;
import java.util.HashSet;
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
/*
*/
private int background = -1;
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private static final int FOLDER_LIST_QUERY_TOKEN = 1;
@ -140,7 +144,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
super.onCreate(savedInstanceState);
setContentView(R.layout.note_list);
initResources();
getWindow().setBackgroundDrawableResource(R.drawable.picture1);
/**
* Insert an introduction when user firstly use this application
*/
@ -509,11 +513,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
Log.e(TAG, "Wrong folder id, should not happen " + folderId);
return;
}
//该方法接收一个参数folderId表示要删除的文件夹的ID。
//
//在方法内部首先通过条件判断检查folderId是否等于Notes.ID_ROOT_FOLDER根文件夹的ID。如果是根文件夹的ID则记录错误日志并返回不执行删除操作。
//
//这段代码的作用是避免意外情况下删除根文件夹因为根文件夹通常是系统的关键文件夹不应该被删除。如果传入的folderId等于根文件夹的ID会输出错误日志并直接返回避免继续执行删除根文件夹的操作。
HashSet<Long> ids = new HashSet<Long>();
ids.add(folderId);
HashSet<AppWidgetAttribute> widgets = DataUtils.getFolderNoteWidget(mContentResolver,
@ -558,21 +558,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
mTitleBar.setVisibility(View.VISIBLE);
}
//该方法接收一个参数data表示要打开的文件夹。
//
//首先将当前文件夹的ID设置为参数data的ID并调用startAsyncNotesListQuery()方法开始异步查询当前文件夹下的笔记列表。
//
//接下来根据文件夹的ID判断当前状态
//
//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER则将状态设置为ListEditState.CALL_RECORD_FOLDER并隐藏添加新笔记按钮
//否则将状态设置为ListEditState.SUB_FOLDER。
//然后根据文件夹的ID设置标题栏的文本
//
//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER则设置标题栏的文本为字符串资源R.string.call_record_folder_name
//否则设置标题栏的文本为文件夹的名称通过调用data.getSnippet()方法获取)。
//最后,将标题栏设置为可见状态。
//
//总之这段代码实现了打开文件夹的功能根据文件夹的ID设置不同的状态和标题并更新UI显示。
public void onClick(View v) {
if (v.getId() == R.id.btn_new_note) {
@ -591,7 +576,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
private void showCreateOrModifyFolderDialog(final boolean create) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
@ -637,7 +621,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
values.put(NoteColumns.LOCAL_MODIFIED, 1);
mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID
+ "=?", new String[] {
String.valueOf(mFocusNoteDataItem.getId())//获取文件夹名称,并设置对话框的标题为对应的修改文件夹名称;
String.valueOf(mFocusNoteDataItem.getId())
});
}
} else if (!TextUtils.isEmpty(name)) {
@ -650,6 +634,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
});
if (TextUtils.isEmpty(etName.getText())) {
positive.setEnabled(false);
}
@ -676,14 +661,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
});
}
//该方法接收一个参数create用于指示是创建文件夹还是修改文件夹。
//
//在方法内部首先创建一个AlertDialog.Builder对象并通过LayoutInflater从XML布局文件中实例化一个视图。
// 获取EditText对象用于输入文件夹名称并调用showSoftInput()方法显示软键盘。
//
//根据create参数的值判断是创建文件夹还是修改文件夹。如果是修改文件夹
// 则从mFocusNoteDataItem中获取文件夹名称并设置对话框的标题为对应的修改文件夹名称
// 如果是创建文件夹则将EditText的文本设置为空并设置对话框的标题为创建文件夹。
@Override
public void onBackPressed() {
switch (mState) {
@ -795,6 +773,15 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else {
Log.e(TAG, "Wrong state:" + mState);
}
if (background == -1)
{
menu.findItem(R.id.menu_switch_to_picture3).setVisible(false);
}else if (background == 0){
menu.findItem(R.id.menu_switch_to_picture2).setVisible(false);
}else if (background == 1){
menu.findItem(R.id.menu_switch_to_picture3).setVisible(false);
}
return true;
}
@ -821,34 +808,26 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
createNewNote();
} else if (itemId == R.id.menu_search) {
onSearchRequested();
}else if (itemId == R.id.menu_switch_to_picture3) {
background = 1;
getWindow().setBackgroundDrawableResource(R.drawable.picture1);
}else if (itemId == R.id.menu_switch_to_picture2) {
background = 0;
getWindow().setBackgroundDrawableResource(R.drawable.picture2);
}else if (itemId == R.id.menu_switch_to_picture1) {
background = -1;
getWindow().setBackgroundDrawableResource(R.drawable.picture3);
}
return true;
}
//每当用户选择菜单项时Android 系统会调用该方法并传入被选中的菜单项MenuItem。该方法首先获取被选中菜单项的ID然后根据不同的ID执行相应的操作。
//
//具体来说:
//
//如果选中的菜单项是R.id.menu_new_folder则调用showCreateOrModifyFolderDialog(true)方法,显示创建或修改文件夹的对话框。
//如果选中的菜单项是R.id.menu_export_text则调用exportNoteToText()方法,将笔记导出为文本。
//如果选中的菜单项是R.id.menu_sync则根据当前是否处于同步模式isSyncMode()分别启动或取消同步服务GTaskSyncService或打开设置活动startPreferenceActivity
//如果选中的菜单项是R.id.menu_setting则打开设置活动startPreferenceActivity
//如果选中的菜单项是R.id.menu_new_note则创建新的笔记createNewNote
//如果选中的菜单项是R.id.menu_search则执行搜索请求onSearchRequested
//最后该方法返回true表示菜单项的选择事件已经得到处理。
//
//总之,该方法根据用户选择的菜单项执行不同的操作,包括创建新文件夹、导出笔记、同步服务控制、打开设置活动、创建新笔记和执行搜索请求等。
@Override
public boolean onSearchRequested() {
startSearch(null, false, null /* appData */, false);
return true;
}
//nSearchRequested方法是一个覆盖方法用于在用户点击搜索按钮或者执行搜索手势时被调用。
//
//在这段代码中首先调用了startSearch方法来启动搜索功能。startSearch方法接受四个参数搜索关键字null表示没有指定关键字是否全局搜索false表示只搜索当前应用程序应用程序数据null表示没有额外的应用程序数据以及是否由用户触发的搜索false表示不是由用户触发
//
//然后返回值为true表示该方法已经处理了搜索请求并不需要其他的默认处理。
//
//总之该代码片段实现了在搜索请求时调用startSearch方法并返回true表示已经处理了该搜索请求。
private void exportNoteToText() {
final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
new AsyncTask<Void, Void, Integer>() {
@ -890,18 +869,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}.execute();
}
//首先定义了一个名为exportNoteToText的私有方法没有任何参数。
//
//在该方法中首先通过BackupUtils.getInstance(NotesListActivity.this)获取一个备份工具类的实例。然后创建一个异步任务AsyncTask来执行导出操作。
//
//在异步任务的doInBackground方法中调用backup.exportToText()方法来执行导出操作,并返回一个结果值。
//
//在异步任务的onPostExecute方法中根据导出的结果值进行不同的处理
//
//如果结果值等于BackupUtils.STATE_SD_CARD_UNMOUONTED表示SD卡未挂载弹出一个对话框提示导出失败和SD卡未挂载的错误信息。
//如果结果值等于BackupUtils.STATE_SUCCESS表示导出成功弹出一个对话框提示导出成功和导出文件的位置信息。
//如果结果值等于BackupUtils.STATE_SYSTEM_ERROR表示导出失败弹出一个对话框提示导出失败的错误信息。
//在最后通过调用execute方法来执行异步任务。
private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
}

@ -0,0 +1,36 @@
package net.micode.notes.ui;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import net.micode.notes.databinding.ActivitySplashBinding;
import net.micode.notes.R;
public class SplashActivity extends AppCompatActivity {
Handler mHandler=new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //加载启动界面
setContentView(R.layout.activity_splash); //加载启动图片
// 当计时结束时跳转至NotesListActivity
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Intent intent=new Intent();
intent.setClass(SplashActivity.this, NotesListActivity.class);
startActivity(intent);
finish(); //销毁欢迎页面
}
}, 2000); // 2 秒后跳转
}
}
Loading…
Cancel
Save