feat: scaffold counter_kt via init_kotlin_app

This commit is contained in:
2026-05-10 15:08:15 +02:00
commit 0b9e33da78
14 changed files with 315 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
.gradle/
build/
local.properties
*.iml
.idea/
captures/
.externalNativeBuild/
.cxx/
*.apk
*.aab
app/src/test/snapshots/
+18
View File
@@ -0,0 +1,18 @@
# counter_kt
Counter demo: validates FnTheme + Material3 + state + tests
Generado con `init_kotlin_app` del registry fn_registry.
## Requisitos
- Android SDK 34
- JDK 17
- Gradle 8.6 (via wrapper)
- `kotlin/functions/ui` modulo del registry (composite build)
## Build rapido
```bash
fn run gradle_assemble_debug_bash_infra apps/counter_kt
```
+68
View File
@@ -0,0 +1,68 @@
---
name: counter_kt
description: "Counter demo: validates FnTheme + Material3 + state + tests"
tags: [demo, counter, kotlin, compose, android]
lang: kt
framework: compose
entry_point: "app/src/main/kotlin/com/fnregistry/counterkt/MainActivity.kt"
dir_path: "apps/counter_kt"
repo_url: "https://gitea.organic-machine.com/dataforge/counter_kt"
uses_functions:
- fn_theme_kt_ui
- fn_tokens_kt_ui
uses_types: []
e2e_checks:
- id: unit
cmd: "fn run gradle_unit_test_bash_infra apps/counter_kt"
timeout_s: 240
- id: screenshot
cmd: "fn run gradle_screenshot_test_bash_infra apps/counter_kt"
timeout_s: 240
- id: build
cmd: "fn run gradle_assemble_debug_bash_infra apps/counter_kt"
timeout_s: 360
- id: emu_start
cmd: "fn run android_emulator_start_bash_infra Medium_Phone_API_35"
timeout_s: 240
- id: instrumented
cmd: "fn run gradle_instrumented_test_bash_infra apps/counter_kt"
timeout_s: 600
- id: emu_stop
cmd: "fn run android_emulator_stop_bash_infra"
severity: warning
timeout_s: 30
---
# counter_kt
Counter demo: validates FnTheme + Material3 + state + tests
## Build
```bash
fn run gradle_assemble_debug_bash_infra apps/counter_kt
```
## Tests unitarios + Roborazzi screenshots
```bash
fn run gradle_unit_test_bash_infra apps/counter_kt
fn run gradle_screenshot_test_bash_infra apps/counter_kt
```
## Tests instrumentados (requiere emulador)
```bash
fn run android_emulator_start_bash_infra Medium_Phone_API_35
fn run gradle_instrumented_test_bash_infra apps/counter_kt
fn run android_emulator_stop_bash_infra
```
## Package
`com.fnregistry.counterkt`
## FnTheme
La app usa FnTheme y FnTokens via composite build en `kotlin/functions/ui`.
Para cambiar colores o tipografia, editar el modulo del registry.
+63
View File
@@ -0,0 +1,63 @@
plugins {
id("com.android.application") version "8.4.0"
id("org.jetbrains.kotlin.android") version "1.9.22"
id("io.github.takahirom.roborazzi") version "1.20.0"
}
android {
namespace = "com.fnregistry.counterkt"
compileSdk = 34
defaultConfig {
applicationId = "com.fnregistry.counterkt"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "0.1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.8"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
testOptions {
unitTests {
isIncludeAndroidResources = true
all {
it.systemProperty("robolectric.graphicsMode", "NATIVE")
}
}
}
}
dependencies {
implementation("androidx.activity:activity-compose:1.8.2")
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")
// FnTheme + FnTokens via composite build
implementation("fn.compose:ui")
testImplementation("junit:junit:4.13.2")
testImplementation("org.robolectric:robolectric:4.11.1")
testImplementation("androidx.compose.ui:ui-test-junit4")
testImplementation("io.github.takahirom.roborazzi:roborazzi:1.20.0")
testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.20.0")
testImplementation("io.github.takahirom.roborazzi:roborazzi-junit-rule:1.20.0")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
@@ -0,0 +1,23 @@
package com.fnregistry.counterkt
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
@get:Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()
@Test
fun appLaunchesAndShowsReadyText() {
composeTestRule
.onNodeWithText("counter_kt ready")
.assertIsDisplayed()
}
}
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,24 @@
package com.fnregistry.counterkt
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import fn.compose.theme.FnTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
FnTheme {
Surface(modifier = Modifier.fillMaxSize()) {
Text("counter_kt ready")
}
}
}
}
}
+3
View File
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">counter_kt</string>
</resources>
@@ -0,0 +1,39 @@
package com.fnregistry.counterkt
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.test.junit4.createComposeRule
import com.github.takahirom.roborazzi.RoborazziRule
import fn.compose.theme.FnTheme
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.GraphicsMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class ExampleScreenshotTest {
@get:Rule
val composeTestRule = createComposeRule()
@get:Rule
val roborazziRule = RoborazziRule(
options = RoborazziRule.Options(
outputDirectoryPath = "src/test/snapshots/images",
),
)
@Test
fun screenshotFnThemeSurface() {
composeTestRule.setContent {
FnTheme {
Surface {
Text("counter_kt screenshot")
}
}
}
// Captura automaticamente al finalizar el test via RoborazziRule
}
}
+5
View File
@@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.4.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}
+4
View File
@@ -0,0 +1,4 @@
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
kotlin.code.style=official
android.nonTransitiveRClass=true
+7
View File
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Gradle wrapper stub — descarga gradle-wrapper.jar si no existe.
# En CI / en WSL instalar el wrapper real con: gradle wrapper --gradle-version 8.6
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec "$SCRIPT_DIR/gradle/wrapper/gradlew" "$@" 2>/dev/null || \
exec gradle "$@"
+23
View File
@@ -0,0 +1,23 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "counter_kt"
include(":app")
// Composite build: FnTheme + FnTokens desde el registry
includeBuild("../../kotlin/functions/ui") {
dependencySubstitution {
substitute(module("fn.compose:ui")).using(project(":"))
}
}