Скелет 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).
This commit is contained in:
Porfiry
2026-09-19 23:06:09 +03:00
commit ef4804a477
20 changed files with 707 additions and 0 deletions
+66
View File
@@ -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)
}
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".AgentikApp"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@android:drawable/sym_def_app_icon"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Agentik"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.Agentik">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,9 @@
package pw.binom.agentik.android
import android.app.Application
/**
* Точка входа приложения. Пока пустая: сюда будут подниматься настройки
* (адрес агента и токен) и хранилище.
*/
class AgentikApp : Application()
@@ -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),
)
}
}
@@ -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)
@@ -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,
)
}
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Agentik</string>
</resources>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Agentik" parent="android:Theme.Material.NoActionBar" />
</resources>
+3
View File
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
</full-backup-content>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules>
<cloud-backup>
</cloud-backup>
</data-extraction-rules>