Repo cloned

This commit is contained in:
Fr4nz D13trich 2025-12-29 13:18:34 +01:00
commit 496ae75f58
7988 changed files with 1451097 additions and 0 deletions

View file

@ -0,0 +1,6 @@
plugins {
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
}
apply(from = "${rootDir}/../constants.gradle.kts")

View file

@ -0,0 +1,30 @@
plugins {
`kotlin-dsl`
}
val signalJavaVersion: JavaVersion by rootProject.extra
val signalKotlinJvmTarget: String by rootProject.extra
java {
sourceCompatibility = signalJavaVersion
targetCompatibility = signalJavaVersion
}
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(signalKotlinJvmTarget))
}
compilerOptions {
suppressWarnings = true
}
}
dependencies {
implementation(libs.kotlin.gradle.plugin)
implementation(libs.android.library)
implementation(libs.android.application)
// These allow us to reference the dependency catalog inside of our compiled plugins
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
implementation(files(testLibs.javaClass.superclass.protectionDomain.codeSource.location))
}

View file

@ -0,0 +1,200 @@
import com.android.build.gradle.AppExtension
import org.jetbrains.kotlin.com.google.gson.Gson
import org.w3c.dom.Document
import org.w3c.dom.Element
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
/**
* Utility object for parsing and manipulating xml resource files.
*/
object XmlRes {
fun parseStrings(stringsFile: File): Pair<Document, List<Element>> {
val doc = parseXmlFile(stringsFile)
val strings = doc.getElements("string") + doc.getElements("plurals")
return doc to strings
}
fun parseColors(stringsFile: File): Pair<Document, Map<String, String>> {
val doc = parseXmlFile(stringsFile)
val colors = doc.getElements("color").associateBy(
{ it.getAttribute("name") }, { it.firstChild.nodeValue }
)
return doc to colors
}
fun writeToFile(doc: Document, file: File) {
val transformer = TransformerFactory.newInstance().newTransformer()
transformer.transform(DOMSource(doc), StreamResult(file))
}
private fun parseXmlFile(file: File): Document {
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
return docBuilder.parse(file).apply {
xmlStandalone = true
}
}
private fun Document.getElements(tagName: String) =
getElementsByTagName(tagName).let { nodes ->
(0 until nodes.length).map { nodes.item(it) as Element }
}
}
val updateTranslationsForMolly by tasks.registering {
group = "Molly"
description = "Updates references to \"Signal\" with \"Molly\" in all translation files."
doLast {
val englishFile = file("src/main/res/values/strings.xml")
val (_, englishStrings) = XmlRes.parseStrings(englishFile)
// Gather all string names containing "mollyify" attribute
val mollyifyList = englishStrings
.filter { it.getAttribute("mollyify") == "true" }
.map { it.getAttribute("name") }
.toSet()
// Iterate through each translation file and perform the replacements
project.fileTree("src/main/res") {
include("**/values-*/strings.xml")
}.forEach { translationFile ->
try {
val (translationDoc, translatedStrings) = XmlRes.parseStrings(translationFile)
var modified = false
translatedStrings.forEach { elem ->
val name = elem.getAttribute("name")
if (name in mollyifyList) {
when (elem.tagName) {
"string" -> {
modified = elem.replaceSignalRefs() or modified
}
"plurals" -> {
val items = elem.getElementsByTagName("item")
for (i in 0 until items.length) {
val item = items.item(i) as Element
modified = item.replaceSignalRefs() or modified
}
}
}
}
}
if (modified) {
// Write back the modified translation file only if replacements were made
XmlRes.writeToFile(translationDoc, translationFile)
logger.lifecycle("Updated translations in: ${translationFile.toRelativeString(project.rootDir)}")
}
} catch (e: Exception) {
logger.error("Error processing file: ${translationFile.path}, ${e.message}")
}
}
}
}
private fun Element.replaceSignalRefs(): Boolean {
val oldContent = textContent
textContent = textContent
.replace("Signal", "Molly")
.replace("signal.org", "molly.im")
return oldContent != textContent
}
val updateColorsForMolly by tasks.registering {
group = "custom"
description = "Replaces Signal colors with Molly colors in the app source set."
doLast {
val appModule = project.rootProject.project(":app")
val mappingFile = appModule.file("src/main/res/values/molly_colors.xml")
val (_, colors) = XmlRes.parseColors(mappingFile)
val colorMappings = colors
.filterKeys { it.startsWith("stock_") }
.map { (signalColorName, signalColor) ->
val mollyColor = colors[signalColorName.replaceFirst("stock_", "molly_")]
?: throw GradleException("No 'molly_*' color found for '$signalColorName' in '$mappingFile'")
signalColor.uppercase() to mollyColor.uppercase()
}
.toSet()
val signalToMolly = colorMappings.groupBy({ it.first }, { it.second })
val mollyToSignal = colorMappings.groupBy({ it.second }, { it.first })
val signalConflicts = signalToMolly.filterValues { it.size > 1 }
val mollyConflicts = mollyToSignal.filterValues { it.size > 1 }
val cycles = mollyToSignal.keys.intersect(signalToMolly.keys).filterNot { color ->
color in signalToMolly[color].orEmpty() && color in mollyToSignal[color].orEmpty()
}
if (signalConflicts.isNotEmpty() || mollyConflicts.isNotEmpty() || cycles.isNotEmpty()) {
logger.error("Conflict detected! Some colors map to multiple values:")
signalConflicts.forEach { (color, set) -> logger.error("Signal $color → Molly: $set") }
mollyConflicts.forEach { (color, set) -> logger.error("Molly $color ← Signal: $set") }
cycles.forEach { logger.error("Signal ↔ Molly: $it") }
throw GradleException("Conflicting color mappings found in '$mappingFile'")
}
val regexReplacements = colorMappings.map { (signalColor, mollyColor) ->
val signalHex = signalColor.drop(1)
val mollyHex = mollyColor.drop(1)
val pattern = """(0x|#)([0-9A-Fa-f]{2})?($signalHex)\b""".toRegex(RegexOption.IGNORE_CASE)
pattern to mollyHex
}
val sourceFiles = fileTree(project.file("src/main")) {
include("**/*.xml", "**/*.kt", "**/*.java")
exclude("**/${mappingFile.name}", "res/values*/strings*.xml")
}
var anyChanges = false
sourceFiles.files.parallelStream().forEach { file ->
val originalContent = file.readText()
var modifiedContent = originalContent
var changesInFile = 0
regexReplacements.forEach { (regex, newColor) ->
modifiedContent = regex.replace(modifiedContent) { match ->
val (_, prefix, alpha, color) = match.groupValues
if (!color.equals(newColor, ignoreCase = true)) {
changesInFile++
"$prefix$alpha$newColor"
} else match.value
}
}
if (changesInFile > 0) {
file.writeText(modifiedContent)
logger.lifecycle("Updated: ${file.toRelativeString(project.rootDir)}: $changesInFile change(s)")
anyChanges = true
}
}
logger.lifecycle(
if (anyChanges) "Finished updating Signal colors to Molly."
else "No changes needed. Colors are already updated."
)
}
}
val version by tasks.registering {
doLast {
val android = project.extensions.getByType(AppExtension::class)
val versionCode = android.defaultConfig.versionCode
val versionName = android.defaultConfig.versionName
val versionInfo = mapOf(
"versionCode" to versionCode,
"versionName" to versionName
)
println(Gson().toJson(versionInfo))
}
}

