straw/strawApp/build.gradle.kts
Kayos 885398e3bd vc=26: look + feel pass — sulkta.com palette + Material Icons
Color palette pulled directly from sulkta.com's stylesheet — the same
greens used on the website now drive the app theme:
  #166534  deep green   (light-theme primary, top app bar background)
  #4ade80  bright lime  (dark-theme primary, accents in dark mode)
  #86efac  light green  (primaryContainer in light theme)
  #e8f5e8  pale green   (secondary container tint)
  #d97706  amber accent (tertiary)
  #374137  olive gray   (secondary on light, container on dark)

Replaces the made-up forest palette from vc=23 with the real Sulkta
brand. Same M3 tonal-role mapping so derived surfaces stay consistent.

TopAppBar redone NewPipe-style: solid deep-green bar with white
"straw" title, white hamburger + search icons. Clear bold header
instead of the previous white-with-a-pill-underneath layout.

Material Icons swapped in everywhere we had emoji:
  drawer        Person / History / PlaylistPlay / Download / Settings
  minibar       PlayArrow / Pause / Close
  fullscreen    Speed / Headphones / Videocam / Share /
                PictureInPictureAlt / KeyboardArrowDown
Pulled in material-icons-extended (4 MB APK growth, all icons).
Consistent renders across vendors; no more emoji font fallback drift.

FeedRow gets a NewPipe-style duration pill burned into the bottom-right
of every thumbnail (mm:ss / h:mm:ss). Live streams / mixes with no
duration leave it off.

Audit deferred-MED items addressed:
  MED-6: dropped the PlayerService STATE_ENDED auto-stop. Service
  shutdown is now driven only by onTaskRemoved + the minibar's ×.
  Removes the implicit "we'll never queue" assumption and is correct
  for a future autoplay/queue feature.
  LOW-7: DownloadsScreen adaptive poll — 1s while a download is
  active, 5s when idle. No more wasted DB queries when nothing
  is running.
2026-05-25 17:46:23 +00:00

206 lines
7.5 KiB
Kotlin

