Compare commits

...

12 Commits

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Notes-master.iml" filepath="$PROJECT_DIR$/Notes-master.iml" />
</modules>
</component>
</project>

@ -1,7 +0,0 @@
欢迎使用MIUI便签
无论从软件中直接添加还是从桌面拖出widgetMIUI便签能让你快速建立和保存便签
除了调整文字大小、便签背景、文件夹等基础功能外你会发现MIUI便签也提供了清单模式、便签提醒、软件加密、导出到SD卡、同步google task的高级功能让你的生活记录更加美好和安全
来分享你的使用体验吧http://www.miui.com/index.php

@ -1 +0,0 @@
Welcome to use MIUI notes!

@ -1,135 +0,0 @@
<?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.
-->
<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>
<string name="widget_havenot_content">No associated note found, click to create associated note.</string>
<string name="widget_under_visit_mode">Privacy modecan not see note content</string>
<string name="notelist_string_info">...</string>
<string name="notelist_menu_new">Add note</string>
<string name="delete_remind_time_message">Delete reminder successfully</string>
<string name="set_remind_time_message">Set reminder</string>
<string name="note_alert_expired">Expired</string>
<string name="format_date_ymd">yyyyMMdd</string>
<string name="format_datetime_mdhm">MMMd kk:mm</string>
<string name="notealert_ok">Got it</string>
<string name="notealert_enter">Take a look</string>
<string name="note_link_tel">Call</string>
<string name="note_link_email">Send email</string>
<string name="note_link_web">Browse web</string>
<string name="note_link_other">Open map</string>
<!-- Text export file information -->
<string name="file_path">/MIUI/notes/</string>
<string name="file_name_txt_format">notes_%s.txt</string>
<!-- notes list 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>
<string name="menu_sync">Sync</string>
<string name="menu_sync_cancel">Cancel syncing</string>
<string name="menu_setting">Settings</string>
<string name="menu_search">Search</string>
<string name="menu_delete">Delete</string>
<string name="menu_move">Move to folder</string>
<string name="menu_select_title">%d selected</string>
<string name="menu_select_none">Nothing selected, the operation is invalid</string>
<string name="menu_select_all">Select all</string>
<string name="menu_deselect_all">Deselect all</string>
<string name="menu_font_size">Font size</string>
<string name="menu_font_small">Small</string>
<string name="menu_font_normal">Medium</string>
<string name="menu_font_large">Large</string>
<string name="menu_font_super">Super</string>
<string name="menu_list_mode">Enter check list</string>
<string name="menu_normal_mode">Leave check list</string>
<string name="menu_folder_view">View folder</string>
<string name="menu_folder_delete">Delete folder</string>
<string name="menu_folder_change_name">Change folder name</string>
<string name="folder_exist">The folder %1$s exist, please rename</string>
<string name="menu_share">Share</string>
<string name="menu_send_to_desktop">Send to home</string>
<string name="menu_alert">Remind me</string>
<string name="menu_remove_remind">Delete reminder</string>
<string name="menu_title_select_folder">Select folder</string>
<string name="menu_move_parent_folder">Parent folder</string>
<string name="info_note_enter_desktop">Note added to home</string>
<string name="alert_message_delete_folder">Confirm to delete folder and its notes?</string>
<string name="alert_title_delete">Delete selected notes</string>
<string name="alert_message_delete_notes">Confirm to delete the selected %d notes?</string>
<string name="alert_message_delete_note">Confirm to delete this note?</string>
<string name="format_move_notes_to_folder">Have moved selected %1$d notes to %2$s folder</string>
<!-- Error information -->
<string name="error_sdcard_unmounted">SD card busy, not available now</string>
<string name="error_sdcard_export">Export failed, please check SD card</string>
<string name="error_note_not_exist">The note is not exist</string>
<string name="error_note_empty_for_clock">Sorry, can not set clock on empty note</string>
<string name="error_note_empty_for_send_to_desktop">Sorry, can not send and empty note to home</string>
<string name="success_sdcard_export">Export successful</string>
<string name="failed_sdcard_export">Export fail</string>
<string name="format_exported_file_location">Export text file (%1$s) to SD (%2$s) directory</string>
<!-- Sync -->
<string name="ticker_syncing">Syncing notes...</string>
<string name="ticker_success">Sync is successful</string>
<string name="ticker_fail">Sync is failed</string>
<string name="ticker_cancel">Sync is canceled</string>
<string name="success_sync_account">Sync is successful with account %1$s</string>
<string name="error_sync_network">Sync failed, please check network and account settings</string>
<string name="error_sync_internal">Sync failed, internal error occurs</string>
<string name="error_sync_cancelled">Sync is canceled</string>
<string name="sync_progress_login">Logging into %1$s...</string>
<string name="sync_progress_init_list">Getting remote note list...</string>
<string name="sync_progress_syncing">Synchronize local notes with Google Task...</string>
<!-- Preferences -->
<string name="preferences_title">Settings</string>
<string name="preferences_account_title">Sync account</string>
<string name="preferences_account_summary">Sync notes with google task</string>
<string name="preferences_last_sync_time">Last sync time %1$s</string>
<string name="preferences_last_sync_time_format">yyyy-MM-dd hh:mm:ss</string>
<string name="preferences_add_account">Add account</string>
<string name="preferences_menu_change_account">Change sync account</string>
<string name="preferences_menu_remove_account">Remove sync account</string>
<string name="preferences_menu_cancel">Cancel</string>
<string name="preferences_button_sync_immediately">Sync immediately</string>
<string name="preferences_button_sync_cancel">Cancel syncing</string>
<string name="preferences_dialog_change_account_title">Current account %1$s</string>
<string name="preferences_dialog_change_account_warn_msg">All sync related information will be deleted, which may result in duplicated items sometime</string>
<string name="preferences_dialog_select_account_title">Sync notes</string>
<string name="preferences_dialog_select_account_tips">Please select a google account. Local notes will be synced with google task.</string>
<string name="preferences_toast_cannot_change_account">Cannot change the account because sync is in progress</string>
<string name="preferences_toast_success_set_accout">%1$s has been set as the sync account</string>
<string name="preferences_bg_random_appear_title">New note background color random</string>
<string name="button_delete">Delete</string>
<string name="call_record_folder_name">Call notes</string>
<string name="hint_foler_name">Input name</string>
<string name="search_label">Searching Notes</string>
<string name="search_hint">Search notes</string>
<string name="search_setting_description">Text in your notes</string>
<string name="search">Notes</string>
<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>
<!-- 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>
</plurals>
</resources>

@ -1,2 +1,15 @@
# ourXiaoMiLabel
<!--
关于综合实践通知一:
头歌平台项目库文件夹组织及命名规则如下:
src (该文件夹存放维护后的所有源代码及数据库等)
model 该文件夹存放UML模型
doc (该文件夹存放系统相关文档)具体包含的文件如下:
01_小米便签开源代码阅读-泛读报告_组长姓名
02_小米便签开源代码阅读-精读报告_学生姓名每个成员单独一份
03_小米便签开源代码-质量分析报告_组长姓名
04_小米便签维护-需求与设计方案_组长姓名
other该文件夹存放汇报PPT及实践总结等具体包含的文件如下
05_小米便签阅读与维护-汇报_组长姓名
06_小米便签阅读与维护-总结报告_学号姓名每个成员单独一份
07_小米便签维护-演示录屏_组长名 -->

@ -0,0 +1 @@
表示需要提交的文档

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

@ -0,0 +1 @@
表示需要提交的文档

@ -0,0 +1 @@
表示需要提交的文档

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="net.micode.notes"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon_app"
android:label="@string/app_name"
tools:ignore="ExtraText">
<!-- 其他声明 -->
<activity
android:name=".ui.ShowResultActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
android:label="Show Result" />
<!-- 其他声明 -->
<activity
android:name=".ui.SplashActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/Theme.Notes1.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"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan"></activity>
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<!-- android:theme="@style/NoteTheme" -->
<intent-filter tools:ignore="AppLinkUrlError">
<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>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<provider
android:name=".data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true" />
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_2x_info" />
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
</receiver>
<receiver android:name=".ui.AlarmInitReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<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>
<activity
android:name=".ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light"></activity>
<service
android:name=".gtask.remote.GTaskSyncService"
android:exported="false"></service>
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
</application>
</manifest>

