From f1c83a2ee7aa45f8411e0b069b2e6f2ed73cd358 Mon Sep 17 00:00:00 2001 From: Mathieu Moran Date: Wed, 12 Aug 2026 00:26:54 -0400 Subject: [PATCH] init: android project scaffold (Phase 28.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Kotlin DSL build with version catalog (AGP 8.7, Kotlin 2.1, Compose BOM 2025.01) - app module: Compose + Material 3, dark theme, network security config - DualNetworkTestScreen — Phase 28.1 gate screen (buttons wired in 28.1.2) - YarisApp, MainActivity, YarisOBDTheme - ProGuard rules for Retrofit/OkHttp/Kotlinx Serialization/Coil/MapLibre/Room - cleartext allowed for 10.42.0.1 + yaris.local - gradle wrapper properties (needs Android Studio to generate wrapper jar) --- android/.gitignore | 12 ++ android/app/build.gradle.kts | 114 ++++++++++++++++ android/app/proguard-rules.pro | 45 ++++++ android/app/src/main/AndroidManifest.xml | 41 ++++++ .../com/yarisobd/app/DualNetworkTestScreen.kt | 128 ++++++++++++++++++ .../java/com/yarisobd/app/MainActivity.kt | 31 +++++ .../main/java/com/yarisobd/app/YarisApp.kt | 16 +++ .../java/com/yarisobd/app/ui/theme/Theme.kt | 83 ++++++++++++ android/app/src/main/res/values/strings.xml | 4 + android/app/src/main/res/values/themes.xml | 7 + .../main/res/xml/network_security_config.xml | 8 ++ android/build.gradle.kts | 7 + android/gradle.properties | 20 +++ android/gradle/libs.versions.toml | 78 +++++++++++ .../gradle/wrapper/gradle-wrapper.properties | 7 + android/plan.md | 8 +- android/settings.gradle.kts | 24 ++++ 17 files changed, 629 insertions(+), 4 deletions(-) create mode 100644 android/.gitignore create mode 100644 android/app/build.gradle.kts create mode 100644 android/app/proguard-rules.pro create mode 100644 android/app/src/main/AndroidManifest.xml create mode 100644 android/app/src/main/java/com/yarisobd/app/DualNetworkTestScreen.kt create mode 100644 android/app/src/main/java/com/yarisobd/app/MainActivity.kt create mode 100644 android/app/src/main/java/com/yarisobd/app/YarisApp.kt create mode 100644 android/app/src/main/java/com/yarisobd/app/ui/theme/Theme.kt create mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 android/app/src/main/res/values/themes.xml create mode 100644 android/app/src/main/res/xml/network_security_config.xml create mode 100644 android/build.gradle.kts create mode 100644 android/gradle.properties create mode 100644 android/gradle/libs.versions.toml create mode 100644 android/gradle/wrapper/gradle-wrapper.properties create mode 100644 android/settings.gradle.kts diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..a58baf0 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,12 @@ +# Android project ignores +*.iml +.gradle/ +build/ +local.properties +.idea/ +*.apk +*.aab +*.jks +*.keystore +!gradle/wrapper/gradle-wrapper.jar +!gradle/wrapper/gradle-wrapper.properties diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts new file mode 100644 index 0000000..fc71d9d --- /dev/null +++ b/android/app/build.gradle.kts @@ -0,0 +1,114 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.ksp) +} + +android { + namespace = "com.yarisobd.app" + compileSdk = 35 + + defaultConfig { + applicationId = "com.yarisobd.app" + minSdk = 26 + targetSdk = 35 + versionCode = 1 + versionName = "0.1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + debug { + applicationIdSuffix = ".debug" + versionNameSuffix = "-debug" + } + release { + isMinifyEnabled = true + isShrinkResources = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + } + + buildFeatures { + compose = true + buildConfig = true + } +} + +dependencies { + // Compose BOM + val composeBom = platform(libs.compose.bom) + implementation(composeBom) + androidTestImplementation(composeBom) + + // Compose UI + implementation(libs.compose.ui) + implementation(libs.compose.ui.graphics) + implementation(libs.compose.ui.tooling.preview) + implementation(libs.compose.material3) + implementation(libs.compose.material.icons) + debugImplementation(libs.compose.ui.tooling) + + // Navigation + implementation(libs.navigation.compose) + + // Activity + Compose integration + implementation(libs.activity.compose) + + // Core + implementation(libs.core.ktx) + + // Lifecycle + implementation(libs.lifecycle.runtime.compose) + implementation(libs.lifecycle.viewmodel.compose) + + // Network — will be used in 28.1.2 + // implementation(libs.okhttp) + // implementation(libs.okhttp.logging) + // implementation(libs.retrofit) + // implementation(libs.retrofit.kotlinx.serialization) + // implementation(libs.kotlinx.serialization.json) + + // Coroutines + implementation(libs.kotlinx.coroutines.android) + + // Local storage — will be used in 28.3 + // implementation(libs.room.runtime) + // implementation(libs.room.ktx) + // ksp(libs.room.compiler) + + // Background work — will be used in 28.3 + // implementation(libs.workmanager) + + // Images — will be used in 28.2 + // implementation(libs.coil.compose) + // implementation(libs.coil.okhttp) + + // Maps — will be used in 28.4 + // implementation(libs.maplibre) + + // Security — will be used in 28.1.3 + // implementation(libs.security.crypto) + + // Testing + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.2.1") + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") + androidTestImplementation(composeBom) + androidTestImplementation("androidx.compose.ui:ui-test-junit4") +} diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..1d6a2c9 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,45 @@ +# Add project specific ProGuard rules here. +# Keep rules for libraries used: + +# Retrofit +-keepattributes Signature, InnerClasses, EnclosingMethod +-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations +-keepclassmembers,allowshrinking,allowobfuscation interface * { + @retrofit2.http.* ; +} +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement +-dontwarn javax.annotation.** +-dontwarn kotlin.Unit +-dontwarn retrofit2.KotlinExtensions +-dontwarn retrofit2.KotlinExtensions$* + +# OkHttp +-dontwarn okhttp3.** +-dontwarn okio.** + +# Kotlinx Serialization +-keepattributes *Annotation*, InnerClasses +-dontnote kotlinx.serialization.AnnotationsKt +-keepclassmembers class kotlinx.serialization.json.** { + *** Companion; +} +-keepclasseswithmembers class kotlinx.serialization.json.** { + kotlinx.serialization.KSerializer serializer(...); +} +-keep,includedescriptorclasses class com.yarisobd.app.**$$serializer { *; } +-keepclassmembers class com.yarisobd.app.** { + *** Companion; +} +-keepclasseswithmembers class com.yarisobd.app.** { + kotlinx.serialization.KSerializer serializer(...); +} + +# Coil +-dontwarn coil.** + +# MapLibre +-keep class org.maplibre.** { *; } + +# Room +-keep class * extends androidx.room.RoomDatabase +-dontwarn androidx.room.paging.** diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b55fcf5 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/java/com/yarisobd/app/DualNetworkTestScreen.kt b/android/app/src/main/java/com/yarisobd/app/DualNetworkTestScreen.kt new file mode 100644 index 0000000..e3a5fe1 --- /dev/null +++ b/android/app/src/main/java/com/yarisobd/app/DualNetworkTestScreen.kt @@ -0,0 +1,128 @@ +package com.yarisobd.app + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +/** + * Phase 28.1 gate screen — proves dual-network binding works on the real device + * before building anything else. + * + * Two buttons: + * "Test Pi" → calls 10.42.0.1/api/gps/status over WiFi + * "Test Server" → calls yaris.ceaf.dev/health over cellular + * + * Both must succeed simultaneously while the phone is associated with the + * Pi's no-internet hotspot ("yaris 911"). + */ +@Composable +fun DualNetworkTestScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + text = "yaris-obd", + style = MaterialTheme.typography.headlineLarge, + color = MaterialTheme.colorScheme.primary + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Phase 28.1 — Network Binding Proof", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Pi WiFi test + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerHigh + ) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text( + text = "Pi Hotspot (WiFi)", + style = MaterialTheme.typography.titleMedium + ) + Text( + text = "Target: 10.42.0.1/api/gps/status", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(12.dp)) + Button( + onClick = { /* TODO: 28.1.2 — WiFi-bound OkHttp call */ }, + modifier = Modifier.fillMaxWidth() + ) { + Text("Test Pi") + } + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + // Server cellular test + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerHigh + ) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text( + text = "Remote Server (Cellular)", + style = MaterialTheme.typography.titleMedium + ) + Text( + text = "Target: yaris.ceaf.dev/health", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(12.dp)) + Button( + onClick = { /* TODO: 28.1.2 — Cellular-bound OkHttp call */ }, + modifier = Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.secondary + ) + ) { + Text("Test Server") + } + } + } + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Connect phone to \"yaris 911\" hotspot first.", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} diff --git a/android/app/src/main/java/com/yarisobd/app/MainActivity.kt b/android/app/src/main/java/com/yarisobd/app/MainActivity.kt new file mode 100644 index 0000000..e5b7f2c --- /dev/null +++ b/android/app/src/main/java/com/yarisobd/app/MainActivity.kt @@ -0,0 +1,31 @@ +package com.yarisobd.app + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.ui.Modifier +import com.yarisobd.app.ui.theme.YarisOBDTheme + +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + + setContent { + YarisOBDTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + // Placeholder — replaced by nav host in 28.1.2 + DualNetworkTestScreen() + } + } + } + } +} diff --git a/android/app/src/main/java/com/yarisobd/app/YarisApp.kt b/android/app/src/main/java/com/yarisobd/app/YarisApp.kt new file mode 100644 index 0000000..16b0c9c --- /dev/null +++ b/android/app/src/main/java/com/yarisobd/app/YarisApp.kt @@ -0,0 +1,16 @@ +package com.yarisobd.app + +import android.app.Application + +class YarisApp : Application() { + + override fun onCreate() { + super.onCreate() + instance = this + } + + companion object { + lateinit var instance: YarisApp + private set + } +} diff --git a/android/app/src/main/java/com/yarisobd/app/ui/theme/Theme.kt b/android/app/src/main/java/com/yarisobd/app/ui/theme/Theme.kt new file mode 100644 index 0000000..efc87bb --- /dev/null +++ b/android/app/src/main/java/com/yarisobd/app/ui/theme/Theme.kt @@ -0,0 +1,83 @@ +package com.yarisobd.app.ui.theme + +import android.app.Activity +import android.os.Build +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.runtime.SideEffect +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +// Brand colors — dark, car-friendly. Inspired by the Pi web UI's dark sidebar. +private val YarisGreen = Color(0xFF4CAF50) +private val YarisGreenDark = Color(0xFF388E3C) +private val YarisBackground = Color(0xFF121212) +private val YarisSurface = Color(0xFF1E1E1E) +private val YarisSurfaceVariant = Color(0xFF2C2C2C) + +private val DarkColorScheme = darkColorScheme( + primary = YarisGreen, + onPrimary = Color.Black, + primaryContainer = YarisGreenDark, + secondary = Color(0xFF81C784), + background = YarisBackground, + surface = YarisSurface, + surfaceContainerHigh = YarisSurfaceVariant, + onBackground = Color(0xFFE0E0E0), + onSurface = Color(0xFFE0E0E0), + onSurfaceVariant = Color(0xFFAAAAAA), + error = Color(0xFFEF5350), +) + +// Light scheme exists for completeness but the app defaults to dark +private val LightColorScheme = lightColorScheme( + primary = YarisGreenDark, + onPrimary = Color.White, + primaryContainer = Color(0xFFC8E6C9), + secondary = Color(0xFF43A047), + background = Color(0xFFFAFAFA), + surface = Color.White, + surfaceContainerHigh = Color(0xFFF5F5F5), + onBackground = Color(0xFF212121), + onSurface = Color(0xFF212121), + onSurfaceVariant = Color(0xFF757575), + error = Color(0xFFD32F2F), +) + +@Composable +fun YarisOBDTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + dynamicColor: Boolean = false, // Off by default — use our brand colors + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.background.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + content = content + ) +} diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..60dbf37 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + yaris-obd + diff --git a/android/app/src/main/res/values/themes.xml b/android/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..f04d7ef --- /dev/null +++ b/android/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..3d5d89b --- /dev/null +++ b/android/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,8 @@ + + + + + 10.42.0.1 + yaris.local + + diff --git a/android/build.gradle.kts b/android/build.gradle.kts new file mode 100644 index 0000000..614b661 --- /dev/null +++ b/android/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.kotlin.serialization) apply false + alias(libs.plugins.ksp) apply false +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..d7b1145 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,20 @@ +# Project-wide Gradle settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +org.gradle.parallel=true +org.gradle.caching=true + +# AndroidX package structure +android.useAndroidX=true + +# Kotlin code style +kotlin.code.style=official + +# Compose compiler (managed by Kotlin plugin in AGP 8.x+) +# No longer need composeVersion here — managed automatically + +# Disable build features we don't use +android.defaults.buildfeatures.buildconfig=true +android.defaults.buildfeatures.aidl=false +android.defaults.buildfeatures.renderscript=false +android.defaults.buildfeatures.resvalues=false +android.defaults.buildfeatures.shaders=false diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml new file mode 100644 index 0000000..c012c97 --- /dev/null +++ b/android/gradle/libs.versions.toml @@ -0,0 +1,78 @@ +[versions] +agp = "8.7.3" +kotlin = "2.1.0" +compose-bom = "2025.01.00" +compose-compiler = "1.5.15" # Kotlin 2.1.x +okhttp = "4.12.0" +retrofit = "2.11.0" +kotlinx-serialization = "1.7.3" +kotlinx-coroutines = "1.9.0" +room = "2.6.1" +workmanager = "2.10.0" +coil = "3.0.4" +maplibre = "11.7.0" +security-crypto = "1.1.0-alpha06" +lifecycle = "2.8.7" +activity-compose = "1.9.3" +core-ktx = "1.15.0" +navigation-compose = "2.8.5" + +[libraries] +# Compose BOM +compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } +compose-ui = { group = "androidx.compose.ui", name = "ui" } +compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +compose-material3 = { group = "androidx.compose.material3", name = "material3" } +compose-material-icons = { group = "androidx.compose.material", name = "material-icons-extended" } + +# Navigation +navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation-compose" } + +# Activity + Compose +activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" } + +# Core +core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } + +# Lifecycle +lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" } +lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } + +# Network +okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } +retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } +retrofit-kotlinx-serialization = { group = "com.squareup.retrofit2", name = "converter-kotlinx-serialization", version.ref = "retrofit" } + +# Serialization +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" } + +# Coroutines +kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } + +# Local storage +room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } +room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } +room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } + +# Background work +workmanager = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workmanager" } + +# Images +coil-compose = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref = "coil" } +coil-okhttp = { group = "io.coil-kt.coil3", name = "coil-network-okhttp", version.ref = "coil" } + +# Maps +maplibre = { group = "org.maplibre.gl", name = "android-sdk", version.ref = "maplibre" } + +# Security +security-crypto = { group = "androidx.security", name = "security-crypto", version.ref = "security-crypto" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version = "2.1.0-1.0.29" } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e2847c8 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/plan.md b/android/plan.md index c0bc99e..ac82a74 100644 --- a/android/plan.md +++ b/android/plan.md @@ -69,13 +69,13 @@ android/ ## Sub-phases -### 28.1 — Scaffold + networking proof-of-concept ⬜ NOT STARTED +### 28.1 — Scaffold + networking proof-of-concept 🚧 IN PROGRESS **Gate: dual-network binding must work on the real Pixel before anything else is built.** #### 28.1.1 — Project creation -- [ ] Create Android project in `android/` via Android Studio (Empty Activity + Compose) -- [ ] Kotlin DSL build files with version catalog -- [ ] `.gitignore` for Android (`*.iml`, `.gradle/`, `build/`, `local.properties`, `.idea/`) +- [x] Create Android project in `android/` via Android Studio (Empty Activity + Compose) +- [x] Kotlin DSL build files with version catalog +- [x] `.gitignore` for Android (`*.iml`, `.gradle/`, `build/`, `local.properties`, `.idea/`) - [ ] Verify project builds and runs on emulator (blank screen) - [ ] Commit: `init: android project scaffold` diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts new file mode 100644 index 0000000..dbe4530 --- /dev/null +++ b/android/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "yaris-obd" + +include(":app")