Complete Android client for encrypted chat platform. 78+ Kotlin files: crypto (X3DH, Double Ratchet, AES-GCM, Ed25519, X25519, RSA-PSS), network (TCP/TLS, 50 endpoints), Hilt DI, Room+SQLCipher DB, Jetpack Compose UI with Catppuccin Mocha theme. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
342 lines
9.5 KiB
Markdown
342 lines
9.5 KiB
Markdown
# Agent A: Gradle + Project Setup
|
|
|
|
## Phase: 0 (Scaffolding)
|
|
## Priority: FIRST — blocks all other agents
|
|
|
|
## Context
|
|
You are setting up an Android project for "Kecalek" — an end-to-end encrypted chat application.
|
|
The app uses Signal Protocol (X3DH + Double Ratchet + Sender Keys) for encryption.
|
|
This is a Kotlin-first project with Jetpack Compose UI.
|
|
|
|
## Task
|
|
Create the complete Android project structure with Gradle build files, manifest, and empty package directories.
|
|
|
|
## Files to Create
|
|
|
|
### Root Level
|
|
```
|
|
android/
|
|
├── build.gradle.kts (project-level)
|
|
├── settings.gradle.kts
|
|
├── gradle.properties
|
|
├── gradle/
|
|
│ └── wrapper/
|
|
│ ├── gradle-wrapper.jar
|
|
│ └── gradle-wrapper.properties
|
|
├── gradlew
|
|
├── gradlew.bat
|
|
└── app/
|
|
├── build.gradle.kts (app-level)
|
|
└── src/
|
|
├── main/
|
|
│ ├── AndroidManifest.xml
|
|
│ ├── java/com/kecalek/chat/ (package dirs)
|
|
│ └── res/
|
|
│ ├── values/
|
|
│ │ ├── strings.xml
|
|
│ │ ├── themes.xml
|
|
│ │ └── colors.xml
|
|
│ ├── mipmap-hdpi/
|
|
│ ├── mipmap-mdpi/
|
|
│ ├── mipmap-xhdpi/
|
|
│ ├── mipmap-xxhdpi/
|
|
│ └── mipmap-xxxhdpi/
|
|
└── test/
|
|
└── java/com/kecalek/chat/
|
|
```
|
|
|
|
### Project-Level build.gradle.kts
|
|
```kotlin
|
|
plugins {
|
|
id("com.android.application") version "8.2.2" apply false
|
|
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
|
|
id("com.google.dagger.hilt.android") version "2.50" apply false
|
|
id("com.google.devtools.ksp") version "1.9.22-1.0.17" apply false
|
|
}
|
|
```
|
|
|
|
### settings.gradle.kts
|
|
```kotlin
|
|
pluginManagement {
|
|
repositories {
|
|
google()
|
|
mavenCentral()
|
|
gradlePluginPortal()
|
|
}
|
|
}
|
|
dependencyResolution {
|
|
repositories {
|
|
google()
|
|
mavenCentral()
|
|
}
|
|
}
|
|
rootProject.name = "Kecalek"
|
|
include(":app")
|
|
```
|
|
|
|
### App-Level build.gradle.kts
|
|
```kotlin
|
|
plugins {
|
|
id("com.android.application")
|
|
id("org.jetbrains.kotlin.android")
|
|
id("com.google.dagger.hilt.android")
|
|
id("com.google.devtools.ksp")
|
|
}
|
|
|
|
android {
|
|
namespace = "com.kecalek.chat"
|
|
compileSdk = 34
|
|
|
|
defaultConfig {
|
|
applicationId = "com.kecalek.chat"
|
|
minSdk = 26
|
|
targetSdk = 34
|
|
versionCode = 1
|
|
versionName = "0.8.5"
|
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
isMinifyEnabled = 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
|
|
}
|
|
|
|
composeOptions {
|
|
kotlinCompilerExtensionVersion = "1.5.8"
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
// Compose BOM
|
|
val composeBom = platform("androidx.compose:compose-bom:2024.02.00")
|
|
implementation(composeBom)
|
|
implementation("androidx.compose.ui:ui")
|
|
implementation("androidx.compose.ui:ui-graphics")
|
|
implementation("androidx.compose.ui:ui-tooling-preview")
|
|
implementation("androidx.compose.material3:material3")
|
|
implementation("androidx.compose.material:material-icons-extended")
|
|
implementation("androidx.activity:activity-compose:1.8.2")
|
|
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
|
|
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")
|
|
implementation("androidx.navigation:navigation-compose:2.7.7")
|
|
|
|
// Hilt DI
|
|
implementation("com.google.dagger:hilt-android:2.50")
|
|
ksp("com.google.dagger:hilt-compiler:2.50")
|
|
implementation("androidx.hilt:hilt-navigation-compose:1.1.0")
|
|
|
|
// Room + SQLCipher
|
|
implementation("androidx.room:room-runtime:2.6.1")
|
|
implementation("androidx.room:room-ktx:2.6.1")
|
|
ksp("androidx.room:room-compiler:2.6.1")
|
|
implementation("net.zetetic:android-database-sqlcipher:4.5.4")
|
|
implementation("androidx.sqlite:sqlite-ktx:2.4.0")
|
|
|
|
// Crypto: Tink + Bouncy Castle
|
|
implementation("com.google.crypto.tink:tink-android:1.12.0")
|
|
implementation("org.bouncycastle:bcprov-jdk18on:1.77")
|
|
implementation("org.bouncycastle:bcpkix-jdk18on:1.77")
|
|
|
|
// Image loading
|
|
implementation("io.coil-kt:coil-compose:2.5.0")
|
|
|
|
// QR code
|
|
implementation("com.google.zxing:core:3.5.3")
|
|
implementation("com.journeyapps:zxing-android-embedded:4.3.0")
|
|
|
|
// Camera (for QR scanning)
|
|
implementation("androidx.camera:camera-camera2:1.3.1")
|
|
implementation("androidx.camera:camera-lifecycle:1.3.1")
|
|
implementation("androidx.camera:camera-view:1.3.1")
|
|
|
|
// Biometric
|
|
implementation("androidx.biometric:biometric:1.1.0")
|
|
|
|
// DataStore (encrypted preferences)
|
|
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
|
implementation("androidx.security:security-crypto:1.1.0-alpha06")
|
|
|
|
// Coroutines
|
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
|
|
|
|
// JSON
|
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
|
|
|
|
// Testing
|
|
testImplementation("junit:junit:4.13.2")
|
|
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
|
|
androidTestImplementation(composeBom)
|
|
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
|
debugImplementation("androidx.compose.ui:ui-tooling")
|
|
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
|
}
|
|
```
|
|
|
|
### AndroidManifest.xml
|
|
```xml
|
|
<?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" />
|
|
<uses-permission android:name="android.permission.CAMERA" />
|
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
|
android:maxSdkVersion="32" />
|
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
|
|
|
<application
|
|
android:name=".KecalekApp"
|
|
android:allowBackup="false"
|
|
android:icon="@mipmap/ic_launcher"
|
|
android:label="@string/app_name"
|
|
android:supportsRtl="true"
|
|
android:theme="@style/Theme.Kecalek"
|
|
android:networkSecurityConfig="@xml/network_security_config">
|
|
|
|
<activity
|
|
android:name=".MainActivity"
|
|
android:exported="true"
|
|
android:theme="@style/Theme.Kecalek">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.MAIN" />
|
|
<category android:name="android.intent.category.LAUNCHER" />
|
|
</intent-filter>
|
|
</activity>
|
|
|
|
</application>
|
|
|
|
</manifest>
|
|
```
|
|
|
|
### gradle.properties
|
|
```properties
|
|
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|
android.useAndroidX=true
|
|
kotlin.code.style=official
|
|
android.nonTransitiveRClass=true
|
|
```
|
|
|
|
### res/values/strings.xml
|
|
```xml
|
|
<resources>
|
|
<string name="app_name">Kecalek</string>
|
|
</resources>
|
|
```
|
|
|
|
### res/xml/network_security_config.xml
|
|
```xml
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<network-security-config>
|
|
<base-config cleartextTrafficPermitted="false">
|
|
<trust-anchors>
|
|
<certificates src="system" />
|
|
</trust-anchors>
|
|
</base-config>
|
|
<!-- Debug only: allow cleartext for local dev -->
|
|
<debug-overrides>
|
|
<trust-anchors>
|
|
<certificates src="user" />
|
|
</trust-anchors>
|
|
</debug-overrides>
|
|
</network-security-config>
|
|
```
|
|
|
|
## Package Directory Structure
|
|
Create these empty directories under `app/src/main/java/com/kecalek/chat/`:
|
|
```
|
|
di/
|
|
crypto/
|
|
network/
|
|
core/
|
|
data/
|
|
data/local/
|
|
data/local/dao/
|
|
data/local/entity/
|
|
data/model/
|
|
data/repository/
|
|
ui/
|
|
ui/theme/
|
|
ui/navigation/
|
|
ui/auth/
|
|
ui/conversations/
|
|
ui/chat/
|
|
ui/groups/
|
|
ui/profile/
|
|
ui/verification/
|
|
ui/devices/
|
|
ui/components/
|
|
util/
|
|
```
|
|
|
|
## Placeholder Files
|
|
Create these minimal placeholder files:
|
|
|
|
### KecalekApp.kt
|
|
```kotlin
|
|
package com.kecalek.chat
|
|
|
|
import android.app.Application
|
|
import dagger.hilt.android.HiltAndroidApp
|
|
|
|
@HiltAndroidApp
|
|
class KecalekApp : Application()
|
|
```
|
|
|
|
### MainActivity.kt
|
|
```kotlin
|
|
package com.kecalek.chat
|
|
|
|
import android.os.Bundle
|
|
import androidx.activity.ComponentActivity
|
|
import androidx.activity.compose.setContent
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
|
|
@AndroidEntryPoint
|
|
class MainActivity : ComponentActivity() {
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
setContent {
|
|
// TODO: NavGraph entry point
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Constraints
|
|
- Min SDK 26 (Android 8.0)
|
|
- Target SDK 34 (Android 14)
|
|
- Kotlin 1.9.22
|
|
- Compose BOM 2024.02.00
|
|
- Java 17 compatibility
|
|
- Do NOT add any business logic
|
|
- Do NOT create any UI components beyond the placeholder MainActivity
|
|
- All `TODO` comments should be brief and descriptive
|
|
|
|
## DO NOT
|
|
- Implement any cryptographic operations
|
|
- Add any UI screens or composables
|
|
- Add business logic or ViewModels
|
|
- Modify any files outside the android/ directory
|