@ -36,6 +36,8 @@ public class Contact {
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
//TODO
//识别电话号码
public static String getContact(Context context, String phoneNumber) {
if(sContactCache == null) {
sContactCache = new HashMap<String, String>();

@ -0,0 +1,96 @@
package net.micode.notes.data;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class DataFetch extends AppCompatActivity {
/***
*
* @param context 访
* @param strFile
* @return
*/
public boolean fileIsExists(Context context, String strFile) {
boolean fileExistFlag;
try{
context.openFileInput(strFile);
fileExistFlag = true;
} catch (FileNotFoundException e){
fileExistFlag = false;
}
return fileExistFlag;
}
/**
*
* @param context 访
* @param file_name
* @param key
*/
public void writeFile(Context context, String file_name, String key){
try {
// 创建文件输出流,以追加模式写入文件
FileOutputStream fos = context.openFileOutput(file_name, Context.MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
// 写入内容到文件中
osw.write(key);
// 刷新输出流到fos的缓冲区中
osw.flush();
// 刷新文件输出流至文件
fos.flush();
// 关闭字符输出流
osw.close();
// 关闭文件输出流
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param context 访
* @param filename
* @return "error"
*/
public String readFile(Context context, String filename) {
try {
// 创建文件输入流
FileInputStream fis = context.openFileInput(filename);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
// 创建字符数组,用于存储读取到的文件内容
// fis.available() 是用于获取文件输入流 FileInputStream 中可读取的字节数量的方法。
// 具体来说,它返回的是当前时刻可从文件输入流中读取的字节数量,而不是文件的总字节数量
char[] input = new char[fis.available()];
// 读取文件内容到字符数组中
isr.read(input);
// 关闭字符输入流
isr.close();
// 关闭文件输入流
fis.close();
// 将字符数组转换为字符串,并返回读取到的文件内容
return new String(input);
} catch (Exception e) {
// 捕获异常并打印堆栈信息
e.printStackTrace();
}
// 如果发生异常,则返回 "error"
return "error";
}
}

@ -206,35 +206,35 @@ public class Notes {
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* Generic data column, the meaning is specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA1 = "data1";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* Generic data column, the meaning is specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA2 = "data2";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* Generic data column, the meaning is specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA3 = "data3";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* Generic data column, the meaning is specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA4 = "data4";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* Generic data column, the meaning is specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/

@ -16,16 +16,24 @@
package net.micode.notes.data;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.util.Log;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
@ -359,4 +367,65 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
//创建搜索类,利用sql语句
public List<String> dosearch(String querystring) //搜索时不区分大小写
{
Cursor cursor = null;
List<String> results = new ArrayList<>();
SQLiteDatabase db = mInstance.getReadableDatabase();
String query_sql_string = "select * from " + TABLE.DATA + " where content like " + "'%"+ querystring + "%'";
Log.i(TAG,query_sql_string);
cursor = db.rawQuery(query_sql_string,null);
if(cursor!=null)
{
while(cursor.moveToNext())
{
String content = cursor.getString(cursor.getColumnIndex("content"));
// 过滤包含特定字符串的[local]和[/local]部分
if(filterLocalContent(content, querystring)){
results.add(content);
}
//打印测试
Log.i(TAG, content);
int id = cursor.getInt(cursor.getColumnIndex("_id")); // 获取便签 ID
//构造便签笔记的 URI
Uri noteUri = ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id);
Log.e(TAG, String.valueOf(noteUri));
//启动便签笔记编辑器页面
//这里启动的页面放在ShowReultActivity活动文件中去
}
}
cursor.close();
return results;
}
private boolean filterLocalContent(String content, String querystring) {
Pattern pattern = Pattern.compile("\\[local\\](.*?)\\[/local\\]");
Matcher matcher = pattern.matcher(content);
StringBuilder filteredContent = new StringBuilder();
int lastIndex = 0;
while (matcher.find()) {
String match = matcher.group(1); // 获取匹配到的文本内容
filteredContent.append(content, lastIndex, matcher.start()); // 添加匹配前的文本
lastIndex = matcher.end(); // 更新最后一个匹配结束的索引位置
if (match.contains(querystring)) {
return false;
}else{
filteredContent.append(match); // 添加不包含查询字符串的匹配文本
}
}
if (lastIndex < content.length()) {
filteredContent.append(content.substring(lastIndex)); // 添加剩余的文本内容
}
Log.e(TAG,filteredContent.toString());
return true;
}
}

@ -46,6 +46,75 @@ public abstract class Node {
private long mLastModified;
private boolean mDeleted;
private String title;
private String content;
private boolean isPinned; // 置顶状态
private boolean isStarred; // 星标状态
public boolean isPinned() {
return isPinned;
}
public void setPinned(boolean pinned) {
isPinned = pinned;
}
public boolean isStarred() {
return isStarred;
}
public void setStarred(boolean starred) {
isStarred = starred;
}
public String getmGid() {
return mGid;
}
public void setmGid(String mGid) {
this.mGid = mGid;
}
public String getmName() {
return mName;
}
public void setmName(String mName) {
this.mName = mName;
}
public long getmLastModified() {
return mLastModified;
}
public void setmLastModified(long mLastModified) {
this.mLastModified = mLastModified;
}
public boolean ismDeleted() {
return mDeleted;
}
public void setmDeleted(boolean mDeleted) {
this.mDeleted = mDeleted;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Node() {
mGid = null;

@ -64,21 +64,25 @@ public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
}
private void showNotification(int tickerId, String content) {
Notification notification = new Notification(R.drawable.notification, mContext
.getString(tickerId), System.currentTimeMillis());
notification.defaults = Notification.DEFAULT_LIGHTS;
notification.flags = Notification.FLAG_AUTO_CANCEL;
PendingIntent pendingIntent;
if (tickerId != R.string.ticker_success) {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesPreferenceActivity.class), 0);
} else {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);
}
notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
pendingIntent);
Notification.Builder builder = new Notification.Builder(mContext)
.setAutoCancel(true)
.setContentTitle(mContext.getString(R.string.app_name))
.setContentText(content)
.setContentIntent(pendingIntent)
.setWhen(System.currentTimeMillis())
.setOngoing(true);
Notification notification=builder.getNotification();
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}

@ -97,6 +97,7 @@ public class GTaskManager {
mLocalDeleteIdMap = new HashSet<Long>();
mGidToNid = new HashMap<String, Long>();
mNidToGid = new HashMap<Long, String>();
}
public static synchronized GTaskManager getInstance() {
@ -104,11 +105,13 @@ public class GTaskManager {
mInstance = new GTaskManager();
}
return mInstance;
}
public synchronized void setActivityContext(Activity activity) {
// used for getting authtoken
mActivity = activity;
}
public int sync(Context context, GTaskASyncTask asyncTask) {
@ -148,13 +151,16 @@ public class GTaskManager {
} catch (NetworkFailureException e) {
Log.e(TAG, e.toString());
return STATE_NETWORK_ERROR;
} catch (ActionFailureException e) {
Log.e(TAG, e.toString());
return STATE_INTERNAL_ERROR;
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return STATE_INTERNAL_ERROR;
} finally {
mGTaskListHashMap.clear();
mGTaskHashMap.clear();
@ -163,6 +169,7 @@ public class GTaskManager {
mGidToNid.clear();
mNidToGid.clear();
mSyncing = false;
}
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS;

@ -42,6 +42,8 @@ public class GTaskSyncService extends Service {
private static String mSyncProgress = "";
//TODO
//同步操作
private void startSync() {
if (mSyncTask == null) {
mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {

@ -38,7 +38,7 @@ public class WorkingNote {
// Note Id
private long mNoteId;
// Note content
private String mContent;
public String mContent;
// Note mode
private int mMode;
@ -187,6 +187,8 @@ public class WorkingNote {
return new WorkingNote(context, id, 0);
}
//TODO
//保存便签(自动)
public synchronized boolean saveNote() {
if (isWorthSaving()) {
if (!existInDatabase()) {
@ -229,6 +231,8 @@ public class WorkingNote {
mNoteSettingStatusListener = l;
}
//TODO
//删除提醒
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
mAlertDate = date;
@ -247,6 +251,8 @@ public class WorkingNote {
}
}
//TODO
//修改便签背景颜色
public void setBgColorId(int id) {
if (id != mBgColorId) {
mBgColorId = id;
@ -257,6 +263,8 @@ public class WorkingNote {
}
}
//TODO
//进入清单模式
public void setCheckListMode(int mode) {
if (mMode != mode) {
if (mNoteSettingStatusListener != null) {

@ -72,6 +72,8 @@ public class DataUtils {
return false;
}
// TODO
// 移动标签
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, desFolderId);
@ -80,6 +82,8 @@ public class DataUtils {
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
// TODO
// 移动标签文件
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
if (ids == null) {

@ -0,0 +1,39 @@
package net.micode.notes.tool;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Calc {
/**
* Javamd5
* @param content
* @return md5
*/
public static String md5Java(String content) {
byte[] hash; // 用于存储计算得到的 MD5 哈希值的字节数组
try {
// 获取 MD5 摘要算法的实例,并计算指定内容的哈希值
hash = MessageDigest.getInstance("MD5").digest(content.getBytes());
} catch (NoSuchAlgorithmException e) {
// 捕获 NoSuchAlgorithmException 异常,并将其包装并抛出 RuntimeException
throw new RuntimeException("NoSuchAlgorithmException", e);
}
// 创建 StringBuilder 对象,用于构建 MD5 哈希值的十六进制表示形式
StringBuilder hex = new StringBuilder(hash.length * 2);
// 遍历哈希值字节数组中的每个字节
for (byte b : hash) {
// 如果当前字节的值小于 16十六进制表示中只有一位则在十六进制字符串中补充一个 '0'
if ((b & 0xFF) < 0x10) {
hex.append(0);
}
// 将当前字节的值转换为十六进制,并追加到 StringBuilder 对象中
hex.append(Integer.toHexString(b & 0xff));
}
// 返回计算得到的 MD5 哈希值的十六进制表示形式
return hex.toString();
}
}

@ -41,34 +41,44 @@ import java.io.IOException;
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private long mNoteId;
private String mSnippet;
private long mNoteId; //文本的id号
private String mSnippet; //闹钟提示出现的文本字段
private static final int SNIPPET_PREW_MAX_LEN = 60;
MediaPlayer mPlayer;
@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 {
//根据ID从数据库中获取标签的内容
//getContentResolver是实现数据共享实例存储。
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
: mSnippet;
: mSnippet;//判断标签片段是否达到符合长度
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
@ -84,11 +94,14 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
private boolean isScreenOn() {
//判断屏幕是否锁屏,调用系统函数判断,最后返回值是布尔类型
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
private void playAlarmSound() {
//闹钟提示音激发
//调用系统的铃声管理URI得到闹钟提示音
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
int silentModeStreams = Settings.System.getInt(getContentResolver(),
@ -101,8 +114,11 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
try {
mPlayer.setDataSource(this, url);
//准备同步
mPlayer.prepare();
//设置循环播放
mPlayer.setLooping(true);
//开始播放
mPlayer.start();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block

@ -35,12 +35,14 @@ public class AlarmInitReceiver extends BroadcastReceiver {
NoteColumns.ALERTED_DATE
};
//对数据库的操作调用标签ID和闹钟时间
private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1;
@Override
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis();
//Cursor在这里的作用是通过查找数据库中的标签内容找到和当前系统时间相等的标签
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,

@ -22,9 +22,15 @@ import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
@Override
//启动AlarmAlertActivity
public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//activity要存在于activity的栈中而非activity的途径启动activity时必然不存在一个activity的栈
//所以要新起一个栈装入启动的activity
context.startActivity(intent);
}
}
//这是实现alarm这个功能最接近用户层的包基于上面的两个包
//作用还需要深究但是对于setClass和addFlags

@ -28,6 +28,8 @@ import android.view.View;
import android.widget.FrameLayout;
import android.widget.NumberPicker;
//FrameLayout是布局模板之一
//所有的子元素全部在屏幕的右上方
public class DateTimePicker extends FrameLayout {
private static final boolean DEFAULT_ENABLE_STATE = true;
@ -83,6 +85,7 @@ 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);
@ -94,6 +97,7 @@ public class DateTimePicker extends FrameLayout {
updateAmPmControl();
}
} else {
//24小时
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
@ -117,10 +121,14 @@ public class DateTimePicker extends FrameLayout {
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
//这里是对 分钟Minute改变的监听
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0;
//如果原值为59新值为0则offset加1
//如果原值为0新值为59则offset减1
if (oldVal == maxValue && newVal == minValue) {
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) {
@ -167,6 +175,7 @@ public class DateTimePicker extends FrameLayout {
this(context, System.currentTimeMillis());
}
//通过对数据库的访问,获取当前的系统时间
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}

@ -33,9 +33,12 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
private Calendar mDate = Calendar.getInstance();
private boolean mIs24HourView;
private OnDateTimeSetListener mOnDateTimeSetListener;
private OnDateTimeSetListener mOnDateTimeSetListener; //滚动日期选择
private DateTimePicker mDateTimePicker;
//DateTimePicker控件控件一般用于让用户可以从日期列表中选择单个值。
//运行时,单击控件边上的下拉箭头,会显示为两个部分:一个下拉列表,一个用于选择日期的
public interface OnDateTimeSetListener {
void OnDateTimeSet(AlertDialog dialog, long date);
}
@ -47,6 +50,8 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
//将视图中的各选项设置为系统当前时间
mDate.set(Calendar.YEAR, year);
mDate.set(Calendar.MONTH, month);
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
@ -56,6 +61,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
}
});
mDate.setTimeInMillis(date);
//系统时间
mDate.set(Calendar.SECOND, 0);
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
setButton(context.getString(R.string.datetime_dialog_ok), this);
@ -80,11 +86,15 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
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是该对话框上的按钮
}
}

@ -30,14 +30,19 @@ import net.micode.notes.R;
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);
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();
@ -45,16 +50,19 @@ public class DropdownMenu {
});
}
//设置菜单的监听
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener);
}
}
//对于菜单选项的初始化,根据索引搜索菜单需要的选项
public MenuItem findItem(int id) {
return mMenu.findItem(id);
}
//设置标题
public void setTitle(CharSequence title) {
mButton.setText(title);
}

@ -0,0 +1,136 @@
package net.micode.notes.ui;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import net.micode.notes.R;
public class EditDialog extends Dialog {
private Button yes, no; // 确定按钮和取消按钮
private TextView titleTv; // 消息标题文本视图
private EditText et_key; // 输入密码的编辑文本框
private String titleStr; // 外界设置的标题文本
private String messageStr; // 外界设置的消息文本
private String yesStr, noStr; // 确定按钮和取消按钮的显示内容
private onNoOnclickListener noOnclickListener; // 取消按钮被点击了的监听器
private onYesOnclickListener yesOnclickListener; // 确定按钮被点击了的监听器
// 设置取消按钮的显示内容和监听
public void setNoOnclickListener(String str, onNoOnclickListener onNoOnclickListener) {
if (str != null) {
noStr = str;
}
this.noOnclickListener = onNoOnclickListener;
}
// 设置确定按钮的显示内容和监听
public void setYesOnclickListener(String str, onYesOnclickListener onYesOnclickListener) {
if (str != null) {
yesStr = str;
}
this.yesOnclickListener = onYesOnclickListener;
}
public EditDialog(Context context) {
super(context, R.style.Dialog_Msg);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_edit);
setCanceledOnTouchOutside(false); // 点击空白处不能取消动画
// 初始化界面控件
initView();
// 初始化界面数据
initData();
// 初始化界面控件的事件
initEvent();
}
// 初始化界面的确定和取消监听器
private void initEvent() {
// 设置确定按钮被点击后的监听器
yes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (yesOnclickListener != null) {
// 回调确定按钮被点击的方法,并传递输入的密码
yesOnclickListener.onYesClick(et_key.getText().toString());
}
}
});
// 设置取消按钮被点击后的监听器
no.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (noOnclickListener != null) {
// 回调取消按钮被点击的方法
noOnclickListener.onNoClick();
}
}
});
}
// 初始化界面控件的显示数据
private void initData() {
// 如果用户自定了title
if (titleStr != null) {
titleTv.setText(titleStr);
}
// 如果设置了确定按钮的文字
if (yesStr != null) {
yes.setText(yesStr);
}
}
// 初始化界面控件
private void initView() {
yes = findViewById(R.id.yes);
no = findViewById(R.id.no);
titleTv = findViewById(R.id.title);
et_key = findViewById(R.id.et_phone);
}
// 从外部Activity为Dialog设置标题
public void setTitle(String title) {
titleStr = title;
}
// 从外部Activity为Dialog设置消息
public void setMessage(String message) {
messageStr = message;
}
// 确定按钮被点击的接口
public interface onYesOnclickListener {
void onYesClick(String key);
}
// 取消按钮被点击的接口
public interface onNoOnclickListener {
void onNoClick();
}
@Override
public void show() {
super.show();
// 设置对话框的宽度和高度为全屏
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
getWindow().getDecorView().setPadding(0, 0, 0, 0);
getWindow().setAttributes(layoutParams);
}
}

@ -30,6 +30,12 @@ import net.micode.notes.data.Notes.NoteColumns;
public class FoldersListAdapter extends CursorAdapter {
//CursorAdapter是Cursor和ListView的接口
//FoldersListAdapter继承了CursorAdapter的类
//主要作用是便签数据库和用户的交互
//这里就是用folder文件夹的形式展现给用户
//调用便签的id和片段
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
@ -38,6 +44,7 @@ public class FoldersListAdapter extends CursorAdapter {
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
//数据库
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
@ -48,6 +55,7 @@ public class FoldersListAdapter extends CursorAdapter {
return new FolderListItem(context);
}
//视图布局绑定
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof FolderListItem) {
@ -68,7 +76,9 @@ public class FoldersListAdapter extends CursorAdapter {
public FolderListItem(Context context) {
super(context);
//操作数据库
inflate(context, R.layout.folder_list_item, this);
//根据布局文件的名字等信息将其找出来
mName = (TextView) findViewById(R.id.tv_folder_name);
}

@ -0,0 +1,6 @@
package net.micode.notes.ui;
import android.app.Activity;
public class LoginActivity extends Activity {
}

@ -16,25 +16,42 @@
package net.micode.notes.ui;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.ContentUris;
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.Canvas;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.Layout;
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.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@ -43,6 +60,7 @@ 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;
@ -55,6 +73,7 @@ import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.data.NotesDatabaseHelper;
import net.micode.notes.model.WorkingNote;
import net.micode.notes.model.WorkingNote.NoteSettingChangedListener;
import net.micode.notes.tool.DataUtils;
@ -65,15 +84,30 @@ import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NoteEditActivity extends Activity implements OnClickListener,
//该类主要是针对标签的编辑
//继承了系统内部许多和监听有关的类
public class NoteEditActivity extends AppCompatActivity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener {
private int mode;
private android.media.MediaRecorder mMediaRecorder = new android.media.MediaRecorder();
private class HeadViewHolder {
public TextView tvModified;
@ -84,6 +118,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public ImageView ibSetBgColor;
}
//Map实现数据管理
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
static {
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
@ -119,21 +154,22 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
private static final String TAG = "NoteEditActivity";
//私有化一个界面操作mHeadViewPanel对表头的操作
private HeadViewHolder mNoteHeaderHolder;
private View mHeadViewPanel;
private View mNoteBgColorSelector;
//私有化一个界面操作mFontSizeSelector对标签字体的操作
private View mFontSizeSelector;
//声明编辑控件,对文本操作
private EditText mNoteEditor;
//私有化一个界面操作mNoteEditorPanel文本编辑的控制板
private View mNoteEditorPanel;
//对模板WorkingNote的初始化
private WorkingNote mWorkingNote;
//私有化SharedPreferences的数据存储方式
//它的本质是基于XML文件存储key-value键值对数据
private SharedPreferences mSharedPrefs;
private int mFontSizeId;
@ -148,6 +184,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery;
private Pattern mPattern;
private final int PHOTO_REQUEST = 1;//请求码
private static final int RECORD_REQUEST = 1987;//录音程序请求码
private NoteEditText editText;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -159,8 +200,106 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return;
}
initResources();
//在Activity后实现的点击图标,但是为了目录导航栏的统一,使用了AppCompatActivity的目录功能
// //根据id获取添加图片按钮
// 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");
// //ACTION_GET_CONTENT: 允许用户选择特殊种类的数据,并返回(特殊种类的数据:照一张相片或录一段音)
// Intent loadImage = new Intent(Intent.ACTION_GET_CONTENT);
// //Category属性用于指定当前动作Action被执行的环境.
// //CATEGORY_OPENABLE; 用来指示一个ACTION_GET_CONTENT的intent
// loadImage.addCategory(Intent.CATEGORY_OPENABLE);
// loadImage.setType("image/*");
// startActivityForResult(loadImage, PHOTO_REQUEST);
// }
// });
// editText = findViewById(R.id.note_edit_view);
// textView = findViewById(R.id.text_num);
// // 添加文本改变监听器
// editText.addTextChangedListener(new TextWatcher() {
// int currentLength = 0;
//
// @Override
// public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// textView.setText("字数:" + currentLength);
// }
//
// @Override
// public void onTextChanged(CharSequence s, int start, int before, int count) {
// String processedText = removeImagesAndLinks(editText.getText().toString());
// currentLength = processedText.length();
// }
//
// @Override
// public void afterTextChanged(Editable s) {
// textView.setText("字数:" + currentLength);
// }
// });
//添加一键删除的功能键
/* Button clearButton = findViewById(R.id.clearButton); // 假设你的清屏按钮的 id 是 "clearButton"
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
editText.setText(""); // 清空文本内容
}
});*/
}
private String removeImagesAndLinks(String text) {
// 剔除<img>标签
text = text.replaceAll("<img[^>]*>", "");
// 剔除链接
text = text.replaceAll("<a\\b[^>]*>(.*?)</a>", "");
// 剔除图片路径名称字符
text = text.replaceAll("\\[local\\].*?\\[/local\\]", "");
// 剔除换行符和空格
text = text.replaceAll("\\s", "");
return text;
// StringBuffer stringBuffer = new StringBuffer(text);
// // 剔除<img>标签
//
// // 剔除链接
//
// int Flag1 = -1;
// int Flag2 = -1;
// do {//不计入表示图片的字符
// Flag1 = stringBuffer.indexOf("[local]");
// Flag2 = stringBuffer.indexOf("[/local]");
// if (Flag1 != -1 && Flag2 != -1) {
// stringBuffer = stringBuffer.replace(Flag1, Flag2+1, "");
// }
// } while (Flag1 != -1 && Flag2 != -1);
// do {//不计入换行字符
// Flag1 = stringBuffer.indexOf("\n");
// if (Flag1 != -1){
// stringBuffer = stringBuffer.replace(Flag1, Flag1+1, "");
// }
// } while (Flag1 != -1);
// do {//不计入空格字符
// Flag1 = stringBuffer.indexOf(" ");
// if (Flag1 != -1) {
// stringBuffer = stringBuffer.replace(Flag1, Flag1+1, "");
// }
// } while (Flag1 != -1);
// return stringBuffer.toString();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.note_edit, menu);
return true;
}
/**
* 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
@ -176,7 +315,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return;
}
Log.d(TAG, "Restoring from killed activity");
}
}//为防止内存不足时程序的终止,在这里有一个保存现场的函数
}
private boolean initActivityState(Intent intent) {
@ -253,7 +392,35 @@ public class NoteEditActivity extends Activity implements OnClickListener,
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
| WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
} else {
}
//重点是这个判断条件,通过输入的字符进行展示
else if(TextUtils.equals(Intent.ACTION_SEARCH, intent.getAction())) //点击搜索按钮响应
{
String querystring = intent.getStringExtra(SearchManager.QUERY); //获取搜索框内的字符串
NotesDatabaseHelper dbhelper = new NotesDatabaseHelper(this);
List<String> list = dbhelper.dosearch(querystring);
//完善判断逻辑,减少异常处理状态
if(list.isEmpty()){
Toast.makeText(NoteEditActivity.this, "搜索结果为空", Toast.LENGTH_SHORT).show();
return false;
}
else {
// 打印查询结果
for (String result : list) {
System.out.println(result);
}
// 创建包含查询结果的Intent
Intent showResultIntent = new Intent(NoteEditActivity.this, ShowResultActivity.class);
showResultIntent.putStringArrayListExtra("searchResult", new ArrayList<>(list));
// 启动ShowResultActivity来展示查询结果
startActivity(showResultIntent);
return false;
}
}
else {
Log.e(TAG, "Intent not specified action, should not support");
finish();
return false;
@ -268,6 +435,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
initNoteScreen();
}
//设置外观
private void initNoteScreen() {
mNoteEditor.setTextAppearance(this, TextAppearanceResources
.getTexAppearanceResource(mFontSizeId));
@ -293,14 +461,20 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* is not ready
*/
showAlertHeader();
//!注意这里需要将有图片的位置转换图片格式
convertToImage();
}
//设置闹钟提醒
private void showAlertHeader() {
if (mWorkingNote.hasClockAlert()) {
long time = System.currentTimeMillis();
if (time > mWorkingNote.getAlertDate()) {
mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired);
} else {
} //如果系统时间大于了闹钟设置的时间,那么闹钟失效
else {
mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString(
mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS));
}
@ -312,6 +486,126 @@ public class NoteEditActivity extends Activity implements OnClickListener,
};
}
private void convertToImage() {
// 获取NoteEditText对象
NoteEditText noteEditText = findViewById(R.id.note_edit_view);
// 获取可编辑的文本对象
Editable editable = noteEditText.getEditableText();
// 将可编辑文本转换为字符串
String noteText = editable.toString();
// 获取字符串的长度
int length = editable.length();
// 获取插入图片前光标的位置
int cursorPositionBeforeInsert = noteEditText.getSelectionStart();
// 设置光标位置为文本末尾
noteEditText.setSelection(length);
// 标记是否已经插入图片
boolean inserted = false;
// 遍历字符串
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 bitmap = BitmapFactory.decodeFile(path);
if (bitmap != null) {
// 设置期望高度
int desiredHeight = 2000;
int originalWidth = bitmap.getWidth();
int originalHeight = bitmap.getHeight();
// 计算期望宽度
int desiredWidth = (originalWidth * desiredHeight) / originalHeight;
// 缩放Bitmap对象
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, desiredWidth, desiredHeight, false);
// 创建ImageSpan对象
ImageSpan imageSpan = new ImageSpan(this, scaledBitmap);
// 构造要替换的字符串
String ss = "[local]" + path + "[/local]";
SpannableString spannableString = new SpannableString(ss);
// 设置居中对齐
spannableString.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// 设置图片Span
spannableString.setSpan(imageSpan, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// 添加ClickableSpan使得点击图片末尾的光标可以和图片对齐
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View view) {
int selectionEnd = noteEditText.getSelectionEnd();
if (selectionEnd == cursorPositionBeforeInsert) {
noteEditText.setSelection(cursorPositionBeforeInsert + 1);
}
}
};
spannableString.setSpan(clickableSpan, ss.length(), ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// 替换原字符串为图片SpannableString
editable.replace(i, i + len + 15, spannableString);
// 标记已经插入图片
inserted = true;
// 设置光标位置为插入图片前位置
noteEditText.setSelection(cursorPositionBeforeInsert);
// 清除点击事件
ClickableSpan[] spans = editable.getSpans(cursorPositionBeforeInsert, cursorPositionBeforeInsert, ClickableSpan.class);
if (spans != null && spans.length > 0) {
for (ClickableSpan span : spans) {
editable.removeSpan(span);
}
}
}
}
}
}
// 如果已插入图片,则在插入图片后添加换行符
if (inserted) {
editable.append("\n");
// 在插入图片后为NoteEditText设置触摸事件监听器用于处理图片点击事件
noteEditText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
// 获取点击位置的偏移量
int offset = noteEditText.getOffsetForPosition(event.getX(), event.getY());
// 获取文本中所有图片的ImageSpan
ImageSpan[] imageSpans = editable.getSpans(0, editable.length(), ImageSpan.class);
// 遍历图片Span
for (ImageSpan span : imageSpans) {
int start = editable.getSpanStart(span);
int end = editable.getSpanEnd(span);
// 如果点击位置在图片所在行返回true表示消费了该事件
if (offset >= start && offset <= end) {
return true;
}
}
}
return false;
}
});
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@ -321,6 +615,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//在创建一个新的标签时,先在数据库中匹配
//如果不存在,那么先在数据库中存储
/**
* For new note without note id, we should firstly save it to
* generate a id. If the editing note is not worth saving, there
@ -329,6 +625,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
//在创建一个新的标签时,先在数据库中匹配
//如果不存在,那么先在数据库中存储
outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId());
Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState");
}
@ -349,6 +647,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return super.dispatchTouchEvent(ev);
}
//对屏幕触控的坐标范围进行操作
private boolean inRangeOfView(View view, MotionEvent ev) {
int []location = new int[2];
view.getLocationOnScreen(location);
@ -406,6 +705,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
clearSettingState();
}
//和桌面小工具的同步
private void updateWidget() {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) {
@ -430,7 +730,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (id == R.id.btn_set_bg_color) {
mNoteBgColorSelector.setVisibility(View.VISIBLE);
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
- View.VISIBLE);
View.VISIBLE);
} else if (sBgSelectorBtnsMap.containsKey(id)) {
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE);
@ -502,9 +802,20 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else {
menu.findItem(R.id.menu_delete_remind).setVisible(false);
}
// //更换背景
// if(mode==0){
// menu.findItem(R.id.menu_hutao).setVisible(false);
// }else if(mode==1){
// menu.findItem(R.id.menu_keli).setVisible(false);
// } else if (mode==2) {
// menu.findItem(R.id.menu_moren).setVisible(false);
// }
return true;
}
//删除标签,修改字体大小
//ToDo
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@ -547,12 +858,24 @@ public class NoteEditActivity extends Activity implements OnClickListener,
case R.id.menu_delete_remind:
mWorkingNote.setAlertDate(0, false);
break;
case R.id.menu_select_image:
// 用户点击了选择图片菜单项
Intent loadImage = new Intent(Intent.ACTION_GET_CONTENT);
loadImage.addCategory(Intent.CATEGORY_OPENABLE);
loadImage.setType("image/*");
startActivityForResult(loadImage, PHOTO_REQUEST);
break;
default:
break;
}
return true;
}
//TODO
//添加提醒
private void setReminder() {
DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis());
d.setOnDateTimeSetListener(new OnDateTimeSetListener() {
@ -567,6 +890,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* Share note to apps that support {@link Intent#ACTION_SEND} action
* and {@text/plain} type
*/
//TODO
//分享
private void sendTo(Context context, String info) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, info);
@ -574,6 +899,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
context.startActivity(intent);
}
// 新建标签
//TODO
private void createNewNote() {
// Firstly, save current editing notes
saveNote();
@ -588,6 +915,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private void deleteCurrentNote() {
if (mWorkingNote.existInDatabase()) {
//假如当前运行的便签内存有数据
HashSet<Long> ids = new HashSet<Long>();
long id = mWorkingNote.getNoteId();
if (id != Notes.ID_ROOT_FOLDER) {
@ -646,18 +974,22 @@ public class NoteEditActivity extends Activity implements OnClickListener,
updateWidget();
}
/*
*
*
*/
public void onEditTextDelete(int index, String text) {
int childCount = mEditTextList.getChildCount();
int childCount = mEditTextList.getChildCount();//没有编辑框的话直接返回
if (childCount == 1) {
return;
}
for (int i = index + 1; i < childCount; i++) {
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i - 1);
.setIndex(i - 1); //通过id把编辑框存在便签编辑框中
}
mEditTextList.removeViewAt(index);
mEditTextList.removeViewAt(index); //删除特定位置的视图
NoteEditText edit = null;
if(index == 0) {
edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById(
@ -665,13 +997,17 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else {
edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById(
R.id.et_edit_text);
}
}//通过id把编辑框存在空的NoteEditText中
int length = edit.length();
edit.append(text);
edit.requestFocus();
edit.setSelection(length);
}
/*
*
*
*/
public void onEditTextEnter(int index, String text) {
/**
* Should not happen, check for debug
@ -690,7 +1026,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
.setIndex(i);
}
}
/*
*
*
*/
private void switchToListMode(String text) {
mEditTextList.removeAllViews();
String[] items = text.split("\n");
@ -708,6 +1047,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mEditTextList.setVisibility(View.VISIBLE);
}
/*
*
*
*/
private Spannable getHighlightQueryResult(String fullText, String userQuery) {
SpannableString spannable = new SpannableString(fullText == null ? "" : fullText);
if (!TextUtils.isEmpty(userQuery)) {
@ -725,6 +1068,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return spannable;
}
//获取列表项
private View getListItem(String item, int index) {
View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);
final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
@ -756,6 +1100,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return view;
}
// 函数功能:便签内容发生改变所触发的事件
public void onTextChange(int index, boolean hasText) {
if (index >= mEditTextList.getChildCount()) {
Log.e(TAG, "Wrong index, should not happen");
@ -766,6 +1111,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE);
}
//如果内容不为空则将其子编辑框可见性置为可见,否则不可见
}
public void onCheckListModeChanged(int oldMode, int newMode) {
@ -779,9 +1125,12 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));
mEditTextList.setVisibility(View.GONE);
mNoteEditor.setVisibility(View.VISIBLE);
convertToImage(); //退出清单模式,应该将有图片的地方显示出来
}
}
//TODO
//分享,设置勾选选项表并返回是否勾选的标记
private boolean getWorkingText() {
boolean hasChecked = false;
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
@ -805,6 +1154,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return hasChecked;
}
//保存注释
private boolean saveNote() {
getWorkingText();
boolean saved = mWorkingNote.saveNote();
@ -816,11 +1166,15 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* new node requires to the top of the list. This code
* {@link #RESULT_OK} is used to identify the create/edit state
*/
//如英文注释所说链接RESULT_OK是为了识别保存的2种情况
// 一是创建后保存,二是修改后保存
setResult(RESULT_OK);
}
return saved;
}
//TODO
//发送到桌面
private void sendToDesktop() {
/**
* Before send message to home, we should make sure that current
@ -829,11 +1183,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
*/
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
}//若不存在数据也就是新的标签就保存起来先
if (mWorkingNote.getNoteId() > 0) {
Intent sender = new Intent();
//建立发送到桌面的连接器
Intent shortcutIntent = new Intent(this, NoteEditActivity.class);
//链接是一个视图
shortcutIntent.setAction(Intent.ACTION_VIEW);
shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId());
sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
@ -841,8 +1197,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
makeShortcutIconTitle(mWorkingNote.getContent()));
sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app));
////将便签的相关信息都添加到要发送的文件里
sender.putExtra("duplicate", true);
//设置sneder的行为是发送
sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
//显示到桌面
showToast(R.string.info_note_enter_desktop);
sendBroadcast(sender);
} else {
@ -856,6 +1215,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
}
/*
*
*
* content2
*/
private String makeShortcutIconTitle(String content) {
content = content.replace(TAG_CHECKED, "");
content = content.replace(TAG_UNCHECKED, "");
@ -870,4 +1234,274 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();
}
//重写onActivityResult()来处理返回的数据
//直接采用简单的方法类返回数据
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(); // 1. 获取图片的真实路径
Bitmap bitmap = null;
try {
// 2. 解码图片convertToImage
bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));
} catch (FileNotFoundException e) {
Log.d(TAG, "onActivityResult: get file_exception");
e.printStackTrace();
}
if (bitmap != null) {
// 3. 根据Bitmap对象创建ImageSpan对象
Log.d(TAG, "onActivityResult: bitmap is not null");
ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
String path = getPath(this, originalUri);
// 4. 使用[local][/local]将path括起来用于之后方便识别图片路径在note中的位置
String img_fragment= "[local]" + path + "[/local]";
// 创建一个SpannableString对象以便插入用ImageSpan对象封装的图像
SpannableString spannableString = new SpannableString(img_fragment);
spannableString.setSpan(imageSpan, 0, img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// 5. 将选择的图片追加到EditText中光标所在位置
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); // 将图片插入到光标所在位置
// 6. 更新笔记内容
mWorkingNote.mContent = e.getText().toString();
mWorkingNote.mContent = mWorkingNote.mContent.replaceAll("(?m)^[ \t]*\r?\n", ""); // 删除空白行
} else {
// 异常处理:获取图片失败
Toast.makeText(NoteEditActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
}
break;
/* case RECORD_REQUEST:
Uri audioUri = intent.getData();
Button playButton = findViewById(R.id.button_play_audio);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 在按钮点击事件中处理播放音频的逻辑
playAudio(audioUri);
}
});
break;*/
default:
break;
}
}
private void playAudio(Uri audioUri) {
try {
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(getApplicationContext(), audioUri);
mediaPlayer.prepare();
mediaPlayer.start();
// 当音频播放完成后,可以在需要的地方添加监听器
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// 音频播放完成后的操作
}
});
} catch (IOException e) {
e.printStackTrace();
// 处理播放音频时的异常情况
}
}
//获取文件的real path
public String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// // DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else
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;
}
//获取数据列_获取此 Uri 的数据列的值。这对MediaStore Uris 和其他基于文件的 ContentProvider。
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 isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
//是否为下载文件
public boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
//是否为媒体文件
public boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private void saveAsTxtFile() {
NoteEditText noteEditText = findViewById(R.id.note_edit_view);
Editable editable = noteEditText.getEditableText();
String noteText = editable.toString();
try {
// 创建文件名
String fileName = noteText.substring(0,3)+".txt";
// 保存到文件管理器的download目录中
File publicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
if (publicDirectory != null) {
// 创建保存文件的完整路径
File file = new File(publicDirectory, fileName);
// 创建文件输出流
FileOutputStream outputStream = new FileOutputStream(file);
// 写入文本内容
outputStream.write(noteText.getBytes());
// 关闭文件输出流
outputStream.close();
// 获取保存文件的完整路径
String filePath = file.getAbsolutePath();
Toast.makeText(this, "成功保存到:" + filePath, Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show();
}
}
private void saveAsImageFile() {
NoteEditText noteEditText = findViewById(R.id.note_edit_view);
Editable editable = noteEditText.getEditableText();
String noteText = editable.toString();
try {
// 创建文件名
String fileName = noteText.substring(0,3)+".png";
// 保存到文件管理器的download目录中
File publicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
if (publicDirectory != null) {
// 创建保存文件的完整路径
File file = new File(publicDirectory, fileName);
// 创建Bitmap对象
Bitmap bitmap = Bitmap.createBitmap(noteEditText.getWidth(), noteEditText.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
noteEditText.draw(canvas);
// 创建文件输出流
FileOutputStream outputStream = new FileOutputStream(file);
// 将Bitmap保存为PNG格式的图片
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
// 关闭文件输出流0
outputStream.close();
// 获取保存文件的完整路径
String filePath = file.getAbsolutePath();
Toast.makeText(this, "成功保存到:" + filePath, Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show();
}
}
private void saveAsWordFile() {
NoteEditText noteEditText = findViewById(R.id.note_edit_view);
Editable editable = noteEditText.getEditableText();
String noteText = editable.toString();
try {
// 创建文件名
String fileName = noteText.substring(0,3)+".doc";
// 保存到文件管理器的download目录中
File publicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
if (publicDirectory != null) {
// 创建保存文件的完整路径
File file = new File(publicDirectory, fileName);
// 创建文件输出流
FileOutputStream outputStream = new FileOutputStream(file);
// 写入文本内容
outputStream.write(noteText.getBytes());
// 关闭文件输出流
outputStream.close();
// 获取保存文件的完整路径
String filePath = file.getAbsolutePath();
Toast.makeText(this, "成功保存到:" + filePath, Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show();
}
}
}

@ -18,10 +18,12 @@ package net.micode.notes.ui;
import android.content.Context;
import android.graphics.Rect;
import android.text.Editable;
import android.text.Layout;
import android.text.Selection;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
@ -31,13 +33,14 @@ import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.widget.EditText;
import android.widget.TextView;
import net.micode.notes.R;
import java.util.HashMap;
import java.util.Map;
public class NoteEditText extends EditText {
public class NoteEditText extends android.support.v7.widget.AppCompatEditText {
private static final String TAG = "NoteEditText";
private int mIndex;
private int mSelectionStartBeforeDelete;
@ -80,6 +83,8 @@ public class NoteEditText extends EditText {
public NoteEditText(Context context) {
super(context, null);
mIndex = 0;
init();
}
public void setIndex(int index) {
@ -92,10 +97,12 @@ public class NoteEditText extends EditText {
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle);
init();
}
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
// TODO Auto-generated constructor stub
}
@ -214,4 +221,34 @@ public class NoteEditText extends EditText {
}
super.onCreateContextMenu(menu);
}
//显示字符数
private TextView mCharacterCountView;
public void setCharacterCountView(TextView textView) {
mCharacterCountView = textView;
}
private void init() {
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 (mCharacterCountView != null) {
String text = s.toString().replaceAll("\\s", "");
int characterCount = text.length();
mCharacterCountView.setText(String.valueOf(characterCount));
}
}
});
}
}

@ -28,12 +28,16 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.ActionMode;
import android.view.ContextMenu;
@ -61,12 +65,14 @@ import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.DataFetch;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.remote.GTaskSyncService;
import net.micode.notes.model.WorkingNote;
import net.micode.notes.tool.BackupUtils;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.MD5Calc;
import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import net.micode.notes.widget.NoteWidgetProvider_2x;
@ -76,9 +82,13 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
public class NotesListActivity extends AppCompatActivity implements OnClickListener, OnItemLongClickListener {
//首页的背景图切换
private int mode=-1;
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private static final int FOLDER_LIST_QUERY_TOKEN = 1;
@ -135,10 +145,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private final static int REQUEST_CODE_OPEN_NODE = 102;
private final static int REQUEST_CODE_NEW_NODE = 103;
public static int secret_mode=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.note_list);
getWindow().setBackgroundDrawableResource(R.drawable.mi1);
initResources();
/**
@ -242,7 +256,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mMoveMenu = menu.findItem(R.id.move);
if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER
|| DataUtils.getUserFolderCount(mContentResolver) == 0) {
mMoveMenu.setVisible(false);
mMoveMenu.setVisible(true);
} else {
mMoveMenu.setVisible(true);
mMoveMenu.setOnMenuItemClickListener(this);
@ -274,6 +288,15 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
// Update dropdown menu
String format = getResources().getString(R.string.menu_select_title, selectedCount);
mDropDownMenu.setTitle(format);
// 改变选中后,目录字体的颜色
SpannableString spannableString = new SpannableString(format);
ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.WHITE);
spannableString.setSpan(colorSpan, 0, format.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
//
mDropDownMenu.setTitle(spannableString);
MenuItem item = mDropDownMenu.findItem(R.id.action_select_all);
if (item != null) {
if (mNotesListAdapter.isAllSelected()) {
@ -286,13 +309,24 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
//这个初始化界面不能修改
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
// public boolean onPrepareAction(ActionMode mode, Menu menu) {
// // TODO Auto-generated method stub
// if(secret_mode==1){
// menu.findItem(R.id.menu_secret).setVisible(false);
// }else{
// menu.findItem(R.id.menu_quit_secret).setVisible(false);
// }
// return true;
// }
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// TODO Auto-generated method stub
return false;
}
@ -345,7 +379,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true;
}
}
private class NewNoteOnTouchListener implements OnTouchListener {
public boolean onTouch(View v, MotionEvent event) {
@ -408,20 +441,43 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
};
//对当前的笔记是否可视化
private void startAsyncNotesListQuery() {
String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION
: NORMAL_SELECTION;
if(secret_mode==0) {
mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null,
Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[]{
String.valueOf(mCurrentFolderId)
}, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
}else{
String str1 = "";
String [] PROJECTION = new String [] { //定义一个新的PROJECTION数组只换掉SNIPPET
NoteColumns.ID,
NoteColumns.ALERTED_DATE,
NoteColumns.BG_COLOR_ID,
NoteColumns.CREATED_DATE,
NoteColumns.HAS_ATTACHMENT,
NoteColumns.MODIFIED_DATE,
NoteColumns.NOTES_COUNT,
NoteColumns.PARENT_ID,
// NoteColumns.SNIPPET,
str1,
NoteColumns.TYPE,
NoteColumns.WIDGET_ID,
NoteColumns.WIDGET_TYPE,
};
mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null,
Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] {
Notes.CONTENT_NOTE_URI, PROJECTION, selection, new String[]{
String.valueOf(mCurrentFolderId)
}, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
}
}
private final class BackgroundQueryHandler extends AsyncQueryHandler {
public BackgroundQueryHandler(ContentResolver contentResolver) {
super(contentResolver);
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
switch (token) {
@ -506,6 +562,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}.execute();
}
// TODO
// 删除文件夹
private void deleteFolder(long folderId) {
if (folderId == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Wrong folder id, should not happen " + folderId);
@ -534,12 +592,69 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
private void openNode(NoteItemData data) {
Intent intent = new Intent(this, NoteEditActivity.class);
// 获取SharedPreferences对象
SharedPreferences sharedPreferences = getSharedPreferences("NoteLock", MODE_PRIVATE);
if (!sharedPreferences.getBoolean("isLocked", false)) {
// 如果笔记未被锁定,直接进入下一个界面
Intent intent = new Intent(NotesListActivity.this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, data.getId());
this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
NotesListActivity.this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
}
else {
// 如果笔记被锁定,要求输入密码然后进入
// 获取 SharedPreferences 中保存的密码
SharedPreferences prefs = getSharedPreferences("MyApp", MODE_PRIVATE);
final String savedPassword = prefs.getString("password", "");
if (!savedPassword.isEmpty()) {
// 如果密码存在,弹出一个对话框让用户输入密码
AlertDialog.Builder passwordDialog = new AlertDialog.Builder(NotesListActivity.this);
passwordDialog.setTitle("输入密码");
final EditText input = new EditText(NotesListActivity.this);
passwordDialog.setView(input);
passwordDialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String enteredPassword = input.getText().toString();
try {
// 创建 MessageDigest 实例
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// 生成哈希值
byte[] hash = digest.digest(enteredPassword.getBytes(Charset.forName("UTF-8")));
// 将字节转换为十六进制字符串
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
// 获取输入密码的哈希值
String enteredHashedPassword = hexString.toString();
// 比较输入密码的哈希值与保存的哈希密码是否相同
if (enteredHashedPassword.equals(savedPassword)) {
// 如果密码正确,解锁笔记并打开
Intent intent = new Intent(NotesListActivity.this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, data.getId());
NotesListActivity.this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
} else {
// 如果密码错误,弹出提示信息
Toast.makeText(NotesListActivity.this, "密码错误", Toast.LENGTH_SHORT).show();
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
});
passwordDialog.setNegativeButton("取消", null);
passwordDialog.show();
}
}
}
//TODO
//查看文件夹
private void openFolder(NoteItemData data) {
mCurrentFolderId = data.getId();
startAsyncNotesListQuery();
@ -579,6 +694,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
// TODO
// 新建文件夹,修改文件夹名称
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);
@ -778,10 +895,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true;
}
//更改按键的功能设定
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_new_folder: {
case R.id.menu_new_folder:{
showCreateOrModifyFolderDialog(true);
break;
}
@ -805,25 +924,158 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
startPreferenceActivity();
break;
}
case R.id.menu_new_note: {
createNewNote();
break;
}
case R.id.menu_search:
onSearchRequested();
break;
case R.id.menu_secret: { //进入私密模式
//TODO
/**
* data/data/net.micode.notes/files/privacy_space_key.txt
*/
// 创建一个DataFetch实例(自定义),用于处理文件写操作
DataFetch datafetch = new DataFetch();
// 检查是否存在名为"privacy_space_key.txt"的文件,如果不存在,表示尚未设置隐私空间密码
if (!datafetch.fileIsExists(NotesListActivity.this, "privacy_space_key.txt")) {
// 弹出对话框,提示用户设置隐私空间密码
final EditDialog registerKeyDialog = new EditDialog(NotesListActivity.this);
registerKeyDialog.setTitle("请设置隐私空间密码");
// 设置确定按钮的点击监听器,用于接收用户输入的密码并进行处理
registerKeyDialog.setYesOnclickListener("确定", new EditDialog.onYesOnclickListener() {
@Override
public void onYesClick(String key) {
// 对密码进行MD5加密处理
String hashed_key = MD5Calc.md5Java(key);
// 将加密后的密码写入文件
datafetch.writeFile(NotesListActivity.this, "privacy_space_key.txt", hashed_key);
// 弹出Toast提示用户设置成功
Toast.makeText(NotesListActivity.this, "您已设置隐私空间密码", Toast.LENGTH_SHORT).show();
// 关闭对话框
registerKeyDialog.dismiss();
}
});
// 设置取消按钮的点击监听器,用于关闭对话框
registerKeyDialog.setNoOnclickListener("取消", new EditDialog.onNoOnclickListener(){
public void onNoClick(){
registerKeyDialog.dismiss();
}
});
// 显示对话框
registerKeyDialog.show();
} else {
// 如果存在名为"privacy_space_key.txt"的文件,表示已经设置了隐私空间密码
// 弹出对话框,提示用户输入密码验证身份
final EditDialog editKeyDialog = new EditDialog(NotesListActivity.this);
editKeyDialog.setTitle("正在进入隐私空间");
// 设置确定按钮的点击监听器,用于接收用户输入的密码并进行处理
editKeyDialog.setYesOnclickListener("确定", new EditDialog.onYesOnclickListener() {
@Override
public void onYesClick(String key) {
// 读取之前设置的密码
String correct_hashed_key = datafetch.readFile(NotesListActivity.this, "privacy_space_key.txt");
// 对用户输入的密码进行MD5加密处理
String input_hashed_key = MD5Calc.md5Java(key);
// 比较输入的密码与正确密码是否匹配
if (correct_hashed_key.equals(input_hashed_key)) {
// 如果密码匹配,弹出确认对话框,提示用户进入私密模式
AlertDialog.Builder dialog = new AlertDialog.Builder(NotesListActivity.this);
dialog.setTitle("重要提醒");
dialog.setMessage("您确认进入私密模式吗?");
dialog.setCancelable(false);
// 设置确认按钮的点击监听器,用于进入私密模式并启动异步查询笔记列表的操作
dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 设置secret_mode为1表示进入私密模式
secret_mode = 1;
// 启动异步查询笔记列表的操作
startAsyncNotesListQuery();
// 弹出Toast提示用户进入私密模式
Toast.makeText(NotesListActivity.this, "您已进入私密模式", Toast.LENGTH_SHORT).show();
}
});
// 设置取消按钮的点击监听器,用于关闭对话框
dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
// 显示对话框
dialog.show();
// 启动异步查询笔记列表的操作
startAsyncNotesListQuery();
// 关闭对话框
editKeyDialog.dismiss();
} else {
// 如果密码不匹配弹出Toast提示用户密码输入错误
Toast.makeText(NotesListActivity.this, "密码输入错误!", Toast.LENGTH_SHORT).show();
// 关闭对话框
editKeyDialog.dismiss();
}
}
});
// 设置取消按钮的点击监听器,用于关闭对话框
editKeyDialog.setNoOnclickListener("取消", new EditDialog.onNoOnclickListener() {
@Override
public void onNoClick() {
editKeyDialog.dismiss();
}
});
// 显示对话框
editKeyDialog.show();
}
break;
}
case R.id.menu_quit_secret:{ //退出私密模式
// 将secret_mode设置为0表示退出私密模式
secret_mode = 0;
// 创建一个AlertDialog.Builder实例
AlertDialog.Builder dialog = new AlertDialog.Builder(NotesListActivity.this);
// 设置对话框标题和内容
dialog.setTitle("重要提醒");
dialog.setMessage("您确认退出私密模式吗?");
dialog.setCancelable(false);
// 设置确认按钮的点击监听器,用于退出私密模式并启动异步查询笔记列表的操作
dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 启动异步查询笔记列表的操作
startAsyncNotesListQuery();
// 弹出Toast提示用户退出私密模式
Toast.makeText(NotesListActivity.this, "您已退出私密模式", Toast.LENGTH_SHORT).show();
}
});
// 设置取消按钮的点击监听器,用于关闭对话框
dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 空操作
}
});
// 显示对话框
dialog.show();
//TODO
break;
}
default:
break;
}
return true;
}
//TODO
//搜索
@Override
public boolean onSearchRequested() {
startSearch(null, false, null /* appData */, false);
return true;
}
// TODO
// 导出文本
private void exportNoteToText() {
final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
new AsyncTask<Void, Void, Integer>() {

@ -30,7 +30,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
/*
* 便CursorAdaptercursorListView
* NotesListAdapter便
*/
public class NotesListAdapter extends CursorAdapter {
private static final String TAG = "NotesListAdapter";
private Context mContext;
@ -43,24 +46,40 @@ public class NotesListAdapter extends CursorAdapter {
public int widgetType;
};
public NotesListAdapter(Context context) {
super(context, null);
mSelectedIndex = new HashMap<Integer, Boolean>();
mSelectedIndex = new HashMap<Integer, Boolean>(); //新建选项下标的hash表
mContext = context;
mNotesCount = 0;
}
/*
*
* 使NotesListItem
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new NotesListItem(context);
}
/*
*
*
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof NotesListItem) {
//若view是NotesListItem的一个实例
NoteItemData itemData = new NoteItemData(context, cursor);
((NotesListItem) view).bind(context, itemData, mChoiceMode,
isSelectedItem(cursor.getPosition()));
//则新建一个项目选项并且用bind跟将view和鼠标内容便签数据捆绑在一起
}
}
@ -87,8 +106,14 @@ public class NotesListAdapter extends CursorAdapter {
}
}
}
//遍历所有光标可用的位置在判断为便签类型之后勾选单项框
}
/*
*
*
*/
public HashSet<Long> getSelectedItemIds() {
HashSet<Long> itemSet = new HashSet<Long>();
for (Integer position : mSelectedIndex.keySet()) {
@ -104,6 +129,10 @@ public class NotesListAdapter extends CursorAdapter {
return itemSet;
}
/*
* Widget
*
*/
public HashSet<AppWidgetAttribute> getSelectedWidget() {
HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>();
@ -128,8 +157,14 @@ public class NotesListAdapter extends CursorAdapter {
return itemSet;
}
/*
*
*
*/
public int getSelectedCount() {
Collection<Boolean> values = mSelectedIndex.values();
//首先获取选项下标的值
if (null == values) {
return 0;
}
@ -143,11 +178,20 @@ public class NotesListAdapter extends CursorAdapter {
return count;
}
/*
*
*
*/
public boolean isAllSelected() {
int checkedCount = getSelectedCount();
return (checkedCount != 0 && checkedCount == mNotesCount);
}
/*
*
*
*/
public boolean isSelectedItem(final int position) {
if (null == mSelectedIndex.get(position)) {
return false;

@ -69,7 +69,7 @@ public class NotesListItem extends LinearLayout {
mCallName.setText(data.getCallName());
mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem);
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
if (data.hasAlert()) {
if (data.hasAlert()) {//图片来源的设置
mAlert.setImageResource(R.drawable.clock);
mAlert.setVisibility(View.VISIBLE);
} else {
@ -94,11 +94,13 @@ public class NotesListItem extends LinearLayout {
}
}
}
///设置内容获取相关时间从data里编辑的日期中获取
mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
setBackground(data);
}
//根据data的文件属性来设置背景
private void setBackground(NoteItemData data) {
int id = data.getBgColorId();
if (data.getType() == Notes.TYPE_NOTE) {

@ -47,7 +47,10 @@ import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.remote.GTaskSyncService;
/*
*NotesPreferenceActivity便
* PreferenceActivityActivity
*/
public class NotesPreferenceActivity extends PreferenceActivity {
public static final String PREFERENCE_NAME = "notes_preferences";
@ -78,6 +81,7 @@ public class NotesPreferenceActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.preferences);
mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
//根据同步账户关键码来初始化分组
mReceiver = new GTaskReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME);
@ -88,13 +92,19 @@ public class NotesPreferenceActivity extends PreferenceActivity {
getListView().addHeaderView(header, null, true);
}
/*
* activity
*
*/
@Override
protected void onResume() {
//先执行父类 的交互实现
super.onResume();
// need to set sync account automatically if user has added a new
// account
if (mHasAddedAccount) {
//若用户新加了账户则自动设置同步账户
Account[] accounts = getGoogleAccounts();
if (mOriAccounts != null && accounts.length > mOriAccounts.length) {
for (Account accountNew : accounts) {
@ -116,6 +126,11 @@ public class NotesPreferenceActivity extends PreferenceActivity {
refreshUI();
}
/*
* activity
*
*/
@Override
protected void onDestroy() {
if (mReceiver != null) {
@ -124,6 +139,10 @@ public class NotesPreferenceActivity extends PreferenceActivity {
super.onDestroy();
}
/*
*
*
*/
private void loadAccountPreference() {
mAccountCategory.removeAll();
@ -154,6 +173,11 @@ public class NotesPreferenceActivity extends PreferenceActivity {
mAccountCategory.addPreference(accountPref);
}
/*
*
*
*/
private void loadSyncButton() {
Button syncButton = (Button) findViewById(R.id.preference_sync_button);
TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
@ -198,6 +222,10 @@ public class NotesPreferenceActivity extends PreferenceActivity {
loadSyncButton();
}
/*
*
*
*/
private void showSelectAccountAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
@ -207,10 +235,13 @@ public class NotesPreferenceActivity extends PreferenceActivity {
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips));
//设置标题以及子标题的内容
dialogBuilder.setCustomTitle(titleView);
dialogBuilder.setPositiveButton(null, null);
//设置对话框的自定义标题建立一个YES的按钮
Account[] accounts = getGoogleAccounts();
//获取同步账户信息
String defAccount = getSyncAccountName(this);
mOriAccounts = accounts;
@ -254,6 +285,10 @@ public class NotesPreferenceActivity extends PreferenceActivity {
});
}
/*
*
*
*/
private void showChangeAccountConfirmAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
@ -283,6 +318,10 @@ public class NotesPreferenceActivity extends PreferenceActivity {
dialogBuilder.show();
}
/*
*
*
*/
private Account[] getGoogleAccounts() {
AccountManager accountManager = AccountManager.get(this);
return accountManager.getAccountsByType("com.google");
@ -317,6 +356,10 @@ public class NotesPreferenceActivity extends PreferenceActivity {
Toast.LENGTH_SHORT).show();
}
}
/*
*
*
*/
private void removeSyncAccount() {
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
@ -340,12 +383,20 @@ public class NotesPreferenceActivity extends PreferenceActivity {
}).start();
}
/*
*
*
*/
public static String getSyncAccountName(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
}
/*
*
*
*/
public static void setLastSyncTime(Context context, long time) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
@ -354,18 +405,27 @@ public class NotesPreferenceActivity extends PreferenceActivity {
editor.commit();
}
/*
*
*
*/
public static long getLastSyncTime(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0);
}
/*
*
* BroadcastReceiver
*/
private class GTaskReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
refreshUI();
if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) {
//获取随广播而来的Intent中的同步服务的数据
TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
syncStatus.setText(intent
.getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG));
@ -373,6 +433,11 @@ public class NotesPreferenceActivity extends PreferenceActivity {
}
}
/*
*
*
* :MenuItem
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {

@ -0,0 +1,38 @@
package net.micode.notes.ui;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import net.micode.notes.R;
import java.util.List;
public class ShowResultActivity extends AppCompatActivity {
/**
* 便
*/
private String TAG="ShowResultActivity";
@SuppressLint("WrongViewCast")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_list);
Log.e(TAG,"search");
ListView listView = findViewById(R.id.listview); // 找到 ListView
Intent intent = getIntent();
if (intent != null) {
List<String> searchResult = intent.getStringArrayListExtra("searchResult");
if (searchResult != null && !searchResult.isEmpty()) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, searchResult);
listView.setAdapter(adapter); // 使用 ArrayAdapter 设置查询结果到 ListView
}
}
}
}

@ -0,0 +1,88 @@
package net.micode.notes.ui;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.animation.AlphaAnimation;
import android.widget.TextView;
import net.micode.notes.R;
public class SplashActivity extends AppCompatActivity {
private static final int ANIMATION_DURATION = 0; // 动画持续时间,单位为毫秒
private static final int SPLASH_DURATION = 0; // 欢迎页展示时间,单位为毫秒
private Handler mHandler = new Handler();
private MediaPlayer mMediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_splash);
//
//
// // 创建 MediaPlayer 对象,并指定要播放的音频文件
//// playAudio(R.raw.testmusic);
//
//
// // 获取 TextView 的引用
// TextView textView = findViewById(R.id.fullscreen_content);
//
// // 创建透明度动画对象,从完全透明到不透明
// AlphaAnimation alphaAnimation = new AlphaAnimation(0f, 1f);
// alphaAnimation.setDuration(ANIMATION_DURATION); // 设置动画持续时间
//
// // 应用动画效果到 TextView 的背景上
// textView.startAnimation(alphaAnimation);
/**
* ~
*/
/*//自主点击跳转
Button skipButton = findViewById(R.id.skip_button);
skipButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SplashActivity.this, NotesListActivity.class);
startActivity(intent);
finish(); // 销毁欢迎页
}
});*/
// 当计时结束时,跳转至 NotesListActivity
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// 在 Activity 销毁时停止播放音频并释放 MediaPlayer 资源
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
Intent intent = new Intent(SplashActivity.this, NotesListActivity.class);
startActivity(intent);
finish(); // 销毁欢迎页
}
}, SPLASH_DURATION);
}
//测试音频BGM
private void playAudio(int audioResId) {
// 创建 MediaPlayer 对象,并指定要播放的音频文件
final MediaPlayer mediaPlayer = MediaPlayer.create(this, audioResId);
// 开始播放音频
mediaPlayer.start();
// 在播放完成后停止播放并释放资源
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayer.stop();
mediaPlayer.release();
}
});
}
}

@ -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)

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save