Compare commits
1 Commits
master
...
diwen_bran
| Author | SHA1 | Date |
|---|---|---|
|
|
87e1516229 | 1 month ago |
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownSettings">
|
||||
<option name="previewPanelProviderInfo">
|
||||
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/MiCode.iml" filepath="$PROJECT_DIR$/MiCode.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,11 @@
|
||||
<?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$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,15 +1,9 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
# generated files
|
||||
bin/
|
||||
gen/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
project.properties
|
||||
.settings/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/MiCode.iml" filepath="$PROJECT_DIR$/MiCode.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,11 @@
|
||||
<?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$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@ -0,0 +1,190 @@
|
||||
|
||||
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/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
@ -1 +0,0 @@
|
||||
/build
|
||||
@ -1,79 +0,0 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "net.micode.notes"
|
||||
|
||||
// 修改这里:匹配你下载的 SDK 30
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "net.micode.notes"
|
||||
minSdk = 30
|
||||
// 修改这里:匹配你下载的 SDK 30
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
// === 这里是新增的代码,用来解决 Jar 包冲突报错 ===
|
||||
packaging {
|
||||
resources {
|
||||
excludes += "META-INF/DEPENDENCIES"
|
||||
excludes += "META-INF/NOTICE"
|
||||
excludes += "META-INF/LICENSE"
|
||||
excludes += "META-INF/LICENSE.txt"
|
||||
excludes += "META-INF/NOTICE.txt"
|
||||
}
|
||||
}
|
||||
// ==============================================
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// === 修改部分:使用兼容 SDK 30 的旧版本库 ===
|
||||
// 替换掉了原本的 libs.appcompat 等引用,改为写死的旧版本号
|
||||
// ViewPager2 用于左右滑动
|
||||
implementation("androidx.recyclerview:recyclerview:1.3.0")
|
||||
implementation("androidx.viewpager2:viewpager2:1.0.0")
|
||||
// Material Design 用于底部导航栏
|
||||
implementation("com.google.android.material:material:1.9.0")
|
||||
// Fragment 核心库 (确保使用 AndroidX 版本)
|
||||
implementation("androidx.fragment:fragment:1.5.7")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.appcompat:appcompat:1.3.1")
|
||||
implementation("com.google.android.material:material:1.4.0")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.drawerlayout:drawerlayout:1.2.0")
|
||||
implementation("androidx.coordinatorlayout:coordinatorlayout:1.2.0")
|
||||
|
||||
// 如果你需要 Activity 的新特性,也需要指定旧版本,否则默认会拉取最新的导致报错
|
||||
implementation("androidx.activity:activity:1.2.4")
|
||||
|
||||
// Google Play Services - 用于地理围栏
|
||||
implementation("com.google.android.gms:play-services-location:21.0.1")
|
||||
|
||||
// === 保持不变:你的 Jar 包路径 ===
|
||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
|
||||
|
||||
// === 测试库也建议指定旧版本,防止冲突 ===
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.3")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@ -1,26 +0,0 @@
|
||||
package net.micode.notes;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("net.micode.notes", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@ -1,422 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.micode.notes.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
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;
|
||||
|
||||
|
||||
public class NotesDatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final String DB_NAME = "note.db";
|
||||
|
||||
private static final int DB_VERSION = 7;
|
||||
|
||||
public interface TABLE {
|
||||
public static final String NOTE = "note";
|
||||
public static final String DATA = "data";
|
||||
public static final String TODO_ITEMS = "todo_items";
|
||||
}
|
||||
|
||||
private static final String TAG = "NotesDatabaseHelper";
|
||||
|
||||
private static NotesDatabaseHelper mInstance;
|
||||
|
||||
private static final String CREATE_NOTE_TABLE_SQL =
|
||||
"CREATE TABLE " + TABLE.NOTE + "(" +
|
||||
NoteColumns.ID + " INTEGER PRIMARY KEY," +
|
||||
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
||||
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
||||
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
|
||||
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
|
||||
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
|
||||
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.PINNED + " INTEGER NOT NULL DEFAULT 0" +
|
||||
")";
|
||||
|
||||
private static final String CREATE_DATA_TABLE_SQL =
|
||||
"CREATE TABLE " + TABLE.DATA + "(" +
|
||||
DataColumns.ID + " INTEGER PRIMARY KEY," +
|
||||
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
|
||||
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
|
||||
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
||||
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
||||
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
|
||||
DataColumns.DATA1 + " INTEGER," +
|
||||
DataColumns.DATA2 + " INTEGER," +
|
||||
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
|
||||
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
|
||||
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
|
||||
")";
|
||||
|
||||
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
|
||||
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
|
||||
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
|
||||
|
||||
private static final String CREATE_TODO_ITEMS_TABLE_SQL =
|
||||
"CREATE TABLE " + TABLE.TODO_ITEMS + "(" +
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||
"content TEXT NOT NULL DEFAULT ''," +
|
||||
"is_done INTEGER NOT NULL DEFAULT 0," +
|
||||
"reminder_type INTEGER NOT NULL DEFAULT 0," +
|
||||
"reminder_timestamp INTEGER NOT NULL DEFAULT 0," +
|
||||
"latitude REAL NOT NULL DEFAULT 0," +
|
||||
"longitude REAL NOT NULL DEFAULT 0," +
|
||||
"location_name TEXT NOT NULL DEFAULT ''," +
|
||||
"created_time INTEGER NOT NULL DEFAULT 0" +
|
||||
")";
|
||||
|
||||
/**
|
||||
* 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 +
|
||||
" BEGIN " +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
|
||||
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* 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 " +
|
||||
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
|
||||
" BEGIN " +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
|
||||
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
|
||||
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* 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 " +
|
||||
" AFTER INSERT ON " + TABLE.NOTE +
|
||||
" BEGIN " +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
|
||||
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* 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 " +
|
||||
" AFTER DELETE ON " + TABLE.NOTE +
|
||||
" BEGIN " +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
|
||||
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
|
||||
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* Update note's content when insert data with type {@link DataConstants#NOTE}
|
||||
*/
|
||||
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
|
||||
"CREATE TRIGGER update_note_content_on_insert " +
|
||||
" AFTER INSERT ON " + TABLE.DATA +
|
||||
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
|
||||
" BEGIN" +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
|
||||
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* Update note's content when data with {@link DataConstants#NOTE} type has changed
|
||||
*/
|
||||
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
|
||||
"CREATE TRIGGER update_note_content_on_update " +
|
||||
" AFTER UPDATE ON " + TABLE.DATA +
|
||||
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
|
||||
" BEGIN" +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
|
||||
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
|
||||
*/
|
||||
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
|
||||
"CREATE TRIGGER update_note_content_on_delete " +
|
||||
" AFTER delete ON " + TABLE.DATA +
|
||||
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
|
||||
" BEGIN" +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.SNIPPET + "=''" +
|
||||
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* 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 " +
|
||||
" AFTER DELETE ON " + TABLE.NOTE +
|
||||
" BEGIN" +
|
||||
" DELETE FROM " + TABLE.DATA +
|
||||
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* 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 " +
|
||||
" AFTER DELETE ON " + TABLE.NOTE +
|
||||
" BEGIN" +
|
||||
" DELETE FROM " + TABLE.NOTE +
|
||||
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
|
||||
" END";
|
||||
|
||||
/**
|
||||
* 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 " +
|
||||
" AFTER UPDATE ON " + TABLE.NOTE +
|
||||
" WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
|
||||
" BEGIN" +
|
||||
" UPDATE " + TABLE.NOTE +
|
||||
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
|
||||
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
|
||||
" END";
|
||||
|
||||
public NotesDatabaseHelper(Context context) {
|
||||
super(context, DB_NAME, null, DB_VERSION);
|
||||
}
|
||||
|
||||
public void createNoteTable(SQLiteDatabase db) {
|
||||
db.execSQL(CREATE_NOTE_TABLE_SQL);
|
||||
reCreateNoteTableTriggers(db);
|
||||
createSystemFolder(db);
|
||||
Log.d(TAG, "note table has been created");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
|
||||
db.insert(TABLE.NOTE, null, values);
|
||||
|
||||
/**
|
||||
* temporary folder which is used for moving note
|
||||
*/
|
||||
values.clear();
|
||||
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
|
||||
db.insert(TABLE.NOTE, null, values);
|
||||
|
||||
/**
|
||||
* create trash folder
|
||||
*/
|
||||
values.clear();
|
||||
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
|
||||
db.insert(TABLE.NOTE, null, values);
|
||||
|
||||
/**
|
||||
* create privacy space folder (hidden, only visible when user enters via Mi Steward)
|
||||
*/
|
||||
values.clear();
|
||||
values.put(NoteColumns.ID, Notes.ID_PRIVACY_FOLDER);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
|
||||
db.insert(TABLE.NOTE, null, values);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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(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);
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
createNoteTable(db);
|
||||
createDataTable(db);
|
||||
createTodoTable(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
boolean reCreateTriggers = false;
|
||||
boolean skipV2 = false;
|
||||
|
||||
if (oldVersion == 1) {
|
||||
upgradeToV2(db);
|
||||
skipV2 = true; // this upgrade including the upgrade from v2 to v3
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (oldVersion == 2 && !skipV2) {
|
||||
upgradeToV3(db);
|
||||
reCreateTriggers = true;
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (oldVersion == 3) {
|
||||
upgradeToV4(db);
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (oldVersion == 4) {
|
||||
upgradeToV5(db);
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (oldVersion == 5) {
|
||||
upgradeToV6(db);
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (oldVersion == 6) {
|
||||
upgradeToV7(db);
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (reCreateTriggers) {
|
||||
reCreateNoteTableTriggers(db);
|
||||
reCreateDataTableTriggers(db);
|
||||
}
|
||||
|
||||
if (oldVersion != newVersion) {
|
||||
throw new IllegalStateException("Upgrade notes database to version " + newVersion
|
||||
+ "fails");
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeToV2(SQLiteDatabase db) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
|
||||
createNoteTable(db);
|
||||
createDataTable(db);
|
||||
}
|
||||
|
||||
private void upgradeToV3(SQLiteDatabase db) {
|
||||
// drop unused triggers
|
||||
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
|
||||
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
|
||||
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
|
||||
// add a column for gtask id
|
||||
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
|
||||
+ " TEXT NOT NULL DEFAULT ''");
|
||||
// add a trash system folder
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
|
||||
db.insert(TABLE.NOTE, null, values);
|
||||
}
|
||||
|
||||
private void upgradeToV4(SQLiteDatabase db) {
|
||||
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
|
||||
+ " INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
|
||||
private void upgradeToV5(SQLiteDatabase db) {
|
||||
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.PINNED
|
||||
+ " INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
|
||||
private void upgradeToV6(SQLiteDatabase db) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NoteColumns.ID, Notes.ID_PRIVACY_FOLDER);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
|
||||
db.insert(TABLE.NOTE, null, values);
|
||||
}
|
||||
|
||||
private void upgradeToV7(SQLiteDatabase db) {
|
||||
db.execSQL(CREATE_TODO_ITEMS_TABLE_SQL);
|
||||
Log.d(TAG, "todo_items table has been created");
|
||||
}
|
||||
|
||||
public void createTodoTable(SQLiteDatabase db) {
|
||||
db.execSQL(CREATE_TODO_ITEMS_TABLE_SQL);
|
||||
Log.d(TAG, "todo_items table has been created");
|
||||
}
|
||||
}
|
||||
@ -1,153 +0,0 @@
|
||||
package net.micode.notes.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.util.Log;
|
||||
|
||||
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
|
||||
import net.micode.notes.todo.TodoItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 待办事项数据访问层 (CRUD)
|
||||
*/
|
||||
public class TodoDao {
|
||||
private static final String TAG = "TodoDao";
|
||||
|
||||
private static final String COL_ID = "id";
|
||||
private static final String COL_CONTENT = "content";
|
||||
private static final String COL_IS_DONE = "is_done";
|
||||
private static final String COL_REMINDER_TYPE = "reminder_type";
|
||||
private static final String COL_REMINDER_TIMESTAMP = "reminder_timestamp";
|
||||
private static final String COL_LATITUDE = "latitude";
|
||||
private static final String COL_LONGITUDE = "longitude";
|
||||
private static final String COL_LOCATION_NAME = "location_name";
|
||||
private static final String COL_CREATED_TIME = "created_time";
|
||||
|
||||
private final NotesDatabaseHelper mHelper;
|
||||
|
||||
public TodoDao(Context context) {
|
||||
mHelper = NotesDatabaseHelper.getInstance(context);
|
||||
}
|
||||
|
||||
public long insert(TodoItem item) {
|
||||
SQLiteDatabase db = mHelper.getWritableDatabase();
|
||||
ContentValues cv = toContentValues(item);
|
||||
long id = db.insert(TABLE.TODO_ITEMS, null, cv);
|
||||
Log.d(TAG, "insert todo id=" + id);
|
||||
return id;
|
||||
}
|
||||
|
||||
public int update(TodoItem item) {
|
||||
if (item.getId() <= 0) return 0;
|
||||
SQLiteDatabase db = mHelper.getWritableDatabase();
|
||||
ContentValues cv = toContentValues(item);
|
||||
return db.update(TABLE.TODO_ITEMS, cv, COL_ID + "=?", new String[]{String.valueOf(item.getId())});
|
||||
}
|
||||
|
||||
public int delete(long id) {
|
||||
SQLiteDatabase db = mHelper.getWritableDatabase();
|
||||
return db.delete(TABLE.TODO_ITEMS, COL_ID + "=?", new String[]{String.valueOf(id)});
|
||||
}
|
||||
|
||||
public int deleteByIds(List<Long> ids) {
|
||||
if (ids == null || ids.isEmpty()) return 0;
|
||||
SQLiteDatabase db = mHelper.getWritableDatabase();
|
||||
StringBuilder sb = new StringBuilder(COL_ID).append(" IN (");
|
||||
for (int i = 0; i < ids.size(); i++) {
|
||||
sb.append(i > 0 ? "," : "").append(ids.get(i));
|
||||
}
|
||||
sb.append(")");
|
||||
return db.delete(TABLE.TODO_ITEMS, sb.toString(), null);
|
||||
}
|
||||
|
||||
public TodoItem getById(long id) {
|
||||
SQLiteDatabase db = mHelper.getReadableDatabase();
|
||||
try (Cursor c = db.query(TABLE.TODO_ITEMS, null, COL_ID + "=?", new String[]{String.valueOf(id)}, null, null, null)) {
|
||||
if (c != null && c.moveToFirst()) {
|
||||
return fromCursor(c);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<TodoItem> getAll() {
|
||||
List<TodoItem> list = new ArrayList<>();
|
||||
SQLiteDatabase db = mHelper.getReadableDatabase();
|
||||
try (Cursor c = db.query(TABLE.TODO_ITEMS, null, null, null, null, null, COL_IS_DONE + " ASC, " + COL_CREATED_TIME + " DESC")) {
|
||||
if (c != null) {
|
||||
while (c.moveToNext()) {
|
||||
list.add(fromCursor(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<TodoItem> getUndone() {
|
||||
List<TodoItem> list = new ArrayList<>();
|
||||
SQLiteDatabase db = mHelper.getReadableDatabase();
|
||||
try (Cursor c = db.query(TABLE.TODO_ITEMS, null, COL_IS_DONE + "=0", null, null, null, COL_CREATED_TIME + " DESC")) {
|
||||
if (c != null) {
|
||||
while (c.moveToNext()) {
|
||||
list.add(fromCursor(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<TodoItem> getDone() {
|
||||
List<TodoItem> list = new ArrayList<>();
|
||||
SQLiteDatabase db = mHelper.getReadableDatabase();
|
||||
try (Cursor c = db.query(TABLE.TODO_ITEMS, null, COL_IS_DONE + "=1", null, null, null, COL_CREATED_TIME + " DESC")) {
|
||||
if (c != null) {
|
||||
while (c.moveToNext()) {
|
||||
list.add(fromCursor(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public int getUndoneCount() {
|
||||
SQLiteDatabase db = mHelper.getReadableDatabase();
|
||||
try (Cursor c = db.rawQuery("SELECT COUNT(*) FROM " + TABLE.TODO_ITEMS + " WHERE " + COL_IS_DONE + "=0", null)) {
|
||||
if (c != null && c.moveToFirst()) {
|
||||
return c.getInt(0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private ContentValues toContentValues(TodoItem item) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(COL_CONTENT, item.getContent());
|
||||
cv.put(COL_IS_DONE, item.isDone() ? 1 : 0);
|
||||
cv.put(COL_REMINDER_TYPE, item.getReminderType());
|
||||
cv.put(COL_REMINDER_TIMESTAMP, item.getReminderTimestamp());
|
||||
cv.put(COL_LATITUDE, item.getLatitude());
|
||||
cv.put(COL_LONGITUDE, item.getLongitude());
|
||||
cv.put(COL_LOCATION_NAME, item.getLocationName());
|
||||
cv.put(COL_CREATED_TIME, item.getCreatedTime());
|
||||
return cv;
|
||||
}
|
||||
|
||||
private TodoItem fromCursor(Cursor c) {
|
||||
TodoItem item = new TodoItem();
|
||||
item.setId(c.getLong(c.getColumnIndexOrThrow(COL_ID)));
|
||||
item.setContent(c.getString(c.getColumnIndexOrThrow(COL_CONTENT)));
|
||||
item.setDone(c.getInt(c.getColumnIndexOrThrow(COL_IS_DONE)) == 1);
|
||||
item.setReminderType(c.getInt(c.getColumnIndexOrThrow(COL_REMINDER_TYPE)));
|
||||
item.setReminderTimestamp(c.getLong(c.getColumnIndexOrThrow(COL_REMINDER_TIMESTAMP)));
|
||||
item.setLatitude(c.getDouble(c.getColumnIndexOrThrow(COL_LATITUDE)));
|
||||
item.setLongitude(c.getDouble(c.getColumnIndexOrThrow(COL_LONGITUDE)));
|
||||
item.setLocationName(c.getString(c.getColumnIndexOrThrow(COL_LOCATION_NAME)));
|
||||
item.setCreatedTime(c.getLong(c.getColumnIndexOrThrow(COL_CREATED_TIME)));
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
package net.micode.notes.todo;
|
||||
|
||||
/**
|
||||
* 待办事项实体类
|
||||
*/
|
||||
public class TodoItem {
|
||||
/** 提醒类型:无 */
|
||||
public static final int REMINDER_NONE = 0;
|
||||
/** 提醒类型:时间 */
|
||||
public static final int REMINDER_TIME = 1;
|
||||
/** 提醒类型:地点 */
|
||||
public static final int REMINDER_LOCATION = 2;
|
||||
|
||||
private long id;
|
||||
private String content;
|
||||
private boolean isDone;
|
||||
private int reminderType;
|
||||
private long reminderTimestamp;
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
private String locationName;
|
||||
private long createdTime;
|
||||
|
||||
public TodoItem() {
|
||||
this.id = 0;
|
||||
this.content = "";
|
||||
this.isDone = false;
|
||||
this.reminderType = REMINDER_NONE;
|
||||
this.reminderTimestamp = 0;
|
||||
this.latitude = 0;
|
||||
this.longitude = 0;
|
||||
this.locationName = "";
|
||||
this.createdTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public long getId() { return id; }
|
||||
public void setId(long id) { this.id = id; }
|
||||
|
||||
public String getContent() { return content; }
|
||||
public void setContent(String content) { this.content = content != null ? content : ""; }
|
||||
|
||||
public boolean isDone() { return isDone; }
|
||||
public void setDone(boolean done) { isDone = done; }
|
||||
|
||||
public int getReminderType() { return reminderType; }
|
||||
public void setReminderType(int reminderType) { this.reminderType = reminderType; }
|
||||
|
||||
public long getReminderTimestamp() { return reminderTimestamp; }
|
||||
public void setReminderTimestamp(long reminderTimestamp) { this.reminderTimestamp = reminderTimestamp; }
|
||||
|
||||
public double getLatitude() { return latitude; }
|
||||
public void setLatitude(double latitude) { this.latitude = latitude; }
|
||||
|
||||
public double getLongitude() { return longitude; }
|
||||
public void setLongitude(double longitude) { this.longitude = longitude; }
|
||||
|
||||
public String getLocationName() { return locationName; }
|
||||
public void setLocationName(String locationName) { this.locationName = locationName != null ? locationName : ""; }
|
||||
|
||||
public long getCreatedTime() { return createdTime; }
|
||||
public void setCreatedTime(long createdTime) { this.createdTime = createdTime; }
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class AlarmReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
intent.setClass(context, AlarmAlertActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
@ -1,142 +0,0 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.media.projection.MediaProjectionManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Switch;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
import net.micode.notes.tool.FloatingService;
|
||||
|
||||
public class InspirationFragment extends Fragment {
|
||||
|
||||
private ListView mListView;
|
||||
private NotesListAdapter mAdapter;
|
||||
private BackgroundQueryHandler mQueryHandler;
|
||||
private Switch mSwitchFloating;
|
||||
|
||||
private static final int QUERY_TOKEN = 202;
|
||||
private static final int REQUEST_CODE_OVERLAY_PERMISSION = 1001;
|
||||
private static final int REQUEST_CODE_SCREEN_CAPTURE = 1002;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_inspiration, container, false);
|
||||
initViews(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
private void initViews(View view) {
|
||||
mListView = view.findViewById(R.id.inspiration_list);
|
||||
mSwitchFloating = view.findViewById(R.id.switch_floating_ball);
|
||||
|
||||
mAdapter = new NotesListAdapter(getActivity());
|
||||
mListView.setAdapter(mAdapter);
|
||||
mQueryHandler = new BackgroundQueryHandler(getActivity().getContentResolver());
|
||||
mListView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(android.widget.AdapterView<?> parent, View view, int position, long id) {
|
||||
// 跳转到编辑页 (复用 NoteEditActivity)
|
||||
Intent intent = new Intent(getActivity(), NoteEditActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(Intent.EXTRA_UID, id); // 传入便签 ID
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
mSwitchFloating.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
checkAndStartService();
|
||||
} else {
|
||||
stopFloatingService();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkAndStartService() {
|
||||
// 1. 检查悬浮窗权限
|
||||
if (!Settings.canDrawOverlays(getContext())) {
|
||||
Toast.makeText(getActivity(), "请授予悬浮窗权限", Toast.LENGTH_SHORT).show();
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||
Uri.parse("package:" + getActivity().getPackageName()));
|
||||
startActivityForResult(intent, REQUEST_CODE_OVERLAY_PERMISSION);
|
||||
mSwitchFloating.setChecked(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 申请截屏权限
|
||||
MediaProjectionManager mm = (MediaProjectionManager) getActivity().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
|
||||
startActivityForResult(mm.createScreenCaptureIntent(), REQUEST_CODE_SCREEN_CAPTURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQUEST_CODE_OVERLAY_PERMISSION) {
|
||||
if (Settings.canDrawOverlays(getContext())) {
|
||||
checkAndStartService();
|
||||
}
|
||||
} else if (requestCode == REQUEST_CODE_SCREEN_CAPTURE) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
startFloatingService(resultCode, data);
|
||||
} else {
|
||||
mSwitchFloating.setChecked(false);
|
||||
Toast.makeText(getActivity(), "未授权截屏,无法开启", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startFloatingService(int resultCode, Intent data) {
|
||||
Intent intent = new Intent(getActivity(), FloatingService.class);
|
||||
intent.putExtra("resultCode", resultCode);
|
||||
intent.putExtra("data", data);
|
||||
getActivity().startForegroundService(intent);
|
||||
}
|
||||
|
||||
private void stopFloatingService() {
|
||||
Intent intent = new Intent(getActivity(), FloatingService.class);
|
||||
getActivity().stopService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
refreshList();
|
||||
}
|
||||
|
||||
private void refreshList() {
|
||||
String selection = NoteColumns.PARENT_ID + "=?";
|
||||
String[] selectionArgs = { String.valueOf(Notes.ID_INSPIRATION_FOLDER) };
|
||||
mQueryHandler.startQuery(QUERY_TOKEN, null, Notes.CONTENT_NOTE_URI,
|
||||
NoteItemData.PROJECTION, selection, selectionArgs, NoteColumns.MODIFIED_DATE + " DESC");
|
||||
}
|
||||
|
||||
private final class BackgroundQueryHandler extends AsyncQueryHandler {
|
||||
public BackgroundQueryHandler(ContentResolver cr) { super(cr); }
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
if (token == QUERY_TOKEN) mAdapter.changeCursor(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/bottom_nav_selected" android:state_checked="true" />
|
||||
<item android:color="@color/bottom_nav_unselected" />
|
||||
</selector>
|
||||
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<solid android:color="#CC3370FF"/> <!-- 半透明蓝色 (CC是透明度) -->
|
||||
<stroke android:width="1dp" android:color="#FFFFFF"/> <!-- 白色描边 -->
|
||||
</shape>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#5C5C5C"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
</vector>
|
||||
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 退出图标,用于退出隐私空间 -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#5C5C5C"
|
||||
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#5C5C5C"
|
||||
android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#1D1D1D"
|
||||
android:pathData="M3,18h18v-2H3v2zM3,13h18v-2H3v2zM3,6v2h18V6H3z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#5C5C5C"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#5C5C5C"
|
||||
android:pathData="M19.14,12.94c0.04,-0.31 0.06,-0.63 0.06,-0.94c0,-0.31 -0.02,-0.63 -0.06,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.31 4.8,11.63 4.8,12s0.02,0.69 0.06,1.06l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#5C5C5C"
|
||||
android:pathData="M12,4V1L8,5l4,4V6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
|
||||
</vector>
|
||||
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#60FFFFFF" />
|
||||
<corners android:radius="1dp" />
|
||||
</shape>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="160"
|
||||
android:startColor="#0D0D0D"
|
||||
android:centerColor="#151520"
|
||||
android:endColor="#0D0D0D"
|
||||
android:type="linear" />
|
||||
</shape>
|
||||
@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:background="@color/surface_white">
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/main_content_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/surface_white">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/divider_light" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottom_navigation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/surface_white"
|
||||
app:itemIconTint="@color/bottom_nav_color"
|
||||
app:itemTextColor="@color/bottom_nav_color"
|
||||
app:labelVisibilityMode="labeled"
|
||||
app:menu="@menu/bottom_nav_menu" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 侧边栏 -->
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true"
|
||||
android:background="@color/surface_white"
|
||||
app:headerLayout="@layout/drawer_header"
|
||||
app:itemIconTint="@color/drawer_icon_tint"
|
||||
app:itemTextColor="@color/drawer_text_primary"
|
||||
app:menu="@menu/drawer_menu" />
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_light"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_todo_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minLines="3"
|
||||
android:gravity="top"
|
||||
android:hint="@string/todo_hint_content"
|
||||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:background="@android:drawable/editbox_background"
|
||||
android:padding="12dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_add_reminder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/todo_add_reminder" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_reminder_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/todo_save" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingTop="32dp"
|
||||
android:paddingBottom="24dp"
|
||||
android:background="@color/surface_white">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="简约 · 高效"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
</LinearLayout>
|
||||
@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#FFFFFF">
|
||||
|
||||
<!-- 顶部控制区 -->
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:background="#F5F6F7"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:elevation="2dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="💡 灵感箱"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#333333"/>
|
||||
|
||||
<!-- 悬浮球开关 -->
|
||||
<Switch
|
||||
android:id="@+id/switch_floating_ball"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="开启桌面悬浮球 "
|
||||
android:textSize="14sp"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- 灵感便签列表 -->
|
||||
<!-- 复用已有的 List View 逻辑 -->
|
||||
<ListView
|
||||
android:id="@+id/inspiration_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
@ -1,122 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_light">
|
||||
|
||||
<!-- 顶部标题栏 -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/top_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@color/surface_white"
|
||||
android:elevation="2dp">
|
||||
|
||||
<!-- 左侧:新对话按钮 -->
|
||||
<ImageView
|
||||
android:id="@+id/btn_new_chat"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:padding="8dp"
|
||||
android:src="@android:drawable/ic_menu_rotate" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:text="Mi 管家"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<!-- 右侧:灵感球 Switch -->
|
||||
<Switch
|
||||
android:id="@+id/switch_steward_floating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="灵感球"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- 中间的 Logo 区域 (初始显示) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/center_logo_area"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
<ImageView
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:src="@android:drawable/sym_def_app_icon"/> <!-- 可替换为自定义Logo -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="你的私人管家"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 聊天列表 (初始隐藏) -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/top_bar"
|
||||
android:layout_above="@id/bottom_input_area"
|
||||
android:visibility="gone"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="10dp"/>
|
||||
|
||||
<!-- 底部输入区域 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_input_area"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:padding="12dp"
|
||||
android:background="@color/surface_white"
|
||||
android:orientation="vertical">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cb_use_knowledge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="使用知识库"
|
||||
android:checked="true"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_secondary"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:drawable/editbox_background"
|
||||
android:hint="问点什么..."
|
||||
android:padding="10dp"
|
||||
android:minHeight="48dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_send"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="发送"
|
||||
android:layout_marginLeft="8dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_light">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/surface_white"
|
||||
android:elevation="2dp">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_todo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/todo_title" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_todo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="80dp" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_todo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="24dp"
|
||||
app:srcCompat="@drawable/ic_add_24dp"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
<net.micode.notes.todo.ConfettiView
|
||||
android:id="@+id/confetti_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="#40000000" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@ -1,82 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- AI 头像 -->
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:src="@android:drawable/sym_def_app_icon"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginTop="2dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 思考状态 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_thinking"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:visibility="visible">
|
||||
<ProgressBar
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
style="?android:attr/progressBarStyleSmall"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=" 深度思考中..."
|
||||
android:textSize="12sp"
|
||||
android:textColor="#999999"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 正文内容 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_ai_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="这是AI回复的内容"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<!-- 参考资料区域 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_references"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="#F0F0F0"
|
||||
android:padding="8dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="参考便签:"
|
||||
android:textSize="10sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_reference_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="1. 工作安排\n2. 会议纪要"
|
||||
android:textSize="12sp"
|
||||
android:textColor="#3370FF"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_user_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="40dp"
|
||||
android:text="帮我查一下明天的日程"
|
||||
android:textColor="#000000"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:minHeight="56dp"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cb_todo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_todo_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="3"
|
||||
android:lineSpacingExtra="2dp" />
|
||||
</LinearLayout>
|
||||
@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/background_light">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"
|
||||
android:background="@color/divider_light" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_section_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- 悬浮球主体:圆形背景 + 图标 -->
|
||||
<ImageView
|
||||
android:id="@+id/iv_floating_ball"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:src="@android:drawable/ic_menu_edit"
|
||||
android:background="@drawable/bg_floating_ball"
|
||||
android:padding="12dp"
|
||||
android:contentDescription="灵感球"
|
||||
android:elevation="6dp"/>
|
||||
<!-- elevation 提供阴影效果 -->
|
||||
|
||||
</FrameLayout>
|
||||
@ -1,43 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#99000000"> <!-- 半透明黑背景 -->
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:background="@android:drawable/dialog_holo_light_frame"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="捕捉灵感"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_inspiration"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="输入此刻的想法..."
|
||||
android:minLines="2"
|
||||
android:gravity="top"
|
||||
android:background="@android:drawable/edit_text">
|
||||
<!-- 标准的自动聚焦写法 -->
|
||||
<requestFocus />
|
||||
</EditText>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_send_inspiration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="存入灵感箱"/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
@ -1,108 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_light"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 顶栏:菜单按钮 + 标题 -->
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_notes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/surface_white"
|
||||
android:elevation="0dp"
|
||||
app:navigationIcon="@drawable/ic_menu_24dp"
|
||||
app:title="@string/notes_tab_title"
|
||||
app:titleTextColor="@color/text_primary"
|
||||
app:titleTextAppearance="@style/ToolbarTitleTextAppearance" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/divider_light" />
|
||||
|
||||
<!-- 子文件夹时显示的标题栏(与原有逻辑兼容) -->
|
||||
<TextView
|
||||
android:id="@+id/tv_title_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:background="@color/surface_white"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/notes_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:cacheColorHint="@android:color/transparent"
|
||||
android:listSelector="@android:color/transparent"
|
||||
android:divider="@color/divider_light"
|
||||
android:dividerHeight="1dp"
|
||||
android:background="@color/background_light"
|
||||
android:fadingEdge="none"
|
||||
android:scrollbars="none" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 右下角:返回上一级(仅子文件夹内显示)+ 新建便签 + 退出隐私空间(仅隐私模式下显示) -->
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/btn_fab_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="84dp"
|
||||
android:layout_marginBottom="88dp"
|
||||
android:contentDescription="@string/fab_back_to_list"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_arrow_back_24dp"
|
||||
app:backgroundTint="@color/text_secondary"
|
||||
app:tint="@color/surface_white"
|
||||
app:elevation="6dp"
|
||||
app:fabSize="normal"
|
||||
app:maxImageSize="24dp" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/btn_fab_exit_privacy"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="84dp"
|
||||
android:layout_marginBottom="88dp"
|
||||
android:contentDescription="@string/privacy_space_exit"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_exit_privacy_24dp"
|
||||
app:backgroundTint="@color/text_secondary"
|
||||
app:tint="@color/surface_white"
|
||||
app:elevation="6dp"
|
||||
app:fabSize="normal"
|
||||
app:maxImageSize="24dp" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/btn_fab_new_note"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginBottom="88dp"
|
||||
android:contentDescription="@string/notelist_menu_new"
|
||||
app:srcCompat="@drawable/ic_add_24dp"
|
||||
app:backgroundTint="@color/accent_primary"
|
||||
app:tint="@color/surface_white"
|
||||
app:elevation="6dp"
|
||||
app:fabSize="normal"
|
||||
app:maxImageSize="24dp" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/nav_mi_steward"
|
||||
android:icon="@android:drawable/ic_dialog_info"
|
||||
android:title="@string/nav_mi_steward" />
|
||||
<item
|
||||
android:id="@+id/nav_notes"
|
||||
android:icon="@android:drawable/ic_menu_edit"
|
||||
android:title="@string/nav_notes" />
|
||||
<item
|
||||
android:id="@+id/nav_todo"
|
||||
android:icon="@android:drawable/ic_menu_agenda"
|
||||
android:title="@string/nav_todo" />
|
||||
</menu>
|
||||
@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/drawer_new_note"
|
||||
android:icon="@drawable/ic_edit_note_24dp"
|
||||
android:title="@string/notelist_menu_new" />
|
||||
<item
|
||||
android:id="@+id/drawer_new_folder"
|
||||
android:icon="@drawable/ic_folder_24dp"
|
||||
android:title="@string/menu_create_folder" />
|
||||
<item
|
||||
android:id="@+id/drawer_export"
|
||||
android:icon="@drawable/ic_export_24dp"
|
||||
android:title="@string/menu_export_text" />
|
||||
</menu>
|
||||
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/menu_new_note"
|
||||
android:title="@string/notelist_menu_new"/>
|
||||
<item
|
||||
android:id="@+id/menu_setting"
|
||||
android:title="@string/menu_setting"/>
|
||||
</menu>
|
||||
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:title="@string/todo_delete"
|
||||
android:icon="@drawable/menu_delete"
|
||||
android:showAsAction="always|withText" />
|
||||
</menu>
|
||||
@ -1,43 +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>
|
||||
<color name="user_query_highlight">#335b5b5b</color>
|
||||
<!-- 置顶条加深色:与便签五色对应,用于列表项左侧标识置顶 -->
|
||||
<color name="note_pinned_bar_yellow">#CCB8860B</color>
|
||||
<color name="note_pinned_bar_blue">#CC1565C0</color>
|
||||
<color name="note_pinned_bar_white">#CC616161</color>
|
||||
<color name="note_pinned_bar_green">#CC2E7D32</color>
|
||||
<color name="note_pinned_bar_red">#CCC62828</color>
|
||||
|
||||
<!-- 简约白主题 -->
|
||||
<color name="surface_white">#FFFFFF</color>
|
||||
<color name="background_light">#F7F8FA</color>
|
||||
<color name="divider_light">#EFF1F3</color>
|
||||
<color name="text_primary">#1D1D1D</color>
|
||||
<color name="text_secondary">#657786</color>
|
||||
<color name="accent_primary">#1DA1F2</color>
|
||||
<color name="accent_primary_dark">#1A91DA</color>
|
||||
<!-- 底部导航与侧边栏 -->
|
||||
<color name="bottom_nav_unselected">#657786</color>
|
||||
<color name="bottom_nav_selected">#1DA1F2</color>
|
||||
<color name="drawer_icon_tint">#657786</color>
|
||||
<color name="drawer_text_primary">#1D1D1D</color>
|
||||
|
||||
<!-- 隐私空间:整体变暗背景 -->
|
||||
<color name="privacy_space_background">#FF1C1C1E</color>
|
||||
</resources>
|
||||
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 代表 Context.getExternalFilesDir() 下的子目录,供 FileProvider 生成 content:// URI -->
|
||||
<external-files-path name="my_images" path="images/" />
|
||||
<!-- 相机拍摄照片保存在 getExternalFilesDir(Environment.DIRECTORY_PICTURES) 即 files/Pictures/ -->
|
||||
<external-files-path name="my_pictures" path="Pictures/" />
|
||||
</paths>
|
||||
@ -1,17 +0,0 @@
|
||||
package net.micode.notes;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue