diff --git a/airhub_app/.metadata b/airhub_app/.metadata
index 9e64d35..4183f93 100644
--- a/airhub_app/.metadata
+++ b/airhub_app/.metadata
@@ -15,7 +15,7 @@ migration:
- platform: root
create_revision: bd7a4a6b5576630823ca344e3e684c53aa1a0f46
base_revision: bd7a4a6b5576630823ca344e3e684c53aa1a0f46
- - platform: ios
+ - platform: android
create_revision: bd7a4a6b5576630823ca344e3e684c53aa1a0f46
base_revision: bd7a4a6b5576630823ca344e3e684c53aa1a0f46
diff --git a/airhub_app/android/.gitignore b/airhub_app/android/.gitignore
new file mode 100644
index 0000000..be3943c
--- /dev/null
+++ b/airhub_app/android/.gitignore
@@ -0,0 +1,14 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+.cxx/
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/to/reference-keystore
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/airhub_app/android/app/build.gradle.kts b/airhub_app/android/app/build.gradle.kts
new file mode 100644
index 0000000..5262112
--- /dev/null
+++ b/airhub_app/android/app/build.gradle.kts
@@ -0,0 +1,44 @@
+plugins {
+ id("com.android.application")
+ id("kotlin-android")
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id("dev.flutter.flutter-gradle-plugin")
+}
+
+android {
+ namespace = "com.airlab.airhub.airhub_app"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_17.toString()
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.airlab.airhub.airhub_app"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
+ minSdk = flutter.minSdkVersion
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.getByName("debug")
+ }
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/airhub_app/android/app/src/debug/AndroidManifest.xml b/airhub_app/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/airhub_app/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/airhub_app/android/app/src/main/AndroidManifest.xml b/airhub_app/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..00b6227
--- /dev/null
+++ b/airhub_app/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/airhub_app/android/app/src/main/kotlin/com/airlab/airhub/airhub_app/MainActivity.kt b/airhub_app/android/app/src/main/kotlin/com/airlab/airhub/airhub_app/MainActivity.kt
new file mode 100644
index 0000000..4befe1f
--- /dev/null
+++ b/airhub_app/android/app/src/main/kotlin/com/airlab/airhub/airhub_app/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.airlab.airhub.airhub_app
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity : FlutterActivity()
diff --git a/airhub_app/android/app/src/main/res/drawable-v21/launch_background.xml b/airhub_app/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/airhub_app/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/airhub_app/android/app/src/main/res/drawable/launch_background.xml b/airhub_app/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/airhub_app/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/airhub_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/airhub_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/airhub_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/airhub_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/airhub_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/airhub_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/airhub_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/airhub_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/airhub_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/airhub_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/airhub_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/airhub_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/airhub_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/airhub_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/airhub_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/airhub_app/android/app/src/main/res/values-night/styles.xml b/airhub_app/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/airhub_app/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/airhub_app/android/app/src/main/res/values/styles.xml b/airhub_app/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/airhub_app/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/airhub_app/android/app/src/profile/AndroidManifest.xml b/airhub_app/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/airhub_app/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/airhub_app/android/build.gradle.kts b/airhub_app/android/build.gradle.kts
new file mode 100644
index 0000000..dbee657
--- /dev/null
+++ b/airhub_app/android/build.gradle.kts
@@ -0,0 +1,24 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+val newBuildDir: Directory =
+ rootProject.layout.buildDirectory
+ .dir("../../build")
+ .get()
+rootProject.layout.buildDirectory.value(newBuildDir)
+
+subprojects {
+ val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
+ project.layout.buildDirectory.value(newSubprojectBuildDir)
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean") {
+ delete(rootProject.layout.buildDirectory)
+}
diff --git a/airhub_app/android/gradle.properties b/airhub_app/android/gradle.properties
new file mode 100644
index 0000000..fbee1d8
--- /dev/null
+++ b/airhub_app/android/gradle.properties
@@ -0,0 +1,2 @@
+org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
diff --git a/airhub_app/android/gradle/wrapper/gradle-wrapper.properties b/airhub_app/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e4ef43f
--- /dev/null
+++ b/airhub_app/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
diff --git a/airhub_app/android/settings.gradle.kts b/airhub_app/android/settings.gradle.kts
new file mode 100644
index 0000000..ca7fe06
--- /dev/null
+++ b/airhub_app/android/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ val flutterSdkPath =
+ run {
+ val properties = java.util.Properties()
+ file("local.properties").inputStream().use { properties.load(it) }
+ val flutterSdkPath = properties.getProperty("flutter.sdk")
+ require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
+ flutterSdkPath
+ }
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id("dev.flutter.flutter-plugin-loader") version "1.0.0"
+ id("com.android.application") version "8.11.1" apply false
+ id("org.jetbrains.kotlin.android") version "2.2.20" apply false
+}
+
+include(":app")
diff --git a/airhub_app/assets/www/kapi写作中.png b/airhub_app/assets/www/kapi_writing.png
similarity index 100%
rename from airhub_app/assets/www/kapi写作中.png
rename to airhub_app/assets/www/kapi_writing.png
diff --git a/airhub_app/assets/www/login.html b/airhub_app/assets/www/login.html
index 4468a3b..1e8c042 100644
--- a/airhub_app/assets/www/login.html
+++ b/airhub_app/assets/www/login.html
@@ -517,7 +517,7 @@
-
+
diff --git a/airhub_app/assets/www/login_mascot.png b/airhub_app/assets/www/login_mascot.png
new file mode 100644
index 0000000..61c6589
Binary files /dev/null and b/airhub_app/assets/www/login_mascot.png differ
diff --git a/airhub_app/assets/www/story-detail.html b/airhub_app/assets/www/story-detail.html
index 564db0e..66e1dde 100644
--- a/airhub_app/assets/www/story-detail.html
+++ b/airhub_app/assets/www/story-detail.html
@@ -204,7 +204,7 @@
@@ -494,8 +494,10 @@
let utterance = null;
- // Stop any previous speech
- window.speechSynthesis.cancel();
+ // Stop any previous speech (check if API exists)
+ if (window.speechSynthesis) {
+ window.speechSynthesis.cancel();
+ }
function setPauseUI() {
// Pause Icon
@@ -519,7 +521,7 @@
}
ttsBtn.onclick = () => {
- const synth = window.speechSynthesis;
+ const synth = window.speechSynthesis || { speak: () => { }, cancel: () => { }, pause: () => { }, resume: () => { }, paused: false, speaking: false };
if (!utterance) {
const pureText = contentEl.innerText;
utterance = new SpeechSynthesisUtterance(pureText);
@@ -577,8 +579,8 @@
// --- Make Picture Book Logic ---
const makeBookBtn = document.getElementById('make-book-btn');
makeBookBtn.onclick = () => {
- // STOP TTS IF PLAYING
- if (window.speechSynthesis.speaking) {
+ // STOP TTS IF PLAYING (check if API exists)
+ if (window.speechSynthesis && window.speechSynthesis.speaking) {
window.speechSynthesis.cancel();
resetTTSUI();
}
diff --git a/airhub_app/assets/www/story-loading.html b/airhub_app/assets/www/story-loading.html
index ae5068c..0530ea7 100644
--- a/airhub_app/assets/www/story-loading.html
+++ b/airhub_app/assets/www/story-loading.html
@@ -21,7 +21,7 @@
-
+
构思故事中...
diff --git a/airhub_app/assets/www/动态绘本/1.mp4 b/airhub_app/assets/www/storybook_videos/1.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/1.mp4
rename to airhub_app/assets/www/storybook_videos/1.mp4
diff --git a/airhub_app/assets/www/动态绘本/2.mp4 b/airhub_app/assets/www/storybook_videos/2.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/2.mp4
rename to airhub_app/assets/www/storybook_videos/2.mp4
diff --git a/airhub_app/assets/www/动态绘本/3.mp4 b/airhub_app/assets/www/storybook_videos/3.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/3.mp4
rename to airhub_app/assets/www/storybook_videos/3.mp4
diff --git a/airhub_app/assets/www/动态绘本/4.mp4 b/airhub_app/assets/www/storybook_videos/4.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/4.mp4
rename to airhub_app/assets/www/storybook_videos/4.mp4
diff --git a/airhub_app/assets/www/动态绘本/5.mp4 b/airhub_app/assets/www/storybook_videos/5.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/5.mp4
rename to airhub_app/assets/www/storybook_videos/5.mp4
diff --git a/airhub_app/assets/www/动态绘本/6.mp4 b/airhub_app/assets/www/storybook_videos/6.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/6.mp4
rename to airhub_app/assets/www/storybook_videos/6.mp4
diff --git a/airhub_app/assets/www/动态绘本/7.mp4 b/airhub_app/assets/www/storybook_videos/7.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/7.mp4
rename to airhub_app/assets/www/storybook_videos/7.mp4
diff --git a/airhub_app/assets/www/动态绘本/8.mp4 b/airhub_app/assets/www/storybook_videos/8.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/8.mp4
rename to airhub_app/assets/www/storybook_videos/8.mp4
diff --git a/airhub_app/assets/www/动态绘本/9.mp4 b/airhub_app/assets/www/storybook_videos/9.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/9.mp4
rename to airhub_app/assets/www/storybook_videos/9.mp4
diff --git a/airhub_app/assets/www/动态绘本/BGM_audio.mp3 b/airhub_app/assets/www/storybook_videos/BGM_audio.mp3
similarity index 100%
rename from airhub_app/assets/www/动态绘本/BGM_audio.mp3
rename to airhub_app/assets/www/storybook_videos/BGM_audio.mp3
diff --git a/airhub_app/assets/www/动态绘本/cover.mp4 b/airhub_app/assets/www/storybook_videos/cover.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/cover.mp4
rename to airhub_app/assets/www/storybook_videos/cover.mp4
diff --git a/airhub_app/assets/www/动态绘本/失控的魔法扫帚.mp4 b/airhub_app/assets/www/storybook_videos/magic_broom.mp4
similarity index 100%
rename from airhub_app/assets/www/动态绘本/失控的魔法扫帚.mp4
rename to airhub_app/assets/www/storybook_videos/magic_broom.mp4
diff --git a/airhub_app/lib/main.dart b/airhub_app/lib/main.dart
index 6d06fa6..a3cc90f 100644
--- a/airhub_app/lib/main.dart
+++ b/airhub_app/lib/main.dart
@@ -63,7 +63,7 @@ Page resource error:
},
),
)
- ..loadFlutterAsset('assets/www/index.html');
+ ..loadFlutterAsset('assets/www/login.html');
// #docregion platform_features
if (controller.platform is AndroidWebViewController) {
diff --git a/airhub_app/pubspec.yaml b/airhub_app/pubspec.yaml
index 507275a..64a9d52 100644
--- a/airhub_app/pubspec.yaml
+++ b/airhub_app/pubspec.yaml
@@ -43,7 +43,7 @@ flutter:
assets:
- assets/www/
- assets/www/icons/
- - assets/www/动态绘本/
+ - assets/www/storybook_videos/
- assets/www/story_covers/
# An image asset can refer to one or more resolution-specific "variants", see