feat(android): add data models, DataStore settings, Application class
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
28
android/app/src/main/AndroidManifest.xml
Normal file
28
android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:name=".DroidClawApp"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.DroidClaw">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.DroidClaw">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.thisux.droidclaw
|
||||
|
||||
import android.app.Application
|
||||
import com.thisux.droidclaw.data.SettingsStore
|
||||
|
||||
class DroidClawApp : Application() {
|
||||
lateinit var settingsStore: SettingsStore
|
||||
private set
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
settingsStore = SettingsStore(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.thisux.droidclaw.data
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||
|
||||
object SettingsKeys {
|
||||
val API_KEY = stringPreferencesKey("api_key")
|
||||
val SERVER_URL = stringPreferencesKey("server_url")
|
||||
val DEVICE_NAME = stringPreferencesKey("device_name")
|
||||
val AUTO_CONNECT = booleanPreferencesKey("auto_connect")
|
||||
}
|
||||
|
||||
class SettingsStore(private val context: Context) {
|
||||
|
||||
val apiKey: Flow<String> = context.dataStore.data.map { prefs ->
|
||||
prefs[SettingsKeys.API_KEY] ?: ""
|
||||
}
|
||||
|
||||
val serverUrl: Flow<String> = context.dataStore.data.map { prefs ->
|
||||
prefs[SettingsKeys.SERVER_URL] ?: "wss://localhost:8080"
|
||||
}
|
||||
|
||||
val deviceName: Flow<String> = context.dataStore.data.map { prefs ->
|
||||
prefs[SettingsKeys.DEVICE_NAME] ?: android.os.Build.MODEL
|
||||
}
|
||||
|
||||
val autoConnect: Flow<Boolean> = context.dataStore.data.map { prefs ->
|
||||
prefs[SettingsKeys.AUTO_CONNECT] ?: false
|
||||
}
|
||||
|
||||
suspend fun setApiKey(value: String) {
|
||||
context.dataStore.edit { it[SettingsKeys.API_KEY] = value }
|
||||
}
|
||||
|
||||
suspend fun setServerUrl(value: String) {
|
||||
context.dataStore.edit { it[SettingsKeys.SERVER_URL] = value }
|
||||
}
|
||||
|
||||
suspend fun setDeviceName(value: String) {
|
||||
context.dataStore.edit { it[SettingsKeys.DEVICE_NAME] = value }
|
||||
}
|
||||
|
||||
suspend fun setAutoConnect(value: Boolean) {
|
||||
context.dataStore.edit { it[SettingsKeys.AUTO_CONNECT] = value }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.thisux.droidclaw.model
|
||||
|
||||
enum class ConnectionState {
|
||||
Disconnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
Error
|
||||
}
|
||||
|
||||
enum class GoalStatus {
|
||||
Idle,
|
||||
Running,
|
||||
Completed,
|
||||
Failed
|
||||
}
|
||||
|
||||
data class AgentStep(
|
||||
val step: Int,
|
||||
val action: String,
|
||||
val reasoning: String,
|
||||
val timestamp: Long = System.currentTimeMillis()
|
||||
)
|
||||
|
||||
data class GoalSession(
|
||||
val sessionId: String,
|
||||
val goal: String,
|
||||
val steps: List<AgentStep>,
|
||||
val status: GoalStatus,
|
||||
val timestamp: Long = System.currentTimeMillis()
|
||||
)
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.thisux.droidclaw.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
|
||||
@Serializable
|
||||
data class AuthMessage(
|
||||
val type: String = "auth",
|
||||
val apiKey: String,
|
||||
val deviceInfo: DeviceInfoMsg? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class DeviceInfoMsg(
|
||||
val model: String,
|
||||
val androidVersion: String,
|
||||
val screenWidth: Int,
|
||||
val screenHeight: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ScreenResponse(
|
||||
val type: String = "screen",
|
||||
val requestId: String,
|
||||
val elements: List<UIElement>,
|
||||
val screenshot: String? = null,
|
||||
val packageName: String? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ResultResponse(
|
||||
val type: String = "result",
|
||||
val requestId: String,
|
||||
val success: Boolean,
|
||||
val error: String? = null,
|
||||
val data: String? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GoalMessage(
|
||||
val type: String = "goal",
|
||||
val text: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PongMessage(
|
||||
val type: String = "pong"
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ServerMessage(
|
||||
val type: String,
|
||||
val requestId: String? = null,
|
||||
val deviceId: String? = null,
|
||||
val message: String? = null,
|
||||
val sessionId: String? = null,
|
||||
val goal: String? = null,
|
||||
val success: Boolean? = null,
|
||||
val stepsUsed: Int? = null,
|
||||
val step: Int? = null,
|
||||
val action: JsonObject? = null,
|
||||
val reasoning: String? = null,
|
||||
val screenHash: String? = null,
|
||||
val x: Int? = null,
|
||||
val y: Int? = null,
|
||||
val x1: Int? = null,
|
||||
val y1: Int? = null,
|
||||
val x2: Int? = null,
|
||||
val y2: Int? = null,
|
||||
val duration: Int? = null,
|
||||
val text: String? = null,
|
||||
val packageName: String? = null,
|
||||
val url: String? = null,
|
||||
val code: Int? = null
|
||||
)
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.thisux.droidclaw.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class UIElement(
|
||||
val id: String = "",
|
||||
val text: String = "",
|
||||
val type: String = "",
|
||||
val bounds: String = "",
|
||||
val center: List<Int> = listOf(0, 0),
|
||||
val size: List<Int> = listOf(0, 0),
|
||||
val clickable: Boolean = false,
|
||||
val editable: Boolean = false,
|
||||
val enabled: Boolean = false,
|
||||
val checked: Boolean = false,
|
||||
val focused: Boolean = false,
|
||||
val selected: Boolean = false,
|
||||
val scrollable: Boolean = false,
|
||||
val longClickable: Boolean = false,
|
||||
val password: Boolean = false,
|
||||
val hint: String = "",
|
||||
val action: String = "read",
|
||||
val parent: String = "",
|
||||
val depth: Int = 0
|
||||
)
|
||||
Reference in New Issue
Block a user