commit ef4804a477e37e9e43c096848e5d72a413efb537 Author: Porfiry Date: Sat Sep 19 23:06:09 2026 +0300 Скелет Android-клиента agentik Новый репозиторий под Android-версию клиента. Базовый проект на Jetpack Compose: один модуль :app, AGP 9.0.1, Kotlin 2.4.20, Compose BOM 2025.05.00, Ktor 3.1.3 (движок OkHttp — ядро больше не выбирает движок само). Ядро подключается из Nexus caffeine как pw.binom.agentik:client:5. Тема одна — тёмная, те же цвета, что согласованы для десктопного клиента (#121218 / #17212B / #6AB2F2 / #EBEBEB / #768C9E / #EC3942); экраны обязаны читать MaterialTheme.colorScheme.*, а не палитру напрямую. Сборка: ./gradlew :app:assembleDebug (нужен local.properties с sdk.dir). diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc98f82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle/ +/local.properties +/.idea/ +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties +app/build/ +build/ +*.apk +*.aab diff --git a/README.md b/README.md new file mode 100644 index 0000000..5da7045 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# agentik-android + +Android-клиент агента [agentik](https://git.binom.pw/subochev/agentik). + +## Что это + +Базовый скелет Android-приложения (Jetpack Compose). Логика диалогов, +сетевые вызовы и экраны будут навешиваться следующими задачами; пока +есть только стартовый экран и тёмная тема, согласованная с десктопным +клиентом. + +## Ядро + +Агент живёт в Nexus (`caffeine`, `pw.binom.agentik:client`). Версия — +в `gradle/libs.versions.toml` (`agentik = "5"`). Библиотека движок +не задаёт — на Android он собирается через +`agentikHttpClient(OkHttp, token) { ... }` поверх `ktor-client-okhttp`. + +## Сборка + +Нужен `local.properties` с `sdk.dir`: + +```properties +sdk.dir=/root/Android/Sdk +``` + +Этот файл **не коммитится** (см. `.gitignore`). + +Сборка debug-APK: + +```bash +export ANDROID_HOME=/root/Android/Sdk +./gradlew :app:assembleDebug +``` + +Артефакт: `app/build/outputs/apk/debug/app-debug.apk`. + +## Дизайн + +Одна тема — тёмная. Цвета в `app/src/main/kotlin/pw/binom/agentik/android/ui/theme/Color.kt`: + +| Слот | Значение | +|-----------------|--------------| +| `Background` | `#121218` | +| `Surface` | `#17212B` | +| `Accent` | `#6AB2F2` | +| `OnBackground` | `#EBEBEB` | +| `Muted` | `#768C9E` | +| `ErrorRed` | `#EC3942` | + +Экраны должны читать `MaterialTheme.colorScheme.*`, а не палитру +напрямую. diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..37a46a0 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,66 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.serialization) +} + +android { + namespace = "pw.binom.agentik.android" + compileSdk = libs.versions.android.compileSdk.get().toInt() + + defaultConfig { + applicationId = "pw.binom.agentik.android" + minSdk = libs.versions.android.minSdk.get().toInt() + targetSdk = libs.versions.android.targetSdk.get().toInt() + versionCode = (project.findProperty("versionCode") as? String)?.toIntOrNull() ?: 1 + versionName = (project.findProperty("versionName") as? String) ?: "1.0.0" + } + + buildTypes { + release { + isMinifyEnabled = false + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + buildFeatures { + compose = true + } + + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + excludes += "/META-INF/INDEX.LIST" + excludes += "/META-INF/DEPENDENCIES" + } + } +} + +dependencies { + // Ядро агента (Nexus caffeine). Тянет :proto, ktor-client-core и т.д. + implementation(libs.agentik.client) + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.androidx.lifecycle.viewmodel.compose) + + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.material.icons.extended) + debugImplementation(libs.androidx.compose.ui.tooling) + + implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.coroutines.core) + + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.okhttp) +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..26e27af --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/kotlin/pw/binom/agentik/android/AgentikApp.kt b/app/src/main/kotlin/pw/binom/agentik/android/AgentikApp.kt new file mode 100644 index 0000000..bd6a449 --- /dev/null +++ b/app/src/main/kotlin/pw/binom/agentik/android/AgentikApp.kt @@ -0,0 +1,9 @@ +package pw.binom.agentik.android + +import android.app.Application + +/** + * Точка входа приложения. Пока пустая: сюда будут подниматься настройки + * (адрес агента и токен) и хранилище. + */ +class AgentikApp : Application() diff --git a/app/src/main/kotlin/pw/binom/agentik/android/MainActivity.kt b/app/src/main/kotlin/pw/binom/agentik/android/MainActivity.kt new file mode 100644 index 0000000..a40b96d --- /dev/null +++ b/app/src/main/kotlin/pw/binom/agentik/android/MainActivity.kt @@ -0,0 +1,45 @@ +package pw.binom.agentik.android + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +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.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import pw.binom.agentik.android.ui.theme.AgentikTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + AgentikTheme { + Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> + StartScreen(Modifier.padding(innerPadding)) + } + } + } + } +} + +@Composable +private fun StartScreen(modifier: Modifier = Modifier) { + Column(modifier = modifier.padding(24.dp)) { + Text( + text = "Agentik", + style = MaterialTheme.typography.headlineMedium, + ) + Text( + text = "Клиент готов к работе. Дальше — список диалогов и чат.", + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.padding(top = 12.dp), + ) + } +} diff --git a/app/src/main/kotlin/pw/binom/agentik/android/ui/theme/Color.kt b/app/src/main/kotlin/pw/binom/agentik/android/ui/theme/Color.kt new file mode 100644 index 0000000..50c9a7a --- /dev/null +++ b/app/src/main/kotlin/pw/binom/agentik/android/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package pw.binom.agentik.android.ui.theme + +import androidx.compose.ui.graphics.Color + +// Тёмная тема клиента agentik (согласована с десктопным клиентом). +internal val Background = Color(0xFF121218) +internal val Surface = Color(0xFF17212B) +internal val Accent = Color(0xFF6AB2F2) +internal val OnBackground = Color(0xFFEBEBEB) +internal val Muted = Color(0xFF768C9E) +internal val ErrorRed = Color(0xFFEC3942) diff --git a/app/src/main/kotlin/pw/binom/agentik/android/ui/theme/Theme.kt b/app/src/main/kotlin/pw/binom/agentik/android/ui/theme/Theme.kt new file mode 100644 index 0000000..6fda91d --- /dev/null +++ b/app/src/main/kotlin/pw/binom/agentik/android/ui/theme/Theme.kt @@ -0,0 +1,33 @@ +package pw.binom.agentik.android.ui.theme + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.runtime.Composable + +/** + * Тема приложения. Пока одна — тёмная. + * + * Цвета берутся из [darkColorScheme] по СМЫСЛУ («поверхность», «акцент», + * «ошибка»), а не по виду: экраны обязаны читать `MaterialTheme.colorScheme.*`, + * чтобы позже появились другие темы без правки экранов. + */ +private val DarkColors = darkColorScheme( + primary = Accent, + onPrimary = Background, + background = Background, + onBackground = OnBackground, + surface = Surface, + onSurface = OnBackground, + surfaceVariant = Surface, + onSurfaceVariant = Muted, + error = ErrorRed, + onError = OnBackground, +) + +@Composable +fun AgentikTheme(content: @Composable () -> Unit) { + MaterialTheme( + colorScheme = DarkColors, + content = content, + ) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..0df3b3d --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Agentik + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..6c3ca57 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,4 @@ + + +