/*
* SPDX-FileCopyrightText: 2026 Sulkta-Coop
* SPDX-License-Identifier: GPL-3.0-or-later
*
* :strawApp — thin Android application shell. Day-2: pulls NewPipeExtractor,
* Media3, Ktor-style HTTP-via-OkHttp + kotlinx-serialization JSON for the
* search → detail → player → SponsorBlock + RYD flow. We keep our deps in
* this module, NOT in the shared libs.versions.toml, so upstream NewPipe
* stays cleanly mergeable.
*/
import com.android.build.api.dsl.ApplicationExtension
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.compose)
alias(libs.plugins.jetbrains.kotlinx.serialization)
}
kotlin {
jvmToolchain(21)
}
configure<ApplicationExtension> {
compileSdk {
version = release(NEWPIPE_VERSION_SDK_COMPILE_MAJOR) {
minorApiLevel = NEWPIPE_VERSION_SDK_COMPILE_MINOR
}
}
namespace = STRAW_APPLICATION_ID
defaultConfig {
applicationId = STRAW_APPLICATION_ID
minSdk { version = release(24) }
targetSdk { version = release(NEWPIPE_VERSION_SDK_TARGET) }
versionCode = STRAW_VERSION_CODE
versionName = STRAW_VERSION_NAME
resValue("string", "app_name", "Straw")
}
buildTypes {
debug {
isDebuggable = true
applicationIdSuffix = ".debug"
resValue("string", "app_name", "Straw debug")
}
release {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
buildFeatures {
compose = true
buildConfig = true
resValues = true
}
packaging {
resources {
excludes += setOf(
"META-INF/README.md",
"META-INF/CHANGES",
"META-INF/COPYRIGHT",
"META-INF/INDEX.LIST",
"META-INF/io.netty.versions.properties",
)
}
}
}
dependencies {
// Compose + AndroidX core
implementation(libs.androidx.activity)
implementation(libs.androidx.core)
implementation(libs.jetbrains.compose.runtime)
implementation(libs.jetbrains.compose.foundation)
implementation(libs.jetbrains.compose.material3)
implementation(libs.jetbrains.compose.ui)
implementation("androidx.compose.material:material-icons-extended:1.7.5")
// Lifecycle + ViewModel for Compose
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.10.0")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0")
// Image loading
implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp)
// NewPipeExtractor (JVM/Android-only) + its OkHttp dep
// libs.newpipe.extractor — REMOVED in Path C-6. Extractor is now strawcore
// (Rust + rustypipe via UniFFI). See rust/strawcore/ + the cargoBuild +
// uniffiBindgen Gradle tasks below.
implementation(libs.squareup.okhttp)
// JSON for SponsorBlock + Return YouTube Dislike clients
implementation(libs.kotlinx.serialization.json)
// Media3 ExoPlayer
implementation("androidx.media3:media3-exoplayer:1.4.1")
implementation("androidx.media3:media3-exoplayer-dash:1.4.1")
implementation("androidx.media3:media3-exoplayer-hls:1.4.1")
implementation("androidx.media3:media3-ui:1.4.1")
// Media3 session — MediaSessionService for background audio + lock-screen controls.
implementation("androidx.media3:media3-session:1.4.1")
// Guava ListenableFuture support for awaiting MediaController connect.
implementation("androidx.concurrent:concurrent-futures-ktx:1.2.0")
// strawcore — Rust YouTube extractor via UniFFI/JNA. Built by the
// cargoBuild + uniffiBindgen tasks below; phase U-2+ exposes search /
// streamInfo / channelInfo to replace NewPipeExtractor.
implementation("net.java.dev.jna:jna:5.14.0@aar")
}
// =============================================================================
// Phase U-1 / Path-C-2 — Rust core build glue.
//
// Two tasks chain into the Android build:
// cargoBuild — cross-compiles rust/strawcore for the four Android ABIs
// via cargo-ndk and drops the .so files in strawApp/src/main/jniLibs/.
// uniffiBindgen — generates the Kotlin bindings from the freshly-built lib
// into strawApp/src/main/java/uniffi/strawcore/.
//
// Both depend on:
// - cargo + rustup with the four Android targets installed
// - cargo-ndk on PATH
// - ANDROID_NDK_HOME pointing at an NDK with the right toolchains
// All of that lives in the crafting-table container.
// =============================================================================
val rustRoot = file("../rust").absolutePath
val jniLibsDir = file("src/main/jniLibs").absolutePath
val bindingsDir = file("src/main/java").absolutePath
val cargoHome: String = System.getenv("CARGO_HOME") ?: "/caches/cargo"
val cargoBin: String = "$cargoHome/bin/cargo"
val ndkHome: String = System.getenv("ANDROID_NDK_HOME")
?: System.getenv("ANDROID_NDK_ROOT")
?: "/caches/android-sdk/ndk/27.2.12479018"
// Honor CARGO_TARGET_DIR if set (we redirect it to /caches on crafting-table
// because the container's writable rootfs hits 100% before the cross-compile
// for 4 ABIs finishes). Falls back to the default `<workspace>/target`.
val cargoTargetDir: String = System.getenv("CARGO_TARGET_DIR")
?: "$rustRoot/target"
val cargoBuild by tasks.registering(Exec::class) {
group = "rust"
description = "Cross-compile strawcore for all Android ABIs via cargo-ndk."
workingDir = file(rustRoot)
environment("ANDROID_NDK_HOME", ndkHome)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(
cargoBin, "ndk",
"-t", "arm64-v8a",
"-t", "armeabi-v7a",
"-t", "x86",
"-t", "x86_64",
"-o", jniLibsDir,
"build", "--release", "-p", "strawcore",
)
standardOutput = System.out
errorOutput = System.err
}
val cargoBuildHost by tasks.registering(Exec::class) {
group = "rust"
description = "Build host-arch debug strawcore so bindgen can read its UniFFI metadata."
workingDir = file(rustRoot)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(cargoBin, "build", "-p", "strawcore")
standardOutput = System.out
errorOutput = System.err
}
val uniffiBindgen by tasks.registering(Exec::class) {
group = "rust"
description = "Generate Kotlin bindings for strawcore via uniffi-bindgen."
dependsOn(cargoBuildHost)
workingDir = file(rustRoot)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(
cargoBin, "run", "--quiet", "--bin", "uniffi-bindgen", "--",
"generate",
"--library", "$cargoTargetDir/debug/libstrawcore.so",
"--crate", "strawcore",
"--language", "kotlin",
"--no-format",
"--out-dir", bindingsDir,
)
standardOutput = System.out
errorOutput = System.err
}
// Make sure Android's JNI-libs merge picks up the freshly built .so files,
// and Kotlin compilation can resolve the generated bindings.
tasks.matching { it.name.startsWith("merge") && it.name.endsWith("JniLibFolders") }
.configureEach { dependsOn(cargoBuild) }
tasks.matching { it.name.startsWith("compile") && it.name.endsWith("Kotlin") }
.configureEach { dependsOn(uniffiBindgen) }