View file

@ -0,0 +1,68 @@
@file:Suppress("UnstableApiUsage")
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.accessors.dm.LibrariesForTestLibs
import org.gradle.api.JavaVersion
import org.gradle.kotlin.dsl.extra
val libs = the<LibrariesForLibs>()
val testLibs = the<LibrariesForTestLibs>()
val signalBuildToolsVersion: String by rootProject.extra
val signalCompileSdkVersion: String by rootProject.extra
val signalTargetSdkVersion: Int by rootProject.extra
val signalMinSdkVersion: Int by rootProject.extra
val signalJavaVersion: JavaVersion by rootProject.extra
val signalKotlinJvmTarget: String by rootProject.extra
plugins {
// We cannot use the version catalog in the plugins block in convention plugins (it's not supported).
// Instead, plugin versions are controlled through the dependencies block in the build.gradle.kts.
id("com.android.library")
id("kotlin-android")
}
android {
buildToolsVersion = signalBuildToolsVersion
compileSdkVersion = signalCompileSdkVersion
defaultConfig {
minSdk = signalMinSdkVersion
vectorDrawables.useSupportLibrary = true
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = signalJavaVersion
targetCompatibility = signalJavaVersion
}
kotlinOptions {
jvmTarget = signalKotlinJvmTarget
suppressWarnings = true
}
lint {
disable += "InvalidVectorPath"
}
}
dependencies {
lintChecks(project(":lintchecks"))
coreLibraryDesugaring(libs.android.tools.desugar)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.annotation)
implementation(libs.androidx.appcompat)
implementation(libs.rxjava3.rxandroid)
implementation(libs.rxjava3.rxjava)
implementation(libs.rxjava3.rxkotlin)
implementation(libs.kotlin.stdlib.jdk8)
testImplementation(testLibs.junit.junit)
testImplementation(testLibs.robolectric.robolectric)
testImplementation(testLibs.androidx.test.core)
testImplementation(testLibs.androidx.test.core.ktx)
}

View file

@ -0,0 +1,85 @@
@file:Suppress("UnstableApiUsage")
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.accessors.dm.LibrariesForTestLibs
import org.gradle.api.JavaVersion
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.the
val libs = the<LibrariesForLibs>()
val testLibs = the<LibrariesForTestLibs>()
val signalBuildToolsVersion: String by rootProject.extra
val signalCompileSdkVersion: String by rootProject.extra
val signalTargetSdkVersion: Int by rootProject.extra
val signalMinSdkVersion: Int by rootProject.extra
val signalJavaVersion: JavaVersion by rootProject.extra
val signalKotlinJvmTarget: String by rootProject.extra
plugins {
// We cannot use the version catalog in the plugins block in convention plugins (it's not supported).
// Instead, plugin versions are controlled through the dependencies block in the build.gradle.kts.
id("com.android.application")
id("kotlin-android")
}
android {
buildToolsVersion = signalBuildToolsVersion
compileSdkVersion = signalCompileSdkVersion
defaultConfig {
versionCode = 1
versionName = "1.0"
minSdk = signalMinSdkVersion
targetSdk = signalTargetSdkVersion
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = signalJavaVersion
targetCompatibility = signalJavaVersion
}
kotlinOptions {
jvmTarget = signalKotlinJvmTarget
suppressWarnings = true
}
buildFeatures {
buildConfig = true
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.4"
}
}
dependencies {
coreLibraryDesugaring(libs.android.tools.desugar)
implementation(project(":core-util"))
coreLibraryDesugaring(libs.android.tools.desugar)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.annotation)
implementation(libs.androidx.appcompat)
implementation(libs.rxjava3.rxandroid)
implementation(libs.rxjava3.rxjava)
implementation(libs.rxjava3.rxkotlin)
implementation(libs.material.material)
implementation(libs.androidx.constraintlayout)
implementation(libs.kotlin.stdlib.jdk8)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.material3)
testImplementation(testLibs.junit.junit)
testImplementation(testLibs.robolectric.robolectric)
testImplementation(testLibs.androidx.test.core)
testImplementation(testLibs.androidx.test.core.ktx)
}

View file

@ -0,0 +1,28 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
create("testLibs") {
from(files("../gradle/test-libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"
include(":plugins")