Files
amethyst/amethyst/build.gradle
T
Claude 19588be84b build(perf): trim build outputs for hooks, CI, and the shipped font
Headline numbers from a fresh `./gradlew assemble`:
- :commons material_symbols_outlined.ttf 11M -> 409K (subset to the 210
  codepoints actually referenced from MaterialSymbols.kt)
- :amethyst per-ABI APKs no longer built in CI (-PdisableAbiSplits=true);
  ~600M of stripped_native_libs intermediates skipped per run

Changes:
- .git-hooks/pre-push runs only :amethyst:testPlayDebugUnitTest plus jvmTest
  on the KMP modules instead of `./gradlew test`, which was compiling all six
  amethyst variants (play/fdroid x debug/release/benchmark)
- amethyst/build.gradle adds three opt-in fast-build flags:
    -PdisableAbiSplits=true       skip per-ABI APK splits
    -PdisableUniversalApk=true    skip the universal APK output
    -Pamethyst.skipMapping=true   disable R8 (release+benchmark)
  Defaults are unchanged; release pipelines must not set skipMapping.
- .github/workflows/build.yml uses gradle/actions/setup-gradle@v4 with
  cache-read-only on PRs / cache-write on main, drops --no-daemon, collapses
  the Android job to a single Gradle invocation (lint + focused debug unit
  tests + assembleBenchmark with -PdisableAbiSplits=true), and globs both
  APK naming patterns for the upload step.
- tools/material-symbols-subset/{subset.sh,README.md} regenerates the font
  from upstream + MaterialSymbols.kt; run after adding/removing icons.

Verified: ./gradlew :amethyst:help with all three new -P flags parses cleanly,
and ./gradlew :commons:jvmJar --rerun-tasks succeeds with the subsetted font
(commons-jvm jar shrinks from ~13M to 2.9M).

https://claude.ai/code/session_01YSmkagXXN5AwGcY4upiUh1
2026-05-05 22:49:43 +00:00

429 lines
13 KiB
Groovy

