Set up project skeleton (milestone 1)

- Architecture and feature overview in docs/ARCHITECTURE.md
- Gradle 9.8 / AGP 9.4 / Kotlin 2.4 with version catalog and convention plugins
- Modules :app, :core:*, :device-profiles, :feature:* (placeholder screens)
- Flavors core (no INTERNET, enforced by a build check) and full
- Material You theme, navigation, expert mode and dry-run settings (DataStore)
- Pixel 8-10 device detection, unit tests, GPLv3 license, English README with Obtainium badge

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-15 22:02:14 +02:00
co-authored by Claude Opus 5.5
commit 0a7caf6c5f
117 changed files with 3175 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
plugins {
alias(libs.plugins.pixelwall.android.library)
alias(libs.plugins.pixelwall.android.compose)
}
android {
namespace = "org.pixelwall.core.ui"
}
dependencies {
api(project(":core:model"))
}
View File
@@ -0,0 +1,38 @@
package org.pixelwall.core.ui.component
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import org.pixelwall.core.ui.R
/** Platzhalter für Bereiche, deren Meilenstein noch aussteht. */
@Composable
fun PlaceholderScreen(title: String, description: String, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(
text = title,
style = MaterialTheme.typography.headlineSmall,
modifier = Modifier.semantics { heading() },
)
Text(text = description, style = MaterialTheme.typography.bodyLarge)
Text(
text = stringResource(R.string.placeholder_coming_soon),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
@@ -0,0 +1,45 @@
package org.pixelwall.core.ui.component
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AdminPanelSettings
import androidx.compose.material.icons.outlined.Terminal
import androidx.compose.material.icons.outlined.TouchApp
import androidx.compose.material3.AssistChip
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import org.pixelwall.core.model.PrivilegeLevel
import org.pixelwall.core.ui.R
/** Zeigt die Berechtigungsstufe an, die eine Einstellung benötigt. */
@Composable
fun PrivilegeChip(level: PrivilegeLevel, modifier: Modifier = Modifier) {
val label = stringResource(level.labelRes())
val description = stringResource(R.string.privilege_required, label)
AssistChip(
onClick = {},
enabled = true,
label = { Text(label) },
leadingIcon = {
Icon(
imageVector = when (level) {
PrivilegeLevel.NORMAL -> Icons.Outlined.TouchApp
PrivilegeLevel.ADB_GRANT -> Icons.Outlined.AdminPanelSettings
PrivilegeLevel.SHIZUKU -> Icons.Outlined.Terminal
},
contentDescription = null,
)
},
modifier = modifier.semantics { contentDescription = description },
)
}
fun PrivilegeLevel.labelRes(): Int = when (this) {
PrivilegeLevel.NORMAL -> R.string.privilege_normal
PrivilegeLevel.ADB_GRANT -> R.string.privilege_adb
PrivilegeLevel.SHIZUKU -> R.string.privilege_shizuku
}
@@ -0,0 +1,40 @@
package org.pixelwall.core.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
private val LightFallback = lightColorScheme(
primary = Color(0xFF2B5EA7),
secondary = Color(0xFF555F71),
tertiary = Color(0xFF6E5676),
)
private val DarkFallback = darkColorScheme(
primary = Color(0xFFA8C8FF),
secondary = Color(0xFFBDC7DC),
tertiary = Color(0xFFDABDE2),
)
/** Material You: dynamische Farben sind ab minSdk 34 immer verfügbar; Fallback nur für Previews. */
@Composable
fun PixelwallTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
content: @Composable () -> Unit,
) {
val context = LocalContext.current
val colorScheme = when {
dynamicColor && darkTheme -> dynamicDarkColorScheme(context)
dynamicColor -> dynamicLightColorScheme(context)
darkTheme -> DarkFallback
else -> LightFallback
}
MaterialTheme(colorScheme = colorScheme, content = content)
}
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="privilege_normal">Normal</string>
<string name="privilege_adb">ADB-Freigabe</string>
<string name="privilege_shizuku">Shizuku</string>
<string name="privilege_required">Benötigt: %1$s</string>
<string name="placeholder_coming_soon">Dieser Bereich ist noch nicht umgesetzt.</string>
</resources>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="privilege_normal">Normal</string>
<string name="privilege_adb">ADB grant</string>
<string name="privilege_shizuku">Shizuku</string>
<string name="privilege_required">Requires: %1$s</string>
<string name="placeholder_coming_soon">This area is not implemented yet.</string>
</resources>