Initial commit: Favorites - Android bookmark navigator

This commit is contained in:
personal82555 committed 2026-06-15 23:38:00 +08:00
commit 461778d763
33 files changed
+2050

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.hermes.app"
compileSdk = 35
defaultConfig {
applicationId = "com.hermes.app"
minSdk = 24
targetSdk = 35
versionCode = 46
versionName = "1.0.46"
}
signingConfigs {
create("release") {
storeFile = rootProject.file("hermes.keystore")
storePassword = "hermes123"
keyAlias = "hermes"
keyPassword = "hermes123"
}
}
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("release")
}
debug {
isMinifyEnabled = false
applicationIdSuffix = ".debug"
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.webkit:webkit:1.9.0")
}
+23
View File
@@ -0,0 +1,23 @@
# Keep WebView JS interface
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
# Keep Hermes voice bridge class explicitly (inner classes get renamed by R8)
-keep class com.hermes.app.MainActivity$HermesVoiceBridge { *; }
# Keep Parcelable
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}
# Keep Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/Theme.HermesApp">
<activity
android:name=".MainActivity"
android:exported="true"
android:hardwareAccelerated="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|locale|layoutDirection"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#80000000" />
<size android:width="36dp" android:height="36dp" />
</shape>
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background -->
<item>
<shape android:shape="rectangle">
<solid android:color="#F0F6FF" />
<corners android:radius="10dp" />
</shape>
</item>
<!-- Left accent bar -->
<item android:left="0dp" android:top="4dp" android:bottom="4dp" android:width="4dp">
<shape android:shape="rectangle">
<solid android:color="#1565C0" />
<corners android:topLeftRadius="2dp" android:bottomLeftRadius="2dp" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,10 @@
<?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>
+11
View File
@@ -0,0 +1,11 @@
<?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"
android:tint="#FFFFFF">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1H8v-2h2c0.55,0 1,-0.45 1,-1V7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z" />
</vector>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<!-- Darker blue background -->
<path
android:fillColor="#0D47A1"
android:pathData="M0,0h108v108H0z" />
</vector>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<!-- Golden five-pointed star -->
<path
android:fillColor="#FFD54F"
android:pathData="M54,12L66,40L96,40L72,58L82,88L54,68L26,88L36,58L12,40L42,40Z" />
<!-- Subtle inner highlight -->
<path
android:fillColor="#FFC107"
android:pathData="M54,22L60,36L74,36L64,46L68,60L54,50L40,60L44,46L34,36L48,36Z" />
</vector>
+12
View File
@@ -0,0 +1,12 @@
<?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"
android:tint="#FFFFFF">
<!-- Three vertical dots (⋮) overflow menu icon -->
<path
android:fillColor="#FFFFFF"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
</vector>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android-color="#CC1A1A1A" />
<corners android:radius="8dp" />
<stroke
android:width="1dp"
android:color="#44FFFFFF" />
</shape>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Shadow layer -->
<item android:left="0dp" android:top="1dp" android:right="0dp" android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="#08000000" />
<corners android:radius="12dp" />
</shape>
</item>
<!-- Card background -->
<item android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp">
<shape android:shape="rectangle">
<solid android:color="#FFFFFF" />
<corners android:radius="12dp" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#F0F8FF" />
<corners android:radius="10dp" />
<stroke android:width="1dp" android:color="#1565C0" />
</shape>
+174
View File
@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
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:fitsSystemWindows="true">
<!-- ===== Navigation Page ===== -->
<LinearLayout
android:id="@+id/navPage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#F2F4F7"
android:visibility="visible">
<!-- Header -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:paddingTop="20dp"
android:paddingBottom="14dp"
android:background="@color/hermes_primary"
android:gravity="center_vertical">
<!-- App icon -->
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/ic_globe"
android:contentDescription="图标"
android:layout_marginEnd="10dp" />
<!-- Title + subtitle -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Favorites"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/headerSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="书签导航"
android:textColor="#B0D4F1"
android:textSize="12sp"
android:layout_marginTop="1dp" />
</LinearLayout>
<!-- Overflow menu button -->
<ImageButton
android:id="@+id/overflowBtn"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_overflow"
android:scaleType="centerInside"
android:padding="8dp"
android:contentDescription="更多"
android:tint="#FFFFFF" />
</LinearLayout>
<!-- URL List -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="12dp"
android:paddingTop="8dp"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/urlListContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
<!-- Bottom hint -->
<TextView
android:id="@+id/navHint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:text="点击书签打开 · 批量粘贴或导入 HTML 添加更多"
android:textColor="#999999"
android:textSize="12sp"
android:gravity="center"
android:background="#FFFFFF" />
</LinearLayout>
<!-- ===== WebView Page (tab strip at bottom) ===== -->
<LinearLayout
android:id="@+id/webPage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone">
<!-- WebView area (fills top) -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<FrameLayout
android:id="@+id/webViewContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="false"
app:trackColor="@android:color/transparent"
app:indicatorColor="@color/hermes_accent"
android:visibility="gone" />
</FrameLayout>
<!-- Tab Strip (fixed at bottom) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#F5F5F5"
android:elevation="4dp"
android:gravity="center_vertical"
android:paddingStart="0dp"
android:paddingEnd="0dp">
<HorizontalScrollView
android:id="@+id/tabScroll"
android:layout_width="0dp"
android:layout_height="44dp"
android:layout_weight="1"
android:scrollbars="none"
android:fadingEdgeLength="0dp"
android:overScrollMode="never">
<LinearLayout
android:id="@+id/tabStrip"
android:layout_width="wrap_content"
android:layout_height="44dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="6dp"
android:paddingEnd="4dp" />
</HorizontalScrollView>
<ImageButton
android:id="@+id/newTabBtn"
android:layout_width="44dp"
android:layout_height="44dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@android:drawable/ic_input_add"
android:scaleType="center"
android:tint="#555555"
android:contentDescription="新建标签" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="hermes_primary">#1565C0</color>
<color name="hermes_primary_dark">#0D47A1</color>
<color name="hermes_accent">#42A5F5</color>
<color name="hermes_background">#FAFAFA</color>
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
</resources>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Favorites</string>
</resources>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.HermesApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/hermes_primary</item>
<item name="colorPrimaryDark">@color/hermes_primary_dark</item>
<item name="colorAccent">@color/hermes_accent</item>
<item name="android:statusBarColor">@color/hermes_primary_dark</item>
<item name="android:windowBackground">@color/hermes_background</item>
<item name="android:windowTranslucentStatus">false</item>
</style>
</resources>