feat(android): Compose app with bundled yt-dlp, theme pack, nav & progress
Turn android/ into a real Gradle app (Kotlin + Jetpack Compose + Material3) that bundles an on-device yt-dlp engine and reuses the Phase-4 Rust JNI core. - Bundled engine: youtubedl-android (Python + yt-dlp + ffmpeg + aria2c) via Engine.kt; initialises off the main thread on first launch. Requires legacy jniLib packaging so the bundled .zip.so payloads extract to disk. - Intuitive navigation: bottom NavigationBar — Download / Files / Settings. - Settings section: dedicated screen with a live theme picker, default-quality chips, engine info, and a Rust-core demo. - All 19 desktop themes ported from src/theme.rs into Theme.kt as Material3 colour schemes, shown as tappable swatches; selection persisted (Prefs.kt). - Download screen: live platform detection through the Rust core as you type, plus an improved animated determinate progress indicator (%/ETA/status/ success-error) and a scrollable log. Toolchain pinned for reproducibility: Gradle 8.9 wrapper, AGP 8.5.2, Kotlin 1.9.24, Compose BOM 2024.06.00, compileSdk 34, minSdk 24, ABIs arm64-v8a + x86_64. build-apk.sh runs Gradle on a JDK <= 21 (system JDK may break R8) and builds the Rust libs first. Verified on an Android 14 x86_64 emulator: installs, launches, engine reports "yt-dlp ready", Rust .so loads, theme switching re-themes live and persists across restart, all screens render. (A real YouTube download still depends on the anti-bot/POT question — Phases 2-3, device-only.) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
1790fd1a22
commit
3a55ff5b8a
22 changed files with 1607 additions and 83 deletions
100
android/app/build.gradle.kts
Normal file
100
android/app/build.gradle.kts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.catacomb.spike"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.catacomb.spike"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
versionCode = 2
|
||||
versionName = "0.2-spike"
|
||||
// youtubedl-android ships native Python for these ABIs; the Rust core
|
||||
// (jniLibs/) ships arm64-v8a + x86_64. Restrict to the intersection so
|
||||
// every ABI in the APK has both libraries.
|
||||
ndk {
|
||||
abiFilters += listOf("arm64-v8a", "x86_64")
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
// Reproducible debug key so `assembleDebug` produces an installable,
|
||||
// stably-signed APK without Android Studio. Generated on first build
|
||||
// by build-apk.sh if absent.
|
||||
create("debugks") {
|
||||
val ks = rootProject.file("debug.keystore")
|
||||
if (ks.exists()) {
|
||||
storeFile = ks
|
||||
storePassword = "android"
|
||||
keyAlias = "androiddebugkey"
|
||||
keyPassword = "android"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
getByName("debug") {
|
||||
isMinifyEnabled = false
|
||||
if (rootProject.file("debug.keystore").exists()) {
|
||||
signingConfig = signingConfigs.getByName("debugks")
|
||||
}
|
||||
}
|
||||
getByName("release") {
|
||||
isMinifyEnabled = false
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
// Matches Kotlin 1.9.24.
|
||||
kotlinCompilerExtensionVersion = "1.5.14"
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||
}
|
||||
// youtubedl-android extracts its bundled Python/ffmpeg/aria2c payloads
|
||||
// (libpython.zip.so, …) from the native lib dir at first launch, so the
|
||||
// .so files MUST be extracted to disk — i.e. legacy packaging on
|
||||
// (extractNativeLibs=true). With them left compressed-in-APK the engine
|
||||
// init fails.
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val composeBom = platform("androidx.compose:compose-bom:2024.06.00")
|
||||
implementation(composeBom)
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.activity:activity-compose:1.9.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.2")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2")
|
||||
implementation("androidx.compose.ui:ui")
|
||||
implementation("androidx.compose.ui:ui-graphics")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
implementation("androidx.compose.material:material-icons-extended")
|
||||
|
||||
// On-device yt-dlp engine (bundled Python + yt-dlp) + ffmpeg + aria2c.
|
||||
implementation("io.github.junkfood02.youtubedl-android:library:0.18.1")
|
||||
implementation("io.github.junkfood02.youtubedl-android:ffmpeg:0.18.1")
|
||||
implementation("io.github.junkfood02.youtubedl-android:aria2c:0.18.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue