7ae536e80d
Add on-device AI writing assistance using ML Kit GenAI APIs (Rewriting, Proofreading) powered by Gemini Nano via Android AICore. Users can tap the sparkle button in the compose toolbar to access tone chips (Correct, Rephrase, Shorter, Elaborate, Friendly, Professional, More Direct, Punchy, + Emoji) that transform their post text. Results appear in a card with Use/Dismiss actions. - Play flavor: MLKitWritingAssistant using on-device Gemini Nano - F-Droid flavor: NoOpWritingAssistant stub (returns unavailable) - WritingAssistant interface for future DVM/NIP90 integration - AI button hidden on unsupported devices Also fixes pre-existing exhaustive when expression in DecryptAndIndexProcessor for GroupEventResult.Duplicate. https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
400 lines
11 KiB
Groovy
400 lines
11 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("1.08.0")
|
|
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'
|
|
]
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), 'proguard-rules.pro'
|
|
minifyEnabled = true
|
|
}
|
|
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 = true
|
|
reset()
|
|
include "x86", "x86_64", "arm64-v8a", "armeabi-v7a"
|
|
universalApk = true
|
|
}
|
|
}
|
|
|
|
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 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
|
|
implementation libs.androidx.material.icons
|
|
|
|
// 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
|
|
|
|
// 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
|
|
|
|
// 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
|
|
} |