import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.googleServices)
alias(libs.plugins.jetbrainsComposeCompiler)
alias(libs.plugins.serialization)
}
def getCurrentBranch() {
try {
def branch = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim()
return branch
} catch (Exception e) {
println "Could not determine git branch: ${e.message}"
return "unknown"
}
}
def generateVersionName(String baseVersion) {
def currentBranch = getCurrentBranch()
if (currentBranch == "main" || currentBranch == "master" || currentBranch == "unknown" || currentBranch == "HEAD") {
return baseVersion
} else {
// Clean branch name for version (replace special characters)
def cleanBranch = currentBranch.replaceAll(/[^a-zA-Z0-9\-_]/, "-")
// Limit branch name to maximum 20 characters
if (cleanBranch.length() > 20) {
cleanBranch = cleanBranch.substring(0, 20)
}
return "${baseVersion}-${cleanBranch}"
}
}
// Workaround: stability.analyzer plugin doesn't declare task dependencies properly for Gradle 9.x
afterEvaluate {
def stabilityNames = tasks.names.findAll { it.contains("StabilityCheck") }
def compileNames = tasks.names.findAll { it.matches("compile.*UnitTestKotlin") }
stabilityNames.each { scName ->
compileNames.each { ctName ->
tasks.named(scName).configure { mustRunAfter(tasks.named(ctName)) }
}
}
}
android {
namespace = 'com.vitorpamplona.amethyst'
compileSdk = libs.versions.android.compileSdk.get().toInteger()
defaultConfig {
applicationId = "com.vitorpamplona.amethyst"
minSdk = libs.versions.android.minSdk.get().toInteger()
targetSdk = libs.versions.android.targetSdk.get().toInteger()
versionCode = 442
versionName = generateVersionName(libs.versions.app.get())
buildConfigField "String", "RELEASE_NOTES_ID", "\"be99e8c8d4df0f54b44eb6c96976ccb38baeea0192436a1c6fc8bc5e930da6b0\""
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
resourceConfigurations += [
'ar',
'ar-rSA',
'bn-rBD',
'cs',
'cs-rCZ',
'cy-rGB',
'da-rDK',
'de',
'de-rDE',
'el-rGR',
'en-rGB',
'eo',
'eo-rUY',
'es',
'es-rES',
'es-rMX',
'es-rUS',
'et-rEE',
'fa',
'fa-rIR',
'fi-rFI',
'fo-rFO',
'fr',
'fr-rCA',
'fr-rFR',
'gu-rIN',
'hi-rIN',
'hr-rHR',
'hu',
'hu-rHU',
'in',
'in-rID',
'it-rIT',
'iw-rIL',
'ja',
'ja-rJP',
'kk-rKZ',
'ko-rKR',
'ks-rIN',
'ku-rTR',
'lt-rLT',
'ne-rNP',
'nl',
'nl-rBE',
'nl-rNL',
'pcm-rNG',
'pl-rPL',
'pt-rBR',
'pt-rPT',
'ru',
'ru-rRU',
'ru-rUA',
'sa-rIN',
'sl-rSI',
'so-rSO',
'sr-rSP',
'ss-rZA',
'sv-rSE',
'sw-rKE',
'sw-rTZ',
'ta',
'ta-rIN',
'th',
'th-rTH',
'tr',
'tr-rTR',
'uk',
'uk-rUA',
'ur-rIN',
'uz-rUZ',
'vi-rVN',
'zh',
'zh-rCN',
'zh-rHK',
'zh-rSG',
'zh-rTW'
]
}
// Opt-in fast-build flags. Default behavior is unchanged.
//
// -PdisableAbiSplits=true skip per-ABI APK splits; produces a single
// APK per (flavor, buildType) instead of 5.
// Cuts ~600 MB of intermediates and several
// minutes off CI.
// -PdisableUniversalApk=true when ABI splits are enabled, skip the
// extra universal APK output. (No effect
// when disableAbiSplits is also set, since
// there are no splits to add to.)
// -Pamethyst.skipMapping=true disable R8 minification on release and
// benchmark. APK is larger, but builds are
// much faster and outputs/mapping/ (~260MB)
// is not produced. Local-dev and PR-CI use
// only — release pipelines must not set it.
def disableAbiSplits = providers.gradleProperty("disableAbiSplits")
.map { it.toBoolean() }.getOrElse(false)
def disableUniversalApk = providers.gradleProperty("disableUniversalApk")
.map { it.toBoolean() }.getOrElse(false)
def skipMapping = providers.gradleProperty("amethyst.skipMapping")
.map { it.toBoolean() }.getOrElse(false)
buildTypes {
release {
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), 'proguard-rules.pro'
minifyEnabled = !skipMapping
}
debug {
applicationIdSuffix '.debug'
versionNameSuffix '-DEBUG'
resValue "string", "app_name", "@string/app_name_debug"
}
create("benchmark") {
initWith(getByName("release"))
applicationIdSuffix '.benchmark'
versionNameSuffix '-BENCHMARK'
resValue "string", "app_name", "@string/app_name_benchmark"
profileable = true
signingConfig = signingConfigs.debug
}
}
// TODO: remove this when lightcompressor uses one MP4 parser only
packaging {
resources {
resources.pickFirsts.add('builddef.lst')
resources.pickFirsts.add('META-INF/LICENSE.md')
resources.pickFirsts.add('META-INF/LICENSE-notice.md')
}
}
flavorDimensions = ["channel"]
productFlavors {
play {
getIsDefault().set(true)
dimension "channel"
}
fdroid {
dimension "channel"
}
}
splits {
abi {
enable = !disableAbiSplits
reset()
include "x86", "x86_64", "arm64-v8a", "armeabi-v7a"
universalApk = !disableUniversalApk
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
buildFeatures {
compose = true
buildConfig = true
resValues = true
}
packagingOptions {
resources {
excludes += ['/META-INF/{AL2.0,LGPL2.1}', '**/libscrypt.dylib']
}
}
lint {
disable 'MissingTranslation'
}
testOptions {
unitTests.returnDefaultValues = true
}
}
// TODO: until google merges and unifiedpush updates https://github.com/tink-crypto/tink-java-apps/pull/5
configurations.all {
def tink = "com.google.crypto.tink:tink-android:1.17.0"
resolutionStrategy {
force(tink)
dependencySubstitution {
substitute module('com.google.crypto.tink:tink') using module(tink)
}
}
}
kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_21
}
}
composeCompiler {
reportsDestination = layout.buildDirectory.dir("compose_compiler")
metricsDestination = layout.buildDirectory.dir("compose_compiler")
}
dependencies {
implementation platform(libs.androidx.compose.bom)
implementation project(path: ':quartz')
implementation project(path: ':commons')
implementation project(path: ':ammolite')
implementation project(path: ':nestsClient')
implementation libs.androidx.core.ktx
implementation libs.androidx.activity.compose
implementation libs.androidx.ui
implementation libs.androidx.ui.graphics
implementation libs.androidx.ui.tooling.preview
// Needs this to open gallery / image upload
implementation libs.androidx.fragment.ktx
// Navigation
implementation libs.androidx.navigation.compose
// Material 3 Design
implementation libs.androidx.material3
// Adaptive Layout / Two Pane
implementation libs.androidx.material3.windowSize
implementation libs.accompanist.adaptive
// Lifecycle
implementation libs.androidx.lifecycle.runtime.ktx
implementation libs.androidx.lifecycle.runtime.compose
implementation libs.androidx.lifecycle.viewmodel.compose
// Zoomable images
implementation libs.zoomable
// Biometrics
implementation libs.androidx.biometric.ktx
// Background Work
implementation libs.androidx.work.runtime.ktx
// Websockets API
implementation libs.okhttp
implementation libs.okhttpCoroutines
// Encrypted Key Storage
implementation libs.androidx.security.crypto.ktx
implementation libs.androidx.datastore.preferences
// view videos
implementation libs.androidx.media3.exoplayer
implementation libs.androidx.media3.exoplayer.hls
implementation libs.androidx.media3.ui.compose.material3
implementation libs.androidx.media3.session
// important for proxy / tor
implementation libs.androidx.media3.datasource.okhttp
// Load images from the web.
implementation libs.coil.compose
// view gifs
implementation libs.coil.gif
// view svgs
implementation libs.coil.svg
// enables network for coil
implementation libs.coil.okhttp
// loads thumbnails for media3
// TODO: Replace this to the FrameExtractor in media 3
// when FrameExtractor accepts custom data sources.
implementation(libs.coil.video)
// Permission to upload pictures:
implementation libs.accompanist.permissions
// For QR generation
implementation libs.zxing
implementation libs.zxing.embedded
// Markdown
//implementation "com.halilibo.compose-richtext:richtext-ui:0.16.0"
//implementation "com.halilibo.compose-richtext:richtext-ui-material:0.16.0"
//implementation "com.halilibo.compose-richtext:richtext-commonmark:0.16.0"
// Markdown (With fix for full-image bleeds)
implementation libs.markdown.ui
implementation libs.markdown.ui.material3
implementation libs.markdown.commonmark
// Language picker and Theme chooser
implementation libs.androidx.appcompat
// Dynamically adjust between phone and tablet UI
implementation libs.androidx.window.core.android
// Local model for language identification
playImplementation libs.google.mlkit.language.id
// Google services model the translate text
playImplementation libs.google.mlkit.translate
// On-device AI writing assistance (Gemini Nano via AICore)
playImplementation libs.google.mlkit.genai.proofreading
playImplementation libs.google.mlkit.genai.prompt
playImplementation libs.google.mlkit.genai.rewriting
// On-device alt-text suggestions: genai image description (preferred, descriptive sentences)
// with image-labeling as a keyword-join fallback for devices without AICore.
playImplementation libs.google.mlkit.genai.image.description
// PushNotifications
playImplementation platform(libs.firebase.bom)
playImplementation libs.firebase.messaging
//PushNotifications(FDroid)
fdroidImplementation libs.unifiedpush
// Charts
implementation libs.vico.charts.compose
implementation libs.vico.charts.m3
// Waveform visualizer
implementation libs.audiowaveform
// Video compression lib
implementation libs.abedElazizShe.video.compressor.fork
// Image compression lib
implementation libs.zelory.image.compressor
// EXIF metadata stripping
implementation libs.androidx.exifinterface
// Voice anonymization DSP
implementation libs.tarsosdsp
// WebRTC for voice/video calls
implementation libs.stream.webrtc.android
// Cbor for cashuB format
implementation libs.kotlinx.serialization.cbor
// Kotlin serialization for the times where we need the Json tree and performance is not that important.
implementation(libs.kotlinx.serialization.json)
testImplementation libs.junit
testImplementation libs.mockk
testImplementation libs.kotlinx.coroutines.test
androidTestImplementation platform(libs.androidx.compose.bom)
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.junit.ktx
androidTestImplementation libs.androidx.espresso.core
androidTestImplementation libs.androidx.ui.test.junit4
androidTestImplementation libs.mockk.android
debugImplementation platform(libs.androidx.compose.bom)
debugImplementation libs.androidx.ui.tooling
debugImplementation libs.androidx.ui.test.manifest
implementation libs.androidx.camera.core
implementation libs.androidx.camera.camera2
implementation libs.androidx.camera.lifecycle
implementation libs.androidx.camera.view
implementation libs.androidx.camera.extensions
}