Compare commits

..

4 Commits

Author SHA1 Message Date
huliaoying 195e999353 add tes
2 years ago
huliaoying 7fda2de9dd Merge branch 'develop' of bdgit.educoder.net:pnq7jmp26/note
2 years ago
huliaoying 4475bb47ec add
2 years ago
pvjtgw7f6 24c39ac74b Update README.md
2 years ago

37
.gitignore vendored

@ -0,0 +1,37 @@
*.iml
.DS_Store
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/dictionaries
.idea/libraries
.idea/
# Keystore files
*.jks
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild

@ -1,16 +1,3 @@
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.
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.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@ -188,3 +175,27 @@
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

@ -1,9 +0,0 @@
# generated files
bin/
gen/
# Local configuration file (sdk path, etc)
project.properties
.settings/
.classpath
.project

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

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

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="NONE" />
</component>
<component name="ChangeListManager">
<list default="true" id="da0340b3-f7de-4062-99e6-bee7bc881776" name="Default Changelist" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="CurrentFile" />
</component>
<component name="ProjectId" id="2M591aRiSTrlymFzGGgFUB7bjIl" />
<component name="ProjectViewState">
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.cidr.known.project.marker": "true",
"cidr.known.project.marker": "true",
"last_opened_file_path": "E:/小米便签/Notes-master"
}
}]]></component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="da0340b3-f7de-4062-99e6-bee7bc881776" name="Default Changelist" comment="" />
<created>1677046361453</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1677046361453</updated>
<workItem from="1677046362780" duration="257000" />
<workItem from="1677054230402" duration="33000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="2" />
</component>
</project>

@ -1,23 +0,0 @@
[中文]
1. MiCode便签是小米便签的社区开源版由MIUI团队(www.miui.com) 发起并贡献第一批代码遵循NOTICE文件所描述的开源协议
今后为MiCode社区(www.micode.net) 拥有,并由社区发布和维护。
2. Bug反馈和跟踪请访问Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. 功能建议和综合讨论请访问MiCode,
http://micode.net/forum.php?mod=forumdisplay&fid=38
[English]
1. MiCode Notes is open source edition of XM notepad, it's first initiated and sponsored by MIUI team (www.miui.com).
It's opened under license described by NOTICE file. It's owned by the MiCode community (www.micode.net). In future,
the MiCode community will release and maintain this project.
2. Regarding issue tracking, please visit Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. Regarding feature request and general discussion, please visit Micode forum,
http://micode.net/forum.php?mod=forumdisplay&fid=38

@ -1,2 +1,29 @@
<<<<<<< HEAD
# note
=======
# MiNotes
[中文]
1. MiCode便签是小米便签的社区开源版由MIUI团队(www.miui.com) 发起并贡献第一批代码遵循NOTICE文件所描述的开源协议
今后为MiCode社区(www.micode.net) 拥有,并由社区发布和维护。
2. Bug反馈和跟踪请访问Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. 功能建议和综合讨论请访问MiCode,
http://micode.net/forum.php?mod=forumdisplay&fid=38
[English]
1. MiCode Notes is open source edition of XM notepad, it's first initiated and sponsored by MIUI team (www.miui.com).
It's opened under license described by NOTICE file. It's owned by the MiCode community (www.micode.net). In future,
the MiCode community will release and maintain this project.
2. Regarding issue tracking, please visit Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. Regarding feature request and general discussion, please visit Micode forum,
http://micode.net/forum.php?mod=forumdisplay&fid=38
>>>>>>> e4d75ee (add a)

@ -0,0 +1,22 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 33
buildToolsVersion "25.0.1"
aaptOptions.cruncherEnabled = false
aaptOptions.useNewCruncher = false
useLibrary 'org.apache.http.legacy'
defaultConfig {
applicationId "net.micode.notes"
minSdkVersion 14
targetSdkVersion 33
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
android{ useLibrary 'org.apache.http.legacy' }
}

@ -16,11 +16,13 @@
-->
<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="0.1" >
<uses-sdk android:minSdkVersion="14" />
<uses-sdk android:minSdkVersion="14"
tools:ignore="GradleOverrides" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />

@ -26,9 +26,11 @@ import android.util.Log;
import java.util.HashMap;
public class Contact {
// 声明一个用于缓存联系人的HashMap
private static HashMap<String, String> sContactCache;
// 声明日志输出的TAG
private static final String TAG = "Contact";
// 定义查询联系人的选择条件,使用占位符 "?" 和 "IN" 子句
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
@ -36,24 +38,34 @@ public class Contact {
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
/**
*
* @param context
* @param phoneNumber
* @return null
*/
public static String getContact(Context context, String phoneNumber) {
// 如果联系人缓存为空则创建一个新的HashMap
if(sContactCache == null) {
sContactCache = new HashMap<String, String>();
}
// 如果联系人缓存中已经存在该电话号码的联系人,则直接返回联系人名称
if(sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber);
}
// 使用PhoneNumberUtils工具类将电话号码转换为拨号最小匹配
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
// 查询联系人
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
selection,
new String[] { phoneNumber },
null);
// 如果查询到联系人,则将联系人名称存入缓存并返回联系人名称
if (cursor != null && cursor.moveToFirst()) {
try {
String name = cursor.getString(0);
@ -66,6 +78,7 @@ public class Contact {
cursor.close();
}
} else {
// 如果找不到联系人则打印日志并返回null
Log.d(TAG, "No contact matched with number:" + phoneNumber);
return null;
}

@ -26,22 +26,22 @@ import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
// 数据库帮助类
public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
private static final String DB_NAME = "note.db";// 数据库名
private static final int DB_VERSION = 4;
private static final int DB_VERSION = 4;// 数据库版本号
public interface TABLE {
public interface TABLE {// 数据表名称常量
public static final String NOTE = "note";
public static final String DATA = "data";
}
private static final String TAG = "NotesDatabaseHelper";
private static NotesDatabaseHelper mInstance;
private static final String TAG = "NotesDatabaseHelper";// 日志tag
private static NotesDatabaseHelper mInstance; // 数据库帮助类实例
// 创建笔记数据表的SQL语句
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +
@ -62,7 +62,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";
// 创建笔记内容数据表的SQL语句
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
@ -77,7 +77,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")";
/**
*SQLId
*/
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
@ -85,6 +87,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Increase folder's note count when move note to the folder
*/
/**
*
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
@ -96,6 +101,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Decrease folder's note count when move note from folder
*
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_update " +
@ -109,6 +115,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Increase folder's note count when insert new note to the folder
*
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_insert " +
@ -121,6 +128,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Decrease folder's note count when delete note from the folder
*
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_delete " +
@ -134,6 +142,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Update note's content when insert data with type {@link DataConstants#NOTE}
* {@link DataConstants#NOTE}
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " +
@ -147,6 +156,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Update note's content when data with {@link DataConstants#NOTE} type has changed
* {@link DataConstants#NOTE}
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER update_note_content_on_update " +
@ -160,6 +170,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
* {@link DataConstants#NOTE}
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
"CREATE TRIGGER update_note_content_on_delete " +
@ -173,6 +184,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Delete datas belong to note which has been deleted
*
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
@ -184,6 +196,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Delete notes belong to folder which has been deleted
*
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " +
@ -195,6 +208,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Move notes belong to folder which has been moved to trash folder
*
*/
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
"CREATE TRIGGER folder_move_notes_on_trash " +
@ -205,48 +219,72 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
//数据库帮助
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
//创建数据库实例
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}
/**
*
* @param db
*/
private void reCreateNoteTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
// 删除更新时增加文件夹计数的触发器
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
// 删除更新时减少文件夹计数的触发器
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete");
// 删除删除时减少文件夹计数的触发器
db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete");
// 删除删除时删除数据的触发器
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert");
// 删除插入时增加文件夹计数的触发器
db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete");
// 删除文件夹删除时删除笔记的触发器
db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash");
// 删除将笔记移动到垃圾桶时的触发器
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
// 创建更新时增加文件夹计数的触发器
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
// 创建更新时减少文件夹计数的触发器
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER);
// 创建删除时减少文件夹计数的触发器
db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
// 创建删除时删除数据的触发器
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
// 创建插入时增加文件夹计数的触发器
db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
// 创建文件夹删除时删除笔记的触发器
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
// 创建将笔记移动到垃圾桶时的触发器
}
/**
@param db
*/
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
/**
* call record foler for call notes
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* root folder which is default folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
@ -254,7 +292,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values);
/**
* temporary folder which is used for moving note
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
@ -262,7 +301,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values);
/**
* create trash folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
@ -271,22 +311,22 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
}
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
Log.d(TAG, "data table has been created");
db.execSQL(CREATE_DATA_TABLE_SQL);// 创建数据表
reCreateDataTableTriggers(db);// 重建数据表触发器
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); // 在数据表上创建笔记 ID 索引
Log.d(TAG, "data table has been created"); // 输出日志,表示数据表已创建
}
private void reCreateDataTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");// 如果存在,删除插入时更新笔记内容的触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); // 如果存在,删除更新时更新笔记内容的触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");// 如果存在,删除删除时更新笔记内容的触发器
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); // 创建插入时更新笔记内容的触发器
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); // 创建更新时更新笔记内容的触发器
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); // 创建删除时更新笔记内容的触发器
}
// 如果实例为空,创建新的实例
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
@ -296,40 +336,40 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
createNoteTable(db); // 创建笔记表
createDataTable(db); // 创建数据表
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
boolean skipV2 = false;
boolean reCreateTriggers = false; // 是否需要重新创建触发器
boolean skipV2 = false; // 是否跳过版本 2
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
upgradeToV2(db); // 升级到版本 2
skipV2 = true; // 标记跳过版本 2因为版本 2 升级包含在版本 3 升级中)
oldVersion++; // 版本号加 1
}
if (oldVersion == 2 && !skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
upgradeToV3(db); // 升级到版本 3
reCreateTriggers = true; // 标记需要重新创建触发器
oldVersion++; // 版本号加 1
}
if (oldVersion == 3) {
upgradeToV4(db);
oldVersion++;
upgradeToV4(db); // 升级到版本 4
oldVersion++; // 版本号加 1
}
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
reCreateNoteTableTriggers(db); // 重新创建笔记表触发器
reCreateDataTableTriggers(db); // 重新创建数据表触发器
}
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
+ "fails"); // 如果版本升级失败,抛出异常
}
}

@ -36,12 +36,13 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE;
public class NotesProvider extends ContentProvider {
// 声明一个 UriMatcher 对象,用于匹配 Uri 和对应的代码
private static final UriMatcher mMatcher;
private NotesDatabaseHelper mHelper;
private static final String TAG = "NotesProvider";
// 声明一些常量,用于标识 Uri 匹配的类型
private static final int URI_NOTE = 1;
private static final int URI_NOTE_ITEM = 2;
private static final int URI_DATA = 3;
@ -49,7 +50,7 @@ public class NotesProvider extends ContentProvider {
private static final int URI_SEARCH = 5;
private static final int URI_SEARCH_SUGGEST = 6;
// 初始化 UriMatcher 对象,将 Uri 和对应的类型添加到 UriMatcher 中
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
@ -65,6 +66,9 @@ public class NotesProvider extends ContentProvider {
* x'0A' represents the '\n' character in sqlite. For title and content in the search result,
* we will trim '\n' and white space in order to show more information.
*/
/**
* x'0A' sqlite '\n' '\n'
*/
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","
@ -72,7 +76,9 @@ public class NotesProvider extends ContentProvider {
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
/**
* SQL
*/
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
@ -88,35 +94,49 @@ public class NotesProvider extends ContentProvider {
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// 初始化游标和数据库
Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase();
// 初始化 id
String id = null;
// 根据 Uri 的不同,执行不同的查询操作
switch (mMatcher.match(uri)) {
// 查询所有笔记
case URI_NOTE:
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
break;
// 根据 id 查询笔记
case URI_NOTE_ITEM:
// 获取 Uri 中的 id
id = uri.getPathSegments().get(1);
// 根据 id 查询笔记
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
// 查询所有数据
case URI_DATA:
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
sortOrder);
break;
// 根据 id 查询数据
case URI_DATA_ITEM:
// 获取 Uri 中的 id
id = uri.getPathSegments().get(1);
// 根据 id 查询数据
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
// 查询笔记的搜索结果
case URI_SEARCH:
case URI_SEARCH_SUGGEST:
// 如果查询中包含排序或者 projection则抛出异常
if (sortOrder != null || projection != null) {
throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
}
// 获取查询的关键词
String searchString = null;
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
if (uri.getPathSegments().size() > 1) {
@ -126,21 +146,26 @@ public class NotesProvider extends ContentProvider {
searchString = uri.getQueryParameter("pattern");
}
// 如果关键词为空,则返回空游标
if (TextUtils.isEmpty(searchString)) {
return null;
}
try {
// 格式化查询字符串
searchString = String.format("%%%s%%", searchString);
// 执行笔记搜索查询
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
new String[] { searchString });
new String[]{searchString});
} catch (IllegalStateException ex) {
Log.e(TAG, "got exception: " + ex.toString());
}
break;
// 如果 Uri 不匹配,则抛出异常
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果游标不为空,则设置游标的内容变化通知 Uri
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
@ -149,81 +174,108 @@ public class NotesProvider extends ContentProvider {
@Override
public Uri insert(Uri uri, ContentValues values) {
// 获取可写的 SQLiteDatabase 实例
SQLiteDatabase db = mHelper.getWritableDatabase();
// 定义变量用于存储插入后的数据行 ID
long dataId = 0, noteId = 0, insertedId = 0;
// 根据传入的 Uri 进行不同的插入操作
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 如果是插入 Note 数据表
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
case URI_DATA:
// 如果是插入 Data 数据表
if (values.containsKey(DataColumns.NOTE_ID)) {
// 获取 Note ID
noteId = values.getAsLong(DataColumns.NOTE_ID);
} else {
// 如果 ContentValues 中没有 Note ID记录日志并退出方法
Log.d(TAG, "Wrong data format without note id:" + values.toString());
}
// 插入数据行
insertedId = dataId = db.insert(TABLE.DATA, null, values);
break;
default:
// 如果传入的 Uri 不合法,抛出 IllegalArgumentException 异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
// 如果插入操作成功,通知相关 Uri 的观察者
// 通知 Note Uri
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// Notify the data uri
// 通知 Data Uri
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
// 返回新插入数据的 Uri
return ContentUris.withAppendedId(uri, insertedId);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 初始化变量
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false;
// 使用 switch-case 语句匹配传入的 Uri
switch (mMatcher.match(uri)) {
// 如果是 URI_NOTE表示删除笔记
case URI_NOTE:
// 将选定条件和 "ID>0" 结合起来
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
// 执行删除操作,并返回受影响的行数
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
// 如果是 URI_NOTE_ITEM表示删除单个笔记
case URI_NOTE_ITEM:
// 从 Uri 中获取笔记的 ID
id = uri.getPathSegments().get(1);
/**
* ID that smaller than 0 is system folder which is not allowed to
* trash
*/
// 如果笔记 ID 小于等于 0则不允许删除
long noteId = Long.valueOf(id);
if (noteId <= 0) {
break;
}
// 执行删除操作,并返回受影响的行数
count = db.delete(TABLE.NOTE,
NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break;
// 如果是 URI_DATA表示删除数据
case URI_DATA:
// 执行删除操作,并返回受影响的行数
count = db.delete(TABLE.DATA, selection, selectionArgs);
deleteData = true;
break;
// 如果是 URI_DATA_ITEM表示删除单个数据
case URI_DATA_ITEM:
// 从 Uri 中获取数据的 ID
id = uri.getPathSegments().get(1);
// 执行删除操作,并返回受影响的行数
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
break;
// 如果匹配失败,则抛出异常
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果受影响的行数大于 0
if (count > 0) {
// 如果删除了数据,则通知数据发生了变化
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知 Uri 发生了变化
getContext().getContentResolver().notifyChange(uri, null);
}
// 返回受影响的行数
return count;
}
@ -233,45 +285,61 @@ public class NotesProvider extends ContentProvider {
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false;
// 根据 Uri 进行分支处理
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 更新笔记版本号
increaseNoteVersion(-1, selection, selectionArgs);
// 更新笔记数据
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
// 获取 Uri 中的 id
id = uri.getPathSegments().get(1);
// 更新笔记版本号
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
// 根据 id 更新笔记数据
count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
break;
case URI_DATA:
// 更新数据表
count = db.update(TABLE.DATA, values, selection, selectionArgs);
updateData = true;
break;
case URI_DATA_ITEM:
// 获取 Uri 中的 id
id = uri.getPathSegments().get(1);
// 根据 id 更新数据表
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true;
break;
default:
// 如果不匹配任何 Uri抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果更新成功,发出通知
if (count > 0) {
if (updateData) {
// 更新数据表时,通知笔记 Uri
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知当前 Uri
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
private String parseSelection(String selection) {
// 如果查询条件不为空,返回 AND (查询条件)
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
// 构建 SQL 语句
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
@ -279,13 +347,17 @@ public class NotesProvider extends ContentProvider {
sql.append(NoteColumns.VERSION);
sql.append("=" + NoteColumns.VERSION + "+1 ");
// 如果传入的 ID 或者查询条件不为空,则在 SQL 语句中添加 WHERE 子句
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
}
// 如果传入的 ID 不为空,添加 ID 条件
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
}
// 如果查询条件不为空,添加查询条件
if (!TextUtils.isEmpty(selection)) {
// 解析查询条件中的参数
String selectString = id > 0 ? parseSelection(selection) : selection;
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
@ -293,6 +365,7 @@ public class NotesProvider extends ContentProvider {
sql.append(selectString);
}
// 执行 SQL 语句,增加笔记版本号
mHelper.getWritableDatabase().execSQL(sql.toString());
}

@ -24,31 +24,48 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
/**
MetaDataTaskGTask
*/
public class MetaData extends Task {
private final static String TAG = MetaData.class.getSimpleName();
// 关联的gid
private String mRelatedGid = null;
/**
* gid
*
* @param gid gid
* @param metaInfo
*/
public void setMeta(String gid, JSONObject metaInfo) {
try {
// 将关联的gid放入JSONObject中
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
Log.e(TAG, "failed to put related gid");
}
// 将元数据的相关信息转换为字符串设置为Task的notes
setNotes(metaInfo.toString());
// 设置Task的名称为元数据的名称
setName(GTaskStringUtils.META_NOTE_NAME);
}
public String getRelatedGid() {
return mRelatedGid;
}
/**
*
* @return truefalse
*/
@Override
public boolean isWorthSaving() {
return getNotes() != null;
}
/**
* JSON
* @param js JSON
*/
@Override
public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js);
@ -62,7 +79,10 @@ public class MetaData extends Task {
}
}
}
/**
* JSON
* @param js JSON
*/
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
@ -73,7 +93,8 @@ public class MetaData extends Task {
public JSONObject getLocalJSONFromContent() {
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
}
/* Cursor
IllegalAccessError "MetaData:getSyncAction should not be called" "MetaData:getSyncAction 不应该被调用"*/
@Override
public int getSyncAction(Cursor c) {
throw new IllegalAccessError("MetaData:getSyncAction should not be called");

@ -77,8 +77,9 @@ public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);
}
notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
pendingIntent);
// notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
// pendingIntent);
notification.contentIntent = pendingIntent;
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}

@ -159,6 +159,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return;
}
initResources();
}
/**
@ -430,7 +431,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);
@ -870,4 +871,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();
}
public void OnOpenMenu(View view) {
openOptionsMenu();
}
}

@ -59,7 +59,6 @@ import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
@ -79,6 +78,8 @@ import java.io.InputStreamReader;
import java.util.HashSet;
public class NotesListActivity extends Activity 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;
@ -104,6 +105,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private ListView mNotesListView;
private Button mAddNewNote;
private Button mMenuSet;
private boolean mDispatch;
@ -139,6 +141,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.note_list);
getWindow().setBackgroundDrawableResource(R.drawable.background1);
initResources();
/**
@ -223,6 +226,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mAddNewNote = (Button) findViewById(R.id.btn_new_note);
mAddNewNote.setOnClickListener(this);
mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
mMenuSet = (Button) findViewById(R.id.btn_set);
mDispatch = false;
mDispatchY = 0;
mOriginY = 0;
@ -234,10 +238,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
private DropdownMenu mDropDownMenu;
private ActionMode mActionMode;
private Menu menu;
private MenuItem mMoveMenu;
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
getMenuInflater().inflate(R.menu.note_list_options, menu);
this.menu = menu;
menu.findItem(R.id.delete).setOnMenuItemClickListener(this);
mMoveMenu = menu.findItem(R.id.move);
if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER
@ -251,6 +257,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mNotesListAdapter.setChoiceMode(true);
mNotesListView.setLongClickable(false);
mAddNewNote.setVisibility(View.GONE);
mMenuSet.setVisibility(View.GONE);
View customView = LayoutInflater.from(NotesListActivity.this).inflate(
R.layout.note_list_dropdown_menu, null);
@ -298,13 +305,36 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
public void onDestroyActionMode(ActionMode mode) {
mNotesListAdapter.setChoiceMode(false);
mNotesListView.clearChoices();
mNotesListView.setItemChecked(0,true);
mNotesListView.setItemChecked(0,false);
mNotesListView.setLongClickable(true);
System.out.println("-----------------onDestroyActionMode------------------");
mNotesListAdapter.notifyDataSetChanged();
// closeOptionsMenu();
// mNotesListView.invalidate();
mAddNewNote.setVisibility(View.VISIBLE);
}
mMenuSet.setVisibility(View.VISIBLE);
// mNotesListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
// menu.clear();
// menu.close();
}
public void finishActionMode() {
mActionMode.finish();
mActionMode = null;
mNotesListAdapter.setChoiceMode(false);
mNotesListView.setLongClickable(true);
}
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
boolean checked) {
@ -345,6 +375,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true;
}
}
private class NewNoteOnTouchListener implements OnTouchListener {
@ -546,6 +577,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
mState = ListEditState.CALL_RECORD_FOLDER;
mAddNewNote.setVisibility(View.GONE);
mMenuSet.setVisibility(View.GONE);
} else {
mState = ListEditState.SUB_FOLDER;
}
@ -666,6 +698,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
@Override
public void onBackPressed() {
System.out.println("-------onBackPressed---00000");
switch (mState) {
case SUB_FOLDER:
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
@ -677,10 +711,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
mState = ListEditState.NOTE_LIST;
mAddNewNote.setVisibility(View.VISIBLE);
mMenuSet.setVisibility(View.VISIBLE);
mTitleBar.setVisibility(View.GONE);
startAsyncNotesListQuery();
break;
case NOTE_LIST:
System.out.println("-------onBackPressed---");
super.onBackPressed();
break;
default:
@ -775,12 +811,35 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else {
Log.e(TAG, "Wrong state:" + mState);
}
//当是当前背景图片时,该按键隐藏
if (mode == 1){
menu.findItem(R.id.menu_background1).setVisible(false);
}else if (mode == 0){
menu.findItem(R.id.menu_background2).setVisible(false);
}else if (mode == -1){
menu.findItem(R.id.menu_background3).setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_background1:{
mode = 1;
getWindow().setBackgroundDrawableResource(R.drawable.background1);
break;
}
case R.id.menu_background2:{
mode = 0;
getWindow().setBackgroundDrawableResource(R.drawable.background2);
break;
}
case R.id.menu_background3:{
mode = -1;
getWindow().setBackgroundDrawableResource(R.drawable.background3);
break;
}
case R.id.menu_new_folder: {
showCreateOrModifyFolderDialog(true);
break;
@ -951,4 +1010,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
return false;
}
public void OnOpenMenu(View view) {
openOptionsMenu();
}
}

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

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: 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: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

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.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Before

Width:  |  Height:  |  Size: 554 KiB

After

Width:  |  Height:  |  Size: 554 KiB

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

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

Loading…
Cancel
Save