From 83c031930bf569620b269921073b24af103e9564 Mon Sep 17 00:00:00 2001 From: zhouxiaofeng <2946471396@qq.com> Date: Thu, 16 Jul 2026 15:22:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/compiler.xml | 6 + .idea/deploymentTargetSelector.xml | 11 + .idea/gradle.xml | 6 + .idea/misc.xml | 2 +- .idea/vcs.xml | 6 + .kotlin/errors/errors-1784164186560.log | 69 ++ app/build.gradle.kts | 42 +- app/proguard-rules.pro | 3 + app/src/main/AndroidManifest.xml | 5 + .../java/cn/flyzxf/agentapp/MainActivity.kt | 50 +- .../java/cn/flyzxf/agentapp/data/ApiClient.kt | 233 +++++ .../java/cn/flyzxf/agentapp/data/Models.kt | 65 ++ .../java/cn/flyzxf/agentapp/data/Store.kt | 95 ++ .../java/cn/flyzxf/agentapp/ui/ChatScreen.kt | 941 ++++++++++++++++++ .../cn/flyzxf/agentapp/ui/ChatViewModel.kt | 358 +++++++ .../cn/flyzxf/agentapp/ui/SettingsScreen.kt | 367 +++++++ .../agentapp/ui/components/MarkdownText.kt | 278 ++++++ .../java/cn/flyzxf/agentapp/ui/theme/Color.kt | 44 +- .../java/cn/flyzxf/agentapp/ui/theme/Theme.kt | 141 ++- .../java/cn/flyzxf/agentapp/ui/theme/Type.kt | 50 +- .../res/drawable/ic_launcher_background.xml | 177 +--- .../res/drawable/ic_launcher_foreground.xml | 31 +- app/src/main/res/values-night/colors.xml | 4 + app/src/main/res/values/colors.xml | 8 +- app/src/main/res/values/strings.xml | 2 +- app/src/main/res/values/themes.xml | 10 +- .../main/res/xml/network_security_config.xml | 9 + build-fix.txt | 46 + build-fix2.txt | 45 + build-fix3.txt | 45 + build-output.txt | 45 + build-output2.txt | 45 + build.gradle.kts | 3 +- gradle.properties | 11 +- gradle/libs.versions.toml | 19 +- replay_pid32560.log | 0 screen.png | Bin 0 -> 185132 bytes settings.gradle.kts | 9 +- 38 files changed, 2968 insertions(+), 313 deletions(-) create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/vcs.xml create mode 100644 .kotlin/errors/errors-1784164186560.log create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/java/cn/flyzxf/agentapp/data/ApiClient.kt create mode 100644 app/src/main/java/cn/flyzxf/agentapp/data/Models.kt create mode 100644 app/src/main/java/cn/flyzxf/agentapp/data/Store.kt create mode 100644 app/src/main/java/cn/flyzxf/agentapp/ui/ChatScreen.kt create mode 100644 app/src/main/java/cn/flyzxf/agentapp/ui/ChatViewModel.kt create mode 100644 app/src/main/java/cn/flyzxf/agentapp/ui/SettingsScreen.kt create mode 100644 app/src/main/java/cn/flyzxf/agentapp/ui/components/MarkdownText.kt create mode 100644 app/src/main/res/values-night/colors.xml create mode 100644 app/src/main/res/xml/network_security_config.xml create mode 100644 build-fix.txt create mode 100644 build-fix2.txt create mode 100644 build-fix3.txt create mode 100644 build-output.txt create mode 100644 build-output2.txt create mode 100644 replay_pid32560.log create mode 100644 screen.png diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..ca16a99 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 7505d8d..cdbc250 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -5,6 +5,12 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index c2b3ddc..a4f09e2 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.kotlin/errors/errors-1784164186560.log b/.kotlin/errors/errors-1784164186560.log new file mode 100644 index 0000000..23bb2c8 --- /dev/null +++ b/.kotlin/errors/errors-1784164186560.log @@ -0,0 +1,69 @@ +kotlin version: 2.2.10 +error message: Daemon compilation failed: Connection to the Kotlin daemon has been unexpectedly lost. This might be caused by the daemon being killed by another process or the operating system, or by JVM crash. +org.jetbrains.kotlin.gradle.tasks.DaemonCrashedException: Connection to the Kotlin daemon has been unexpectedly lost. This might be caused by the daemon being killed by another process or the operating system, or by JVM crash. + at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.wrapCompilationExceptionIfNeeded(tasksUtils.kt:54) + at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.wrapAndRethrowCompilationException(tasksUtils.kt:65) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:243) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111) + at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74) + at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61) + at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58) + at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176) + at java.base/java.util.concurrent.FutureTask.run(Unknown Source) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169) + at org.gradle.internal.Factories$1.create(Factories.java:30) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:275) + at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:273) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:265) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:128) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:133) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) + at java.base/java.util.concurrent.FutureTask.run(Unknown Source) + at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) + at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) + at java.base/java.lang.Thread.run(Unknown Source) +Caused by: java.rmi.UnmarshalException: Error unmarshaling return header; nested exception is: + java.net.SocketException: Connection reset + at java.rmi/sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source) + at java.rmi/sun.rmi.server.UnicastRef.invoke(Unknown Source) + at java.rmi/java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source) + at java.rmi/java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source) + at jdk.proxy4/jdk.proxy4.$Proxy134.compile(Unknown Source) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.incrementalCompilationWithDaemon(GradleKotlinCompilerWork.kt:328) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:235) + ... 40 more +Caused by: java.net.SocketException: Connection reset + at java.base/sun.nio.ch.NioSocketImpl.implRead(Unknown Source) + at java.base/sun.nio.ch.NioSocketImpl.read(Unknown Source) + at java.base/sun.nio.ch.NioSocketImpl$1.read(Unknown Source) + at java.base/java.net.Socket$SocketInputStream.read(Unknown Source) + at java.base/java.io.BufferedInputStream.fill(Unknown Source) + at java.base/java.io.BufferedInputStream.implRead(Unknown Source) + at java.base/java.io.BufferedInputStream.read(Unknown Source) + at java.base/java.io.DataInputStream.readUnsignedByte(Unknown Source) + at java.base/java.io.DataInputStream.readByte(Unknown Source) + ... 47 more + + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f7352f8..b425c56 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,51 +1,69 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.serialization) } android { namespace = "cn.flyzxf.agentapp" - compileSdk { - version = release(36) { - minorApiLevel = 1 - } - } + compileSdk = 36 defaultConfig { applicationId = "cn.flyzxf.agentapp" minSdk = 28 - targetSdk = 36 + targetSdk = 35 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } } buildTypes { release { - optimization { - enable = false - } + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } buildFeatures { compose = true } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + +kotlin { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + } } dependencies { implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.activity.compose) implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.material.icons.extended) implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.androidx.lifecycle.viewmodel.compose) + implementation(libs.okhttp) + implementation(libs.kotlinx.serialization.json) testImplementation(libs.junit) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.compose.ui.test.junit4) @@ -53,4 +71,4 @@ dependencies { androidTestImplementation(libs.androidx.junit) debugImplementation(libs.androidx.compose.ui.test.manifest) debugImplementation(libs.androidx.compose.ui.tooling) -} \ No newline at end of file +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..870de40 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,3 @@ +# Add project specific ProGuard rules here. +-keep class cn.flyzxf.agentapp.data.** { *; } +-keepclassmembers class kotlinx.serialization.json.** { *; } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 56250e7..17780e2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + - Greeting( - name = "Android", - modifier = Modifier.padding(innerPadding) - ) + val viewModel: ChatViewModel = viewModel() + val state by viewModel.ui.collectAsStateWithLifecycle() + AppTheme(darkTheme = state.isDarkTheme) { + Surface( + modifier = Modifier.fillMaxSize().background(LocalAppColors.current.bg), + ) { + ChatScreen(viewModel = viewModel) } } } } } - -@Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) -} - -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - AgentAppTheme { - Greeting("Android") - } -} \ No newline at end of file diff --git a/app/src/main/java/cn/flyzxf/agentapp/data/ApiClient.kt b/app/src/main/java/cn/flyzxf/agentapp/data/ApiClient.kt new file mode 100644 index 0000000..1fc48e2 --- /dev/null +++ b/app/src/main/java/cn/flyzxf/agentapp/data/ApiClient.kt @@ -0,0 +1,233 @@ +package cn.flyzxf.agentapp.data + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.buildJsonArray +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import java.io.IOException +import java.util.concurrent.TimeUnit +import kotlin.coroutines.coroutineContext + +class ApiClient { + + private val json = Json { ignoreUnknownKeys = true; isLenient = true } + + private val client = OkHttpClient.Builder() + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.MILLISECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .retryOnConnectionFailure(true) + .build() + + // ---- safe JSON helpers (handle JsonNull without throwing) ---- + private fun JsonElement?.objOrNull(): JsonObject? = this as? JsonObject + private fun JsonElement?.arrOrNull(): JsonArray? = this as? JsonArray + private fun JsonElement?.strOrNull(): String? { + val p = this as? JsonPrimitive ?: return null + if (p === JsonNull || p is JsonNull) return null + return p.content + } + private fun JsonElement?.longOrZero(): Long { + val p = this as? JsonPrimitive ?: return 0L + if (p === JsonNull || p is JsonNull) return 0L + return p.content.toLongOrNull() ?: 0L + } + + private fun normalizeBaseURL(baseURL: String): String { + var url = baseURL.trim().trimEnd('/') + if (url.endsWith("/chat/completions")) { + url = url.removeSuffix("/chat/completions") + } + return url + } + + private fun chatURL(baseURL: String) = normalizeBaseURL(baseURL) + "/chat/completions" + private fun modelsURL(baseURL: String) = normalizeBaseURL(baseURL) + "/models" + + suspend fun fetchModels(baseURL: String, apiKey: String): List = withContext(Dispatchers.IO) { + val request = Request.Builder() + .url(modelsURL(baseURL)) + .get() + .addHeader("Authorization", "Bearer $apiKey") + .build() + val call = client.newCall(request) + val parentJob = coroutineContext[Job] + val handle = parentJob?.invokeOnCompletion { call.cancel() } + try { + call.execute().use { res -> + if (!res.isSuccessful) { + val body = res.body?.string().orEmpty() + throw IOException("HTTP ${res.code}: ${body.take(400)}") + } + val root = json.parseToJsonElement(res.body!!.string()).objOrNull() + ?: return@withContext emptyList() + val data = root["data"].arrOrNull() ?: root["models"].arrOrNull() ?: emptyList() + data.mapNotNull { el -> + when (el) { + is JsonPrimitive -> if (el is JsonNull) null else el.content + is JsonObject -> el["id"].strOrNull() ?: el["name"].strOrNull() + else -> null + } + }.filter { it.isNotBlank() } + } + } finally { + handle?.dispose() + } + } + + suspend fun streamChat( + params: StreamParams, + onChunk: (content: String, reasoning: String) -> Unit, + onUsage: (Usage) -> Unit, + ): Pair = withContext(Dispatchers.IO) { + val parentJob = coroutineContext[Job]!! + var currentMessages = params.messages + var accumulated = "" + val maxIter = 16 + val continuePrompt = "继续,请从刚才中断的地方直接接着输出,不要重复已经输出的任何内容。" + + for (iter in 0 until maxIter) { + coroutineContext.ensureActive() + val body = buildRequestBody(params, currentMessages) + val request = Request.Builder() + .url(chatURL(params.baseURL)) + .post(body.toRequestBody(JSON)) + .addHeader("Authorization", "Bearer ${params.apiKey}") + .addHeader("Accept", "text/event-stream") + .build() + + val call = client.newCall(request) + val handle = parentJob.invokeOnCompletion { runCatching { call.cancel() } } + + try { + val response = call.execute() + if (!response.isSuccessful) { + val errBody = response.body?.string().orEmpty() + response.close() + throw IOException("HTTP ${response.code}: ${errBody.take(500)}") + } + val source = response.body!!.byteStream().bufferedReader() + var finishReason: String? = null + var sawDone = false + var gotContentThisIter = false + + try { + while (true) { + if (!parentJob.isActive) { + response.close() + return@withContext StreamOutcome.ABORTED to accumulated + } + val line = source.readLine() ?: break + val data = line.removePrefix("data:").trim() + if (data.isEmpty()) continue + if (data == "[DONE]") { sawDone = true; break } + val el = runCatching { json.parseToJsonElement(data) }.getOrNull() ?: continue + val obj = el.objOrNull() ?: continue + + // usage + val usageEl = obj["usage"] + if (usageEl != null && usageEl !is JsonNull) { + val u = parseUsage(usageEl) + if (u.totalTokens > 0) onUsage(u) + } + + // choices + val choices = obj["choices"].arrOrNull() + val choice = choices?.firstOrNull().objOrNull() + if (choice != null) { + val delta = choice["delta"].objOrNull() + val content = delta?.get("content").strOrNull().orEmpty() + val reasoning = (delta?.get("reasoning_content").strOrNull() + ?: delta?.get("reasoning").strOrNull()).orEmpty() + if (content.isNotEmpty()) { + accumulated += content + gotContentThisIter = true + onChunk(content, "") + } + if (reasoning.isNotEmpty()) { + onChunk("", reasoning) + } + val fr = choice["finish_reason"].strOrNull() + if (fr != null && fr != "null") finishReason = fr + } + } + } finally { + response.close() + } + handle.dispose() + + if (!parentJob.isActive) return@withContext StreamOutcome.ABORTED to accumulated + + val truncated = finishReason == "length" + + if (truncated && iter < maxIter - 1 && accumulated.isNotEmpty()) { + currentMessages = params.messages + listOf( + mapOf("role" to "assistant", "content" to accumulated), + mapOf("role" to "user", "content" to continuePrompt), + ) + onChunk("\n\n", "") + continue + } + break + } catch (e: IOException) { + handle.dispose() + if (!parentJob.isActive) { + return@withContext StreamOutcome.ABORTED to accumulated + } + throw e + } + } + StreamOutcome.DONE to accumulated + } + + private fun buildRequestBody(params: StreamParams, messages: List>): String { + val msgs = buildJsonArray { + messages.forEach { m -> + add(buildJsonObject { + m.forEach { (k, v) -> put(k, v) } + }) + } + } + val root = buildJsonObject { + put("model", params.model) + put("messages", msgs) + put("stream", true) + if (params.enableThinking) { + put("thinking", buildJsonObject { put("type", "enabled") }) + if (params.reasoningEffort != null) put("reasoning_effort", params.reasoningEffort) + } + if (params.maxTokens > 0) put("max_tokens", params.maxTokens) + } + return root.toString() + } + + private fun parseUsage(el: JsonElement): Usage { + val obj = el.objOrNull() ?: return Usage() + fun getLong(key: String): Long = obj[key].longOrZero() + val input = getLong("prompt_tokens").let { if (it > 0) it else getLong("input_tokens") } + val completion = getLong("completion_tokens").let { if (it > 0) it else getLong("output_tokens") } + val details = obj["completion_tokens_details"].objOrNull() + val reasoning = (details?.get("reasoning_tokens").longOrZero()).let { + if (it > 0) it else getLong("reasoning_tokens") + } + val total = getLong("total_tokens").let { if (it > 0) it else input + completion } + return Usage(input, completion, reasoning, total) + } + + companion object { + private val JSON = "application/json; charset=utf-8".toMediaType() + } +} diff --git a/app/src/main/java/cn/flyzxf/agentapp/data/Models.kt b/app/src/main/java/cn/flyzxf/agentapp/data/Models.kt new file mode 100644 index 0000000..da015d3 --- /dev/null +++ b/app/src/main/java/cn/flyzxf/agentapp/data/Models.kt @@ -0,0 +1,65 @@ +package cn.flyzxf.agentapp.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Provider( + val id: String = "", + val name: String = "", + val baseURL: String = "", + val apiKey: String = "", + val models: List = emptyList(), + val maxTokens: Long = 0, + val visionModels: List = emptyList(), +) + +@Serializable +data class Usage( + val promptTokens: Long = 0, + val completionTokens: Long = 0, + val reasoningTokens: Long = 0, + val totalTokens: Long = 0, +) + +@Serializable +data class Message( + val role: String, + val content: String = "", + val reasoning: String = "", + val usage: Usage? = null, + val streaming: Boolean = false, +) + +@Serializable +data class Conversation( + val id: String, + val title: String = "新对话", + val messages: List = emptyList(), + val providerId: String? = null, + val model: String? = null, + val createdAt: Long = 0L, + val updatedAt: Long = 0L, +) + +data class ConversationMeta( + val id: String, + val title: String, + val providerId: String?, + val model: String?, + val createdAt: Long, + val updatedAt: Long, + val messageCount: Int, +) + +data class StreamParams( + val baseURL: String, + val apiKey: String, + val model: String, + val messages: List>, + val enableThinking: Boolean, + val reasoningEffort: String?, + val maxTokens: Long, +) + +enum class StreamOutcome { DONE, ABORTED, ERROR } diff --git a/app/src/main/java/cn/flyzxf/agentapp/data/Store.kt b/app/src/main/java/cn/flyzxf/agentapp/data/Store.kt new file mode 100644 index 0000000..cb4f167 --- /dev/null +++ b/app/src/main/java/cn/flyzxf/agentapp/data/Store.kt @@ -0,0 +1,95 @@ +package cn.flyzxf.agentapp.data + +import android.content.Context +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import java.io.File +import java.util.UUID + +class Store(context: Context) { + + private val json = Json { + ignoreUnknownKeys = true + encodeDefaults = true + prettyPrint = true + } + + private val rootDir = File(context.filesDir, "agentapp").apply { mkdirs() } + private val convDir = File(rootDir, "conversations").apply { mkdirs() } + private val providersFile = File(rootDir, "providers.json") + + // ---------------- providers ---------------- + + fun getProviders(): List { + if (!providersFile.exists()) return emptyList() + return runCatching { + json.decodeFromString>(providersFile.readText()) + }.getOrDefault(emptyList()) + } + + fun saveProvider(provider: Provider): Provider { + val list = getProviders().toMutableList() + val p = if (provider.id.isBlank()) provider.copy(id = UUID.randomUUID().toString()) else provider + val idx = list.indexOfFirst { it.id == p.id } + if (idx >= 0) list[idx] = p else list.add(p) + writeProviders(list) + return p + } + + fun deleteProvider(id: String) { + writeProviders(getProviders().filter { it.id != id }) + } + + private fun writeProviders(list: List) { + providersFile.writeText(json.encodeToString(list)) + } + + // ---------------- conversations ---------------- + + fun getConversationList(): List { + val files = convDir.listFiles { f -> f.isFile && f.name.endsWith(".json") } ?: emptyArray() + return files.mapNotNull { f -> + runCatching { + val c = json.decodeFromString(f.readText()) + ConversationMeta( + id = c.id, + title = c.title, + providerId = c.providerId, + model = c.model, + createdAt = c.createdAt, + updatedAt = c.updatedAt, + messageCount = c.messages.size, + ) + }.getOrNull() + }.sortedByDescending { it.updatedAt } + } + + fun getConversation(id: String): Conversation? { + val f = File(convDir, "$id.json") + if (!f.exists()) return null + return runCatching { json.decodeFromString(f.readText()) }.getOrNull() + } + + fun saveConversation(conv: Conversation): Conversation { + val now = System.currentTimeMillis() + val saved = conv.copy( + createdAt = if (conv.createdAt == 0L) now else conv.createdAt, + updatedAt = now, + ) + File(convDir, "${saved.id}.json").writeText(json.encodeToString(saved)) + return saved + } + + fun deleteConversation(id: String) { + File(convDir, "$id.json").delete() + } + + fun clearAllConversations() { + convDir.listFiles { f -> f.isFile && f.name.endsWith(".json") }?.forEach { it.delete() } + } + + fun renameConversation(id: String, title: String) { + val conv = getConversation(id) ?: return + saveConversation(conv.copy(title = title)) + } +} diff --git a/app/src/main/java/cn/flyzxf/agentapp/ui/ChatScreen.kt b/app/src/main/java/cn/flyzxf/agentapp/ui/ChatScreen.kt new file mode 100644 index 0000000..ca3af9e --- /dev/null +++ b/app/src/main/java/cn/flyzxf/agentapp/ui/ChatScreen.kt @@ -0,0 +1,941 @@ +package cn.flyzxf.agentapp.ui + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.AutoAwesome +import androidx.compose.material.icons.filled.Clear +import androidx.compose.material.icons.filled.ContentCopy +import androidx.compose.material.icons.filled.DarkMode +import androidx.compose.material.icons.filled.DeleteOutline +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.filled.LightMode +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.Person +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material.icons.automirrored.filled.Send +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.filled.Stop +import androidx.compose.material.icons.outlined.ChatBubbleOutline +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalDrawerSheet +import androidx.compose.material3.ModalNavigationDrawer +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.rememberDrawerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import cn.flyzxf.agentapp.data.Message +import cn.flyzxf.agentapp.data.Usage +import cn.flyzxf.agentapp.ui.components.MarkdownText +import cn.flyzxf.agentapp.ui.theme.LocalAppColors +import kotlinx.coroutines.launch + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChatScreen(viewModel: ChatViewModel) { + val state by viewModel.ui.collectAsStateWithLifecycle() + val c = LocalAppColors.current + val context = LocalContext.current + val drawerState = rememberDrawerState(initialValue = androidx.compose.material3.DrawerValue.Closed) + val scope = rememberCoroutineScope() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(state.toast) { + state.toast?.let { + snackbarHostState.showSnackbar(it) + viewModel.clearToast() + } + } + + LaunchedEffect(state.drawerOpen) { + if (state.drawerOpen) scope.launch { drawerState.open() } else scope.launch { drawerState.close() } + } + LaunchedEffect(drawerState.currentValue) { + if (drawerState.currentValue == androidx.compose.material3.DrawerValue.Closed && state.drawerOpen) { + viewModel.setDrawerOpen(false) + } + } + + ModalNavigationDrawer( + drawerState = drawerState, + drawerContent = { + SidebarContent( + state = state, + onNewChat = { viewModel.newConversation() }, + onOpen = { viewModel.openConversation(it); scope.launch { drawerState.close() } }, + onDelete = { viewModel.deleteConversation(it) }, + onClearAll = { viewModel.clearAll() }, + onSettings = { viewModel.setShowSettings(true); scope.launch { drawerState.close() } }, + onSearch = { viewModel.setSearchQuery(it) }, + onToggleTheme = { viewModel.toggleTheme() }, + ) + }, + gesturesEnabled = true, + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(c.bg) + .windowInsetsPadding(WindowInsets.systemBars) + ) { + Column(modifier = Modifier.fillMaxSize()) { + ChatTopBar( + state = state, + onMenu = { scope.launch { drawerState.open() } }, + onSettings = { viewModel.setShowSettings(true) }, + onToggleTheme = { viewModel.toggleTheme() }, + onSelectModel = { pid, m -> viewModel.selectModel(pid, m) }, + onRename = { viewModel.renameConversation(state.currentConversation!!.id, it) }, + onClearCurrent = { viewModel.clearCurrent() }, + ) + HorizontalDivider(thickness = 1.dp, color = c.border) + ControlsBar(state = state, viewModel = viewModel) + HorizontalDivider(thickness = 1.dp, color = c.borderSoft) + MessagesArea( + modifier = Modifier.weight(1f), + state = state, + onCopy = { copyText(it, context) }, + onRegenerate = { viewModel.regenerate() }, + ) + ComposerBar( + state = state, + onSend = { viewModel.sendMessage(it) }, + onStop = { viewModel.stopStreaming() }, + ) + } + SnackbarHost( + hostState = snackbarHostState, + modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(), + ) + } + } + + if (state.showSettings) { + SettingsScreen(viewModel = viewModel, onDismiss = { viewModel.setShowSettings(false) }) + } +} + +// ===================== Top Bar ===================== + +@Composable +private fun ChatTopBar( + state: ChatUiState, + onMenu: () -> Unit, + onSettings: () -> Unit, + onToggleTheme: () -> Unit, + onSelectModel: (String, String) -> Unit, + onRename: (String) -> Unit, + onClearCurrent: () -> Unit, +) { + val c = LocalAppColors.current + var menuOpen by remember { mutableStateOf(false) } + var showRename by remember { mutableStateOf(false) } + var renameText by remember { mutableStateOf("") } + + Row( + modifier = Modifier + .fillMaxWidth() + .height(52.dp) + .padding(horizontal = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + IconButton(onClick = onMenu) { + Icon(Icons.Outlined.ChatBubbleOutline, contentDescription = "菜单", tint = c.text) + } + Text( + text = state.currentConversation?.title ?: "FengAI", + style = MaterialTheme.typography.titleMedium, + color = c.text, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f).padding(horizontal = 4.dp), + ) + // model dropdown + ModelSelector(state = state, onSelect = onSelectModel) + // overflow menu + Box { + IconButton(onClick = { menuOpen = true }) { + Icon(Icons.Filled.MoreVert, contentDescription = "更多", tint = c.textDim) + } + DropdownMenu(expanded = menuOpen, onDismissRequest = { menuOpen = false }) { + DropdownMenuItem( + text = { Text("重命名对话") }, + onClick = { + menuOpen = false + state.currentConversation?.let { renameText = it.title; showRename = true } + }, + leadingIcon = { Icon(Icons.Filled.Edit, contentDescription = null, modifier = Modifier.size(18.dp)) }, + ) + DropdownMenuItem( + text = { Text("清空当前对话") }, + onClick = { menuOpen = false; onClearCurrent() }, + leadingIcon = { Icon(Icons.Filled.Clear, contentDescription = null, modifier = Modifier.size(18.dp)) }, + ) + DropdownMenuItem( + text = { Text("设置") }, + onClick = { menuOpen = false; onSettings() }, + leadingIcon = { Icon(Icons.Filled.Settings, contentDescription = null, modifier = Modifier.size(18.dp)) }, + ) + } + } + } + + if (showRename) { + AlertDialog( + onDismissRequest = { showRename = false }, + title = { Text("重命名对话") }, + text = { + OutlinedTextField( + value = renameText, + onValueChange = { renameText = it }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + ) + }, + confirmButton = { + TextButton(onClick = { + if (renameText.isNotBlank()) onRename(renameText.trim()) + showRename = false + }) { Text("确定") } + }, + dismissButton = { TextButton(onClick = { showRename = false }) { Text("取消") } }, + ) + } +} + +@Composable +private fun ModelSelector(state: ChatUiState, onSelect: (String, String) -> Unit) { + val c = LocalAppColors.current + var expanded by remember { mutableStateOf(false) } + val allModels = remember(state.providers) { + state.providers.flatMap { p -> p.models.map { m -> p to m } } + } + + Box { + Row( + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(8.dp)) + .clickable(enabled = allModels.isNotEmpty()) { expanded = true } + .padding(horizontal = 10.dp, vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = "${state.selectedModel ?: "选择模型"}", + style = MaterialTheme.typography.labelLarge, + color = if (allModels.isEmpty()) c.textFaint else c.text, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.widthIn(max = 130.dp), + ) + Icon(Icons.Filled.ArrowDropDown, contentDescription = null, tint = c.textDim, modifier = Modifier.size(18.dp)) + } + DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { + allModels.forEach { (p, m) -> + DropdownMenuItem( + text = { Text("${p.name} / $m", style = MaterialTheme.typography.bodyMedium) }, + onClick = { + onSelect(p.id, m) + expanded = false + }, + ) + } + if (allModels.isEmpty()) { + DropdownMenuItem(text = { Text("请先配置供应商") }, onClick = { expanded = false }) + } + } + } +} + +// ===================== Controls Bar ===================== + +@Composable +private fun ControlsBar(state: ChatUiState, viewModel: ChatViewModel) { + val c = LocalAppColors.current + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + // context stepper + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(2.dp)) { + Text("上下文", style = MaterialTheme.typography.labelSmall, color = c.textDim) + StepBtn("-") { viewModel.setContextLimit(state.contextLimit - 1) } + Text( + "${state.contextLimit}", + style = MaterialTheme.typography.labelLarge, + color = c.text, + modifier = Modifier.padding(horizontal = 6.dp), + ) + StepBtn("+") { viewModel.setContextLimit(state.contextLimit + 1) } + } + HorizontalDivider(modifier = Modifier.width(1.dp).height(16.dp), color = c.borderSoft) + // thinking effort + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(2.dp)) { + Text("思考", style = MaterialTheme.typography.labelSmall, color = c.textDim) + val efforts = listOf("off" to "关闭", "high" to "增强", "max" to "深度") + efforts.forEach { (v, label) -> + val active = state.thinkingEffort == v + Box( + modifier = Modifier + .clip(RoundedCornerShape(6.dp)) + .background(if (active) c.accentBrush else SolidColor(Color.Transparent)) + .clickable { viewModel.setThinkingEffort(v) } + .padding(horizontal = 8.dp, vertical = 4.dp), + ) { + Text( + label, + style = MaterialTheme.typography.labelSmall, + color = if (active) Color.White else c.textDim, + ) + } + } + } + } +} + +@Composable +private fun StepBtn(label: String, onClick: () -> Unit) { + val c = LocalAppColors.current + Box( + modifier = Modifier + .size(24.dp) + .clip(RoundedCornerShape(6.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(6.dp)) + .clickable(onClick = onClick), + contentAlignment = Alignment.Center, + ) { + Text(label, style = MaterialTheme.typography.labelLarge, color = c.text) + } +} + +// ===================== Messages ===================== + +@Composable +private fun MessagesArea( + modifier: Modifier = Modifier, + state: ChatUiState, + onCopy: (String) -> Unit, + onRegenerate: () -> Unit, +) { + val c = LocalAppColors.current + val listState = rememberLazyListState() + val scope = rememberCoroutineScope() + val conv = state.currentConversation + val messages = conv?.messages ?: emptyList() + + val totalItems = messages.size + (if (state.isStreaming) 1 else 0) + var autoScroll by remember { mutableStateOf(true) } + + LaunchedEffect(listState) { + snapshotFlow { + val last = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: -1 + val total = listState.layoutInfo.totalItemsCount + total > 0 && last >= total - 2 + }.collect { nearBottom -> autoScroll = nearBottom } + } + + LaunchedEffect(state.streamContent, state.streamReasoning, messages.size, state.isStreaming) { + if (autoScroll && totalItems > 0) { + listState.animateScrollToItem(totalItems - 1) + } + } + + if (messages.isEmpty() && !state.isStreaming) { + EmptyState(modifier = modifier) + return + } + + Box(modifier = modifier) { + LazyColumn( + state = listState, + modifier = Modifier.fillMaxSize(), + contentPadding = androidx.compose.foundation.layout.PaddingValues(vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(20.dp), + ) { + items(messages) { msg -> + MessageItem( + msg = msg, + isLast = msg == messages.last(), + isStreaming = false, + onCopy = onCopy, + onRegenerate = onRegenerate, + ) + } + if (state.isStreaming) { + item { + StreamingMessage( + content = state.streamContent, + reasoning = state.streamReasoning, + onCopy = { onCopy(state.streamContent) }, + ) + } + } + if (state.error != null) { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .clip(RoundedCornerShape(9.dp)) + .background(c.danger.copy(alpha = 0.1f)) + .border(1.dp, c.danger, RoundedCornerShape(9.dp)) + .padding(12.dp), + ) { + Text(state.error, style = MaterialTheme.typography.bodySmall, color = c.danger) + } + } + } + } + AnimatedVisibility( + visible = !autoScroll, + enter = fadeIn(), + exit = fadeOut(), + modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp), + ) { + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .background(c.bg2) + .border(1.dp, c.border, CircleShape) + .clickable { + autoScroll = true + scope.launch { listState.animateScrollToItem(totalItems - 1) } + }, + contentAlignment = Alignment.Center, + ) { + Text("↓", color = c.text, fontSize = 18.sp) + } + } + } +} + +@Composable +private fun EmptyState(modifier: Modifier = Modifier) { + val c = LocalAppColors.current + Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Box(contentAlignment = Alignment.Center) { + // glow layer + Box(modifier = Modifier.size(108.dp).clip(CircleShape).background(c.accent.copy(alpha = 0.12f))) + // main icon + Box( + modifier = Modifier + .size(80.dp) + .clip(CircleShape) + .background(c.accentBrush), + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Filled.AutoAwesome, contentDescription = null, tint = Color.White, modifier = Modifier.size(40.dp)) + } + } + Spacer(Modifier.height(16.dp)) + Text("FengAI", style = MaterialTheme.typography.titleLarge, color = c.text, fontWeight = FontWeight.Bold) + Spacer(Modifier.height(6.dp)) + Text("选择模型,输入消息开始对话", style = MaterialTheme.typography.bodyMedium, color = c.textFaint) + } + } +} + +@Composable +private fun MessageItem( + msg: Message, + isLast: Boolean, + isStreaming: Boolean, + onCopy: (String) -> Unit, + onRegenerate: () -> Unit, +) { + val c = LocalAppColors.current + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) { + // header + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Box( + modifier = Modifier + .size(24.dp) + .clip(RoundedCornerShape(7.dp)) + .background(if (msg.role == "user") SolidColor(c.accent2) else c.accentBrush), + contentAlignment = Alignment.Center, + ) { + Icon( + if (msg.role == "user") Icons.Filled.Person else Icons.Filled.AutoAwesome, + contentDescription = null, + tint = Color.White, + modifier = Modifier.size(14.dp), + ) + } + Text( + if (msg.role == "user") "你" else "FengAI", + style = MaterialTheme.typography.labelSmall, + color = c.textDim, + ) + if (msg.role == "assistant" && isLast && !isStreaming) { + Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { + MiniBtn("复制") { onCopy(msg.content) } + MiniBtn("重新生成") { onRegenerate() } + } + } + } + Spacer(Modifier.height(6.dp)) + if (msg.reasoning.isNotBlank()) { + ReasoningCard(reasoning = msg.reasoning, isStreaming = false) + Spacer(Modifier.height(8.dp)) + } + if (msg.role == "user") { + Box( + modifier = Modifier + .clip(RoundedCornerShape(14.dp)) + .background(c.userBubble) + .padding(horizontal = 14.dp, vertical = 10.dp), + ) { + SelectionContainer { + Text(msg.content, style = MaterialTheme.typography.bodyLarge, color = c.text) + } + } + } else { + if (msg.content.isNotBlank()) { + MarkdownText(text = msg.content, modifier = Modifier.fillMaxWidth()) + } + } + msg.usage?.let { + if (it.totalTokens > 0) { + Spacer(Modifier.height(6.dp)) + Text( + "📊 输入 ${fmtTokens(it.promptTokens)} · 思考 ${fmtTokens(it.reasoningTokens)} · 输出 ${fmtTokens(it.completionTokens)} · 合计 ${fmtTokens(it.totalTokens)}", + style = MaterialTheme.typography.labelSmall.copy(fontFamily = FontFamily.Monospace), + color = c.textFaint, + ) + } + } + } +} + +@Composable +private fun StreamingMessage(content: String, reasoning: String, onCopy: () -> Unit) { + val c = LocalAppColors.current + val blink by rememberInfiniteTransition().animateFloat( + initialValue = 1f, targetValue = 0f, + animationSpec = infiniteRepeatable(tween(600), RepeatMode.Reverse), + ) + Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp)) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Box( + modifier = Modifier + .size(24.dp) + .clip(RoundedCornerShape(7.dp)) + .background(c.accentBrush), + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Filled.AutoAwesome, contentDescription = null, tint = Color.White, modifier = Modifier.size(14.dp)) + } + Text("FengAI", style = MaterialTheme.typography.labelSmall, color = c.textDim) + } + Spacer(Modifier.height(6.dp)) + if (reasoning.isNotBlank()) { + ReasoningCard(reasoning = reasoning, isStreaming = true) + Spacer(Modifier.height(8.dp)) + } + if (content.isNotBlank()) { + MarkdownText(text = content, modifier = Modifier.fillMaxWidth()) + } + Text("▋", color = c.accent, modifier = Modifier.alpha(blink), fontSize = 16.sp) + } +} + +@Composable +private fun ReasoningCard(reasoning: String, isStreaming: Boolean) { + val c = LocalAppColors.current + var collapsed by remember { mutableStateOf(false) } + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(9.dp)) + .background(c.bg3.copy(alpha = 0.5f)) + .border(1.dp, c.borderSoft, RoundedCornerShape(9.dp)), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { collapsed = !collapsed } + .padding(horizontal = 12.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(7.dp), + ) { + Box( + modifier = Modifier + .size(7.dp) + .clip(CircleShape) + .background(if (isStreaming) c.accent else c.textFaint) + .alpha(if (isStreaming) blinkPulse() else 1f), + ) + Text(if (isStreaming) "思考中…" else "思考过程", style = MaterialTheme.typography.labelSmall, color = c.reasoningText) + Text(if (collapsed) "▶" else "▼", style = MaterialTheme.typography.labelSmall, color = c.reasoningText, fontSize = 9.sp) + } + AnimatedVisibility(visible = !collapsed, enter = expandVertically(), exit = shrinkVertically()) { + Box( + modifier = Modifier + .fillMaxWidth() + .heightIn(max = 320.dp) + .verticalScroll(rememberScrollState()) + .padding(horizontal = 12.dp, vertical = 8.dp) + ) { + SelectionContainer { + Text(reasoning, style = MaterialTheme.typography.bodySmall.copy(lineHeight = 19.sp), color = c.textDim) + } + } + } + } +} + +@Composable +private fun blinkPulse(): Float { + return rememberInfiniteTransition().animateFloat( + initialValue = 0.3f, targetValue = 1f, + animationSpec = infiniteRepeatable(tween(1_400), RepeatMode.Reverse), + ).value +} + +@Composable +private fun MiniBtn(label: String, onClick: () -> Unit) { + val c = LocalAppColors.current + Box( + modifier = Modifier + .clip(RoundedCornerShape(6.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(6.dp)) + .clickable(onClick = onClick) + .padding(horizontal = 8.dp, vertical = 2.dp), + ) { + Text(label, style = MaterialTheme.typography.labelSmall, color = c.textDim) + } +} + +// ===================== Composer ===================== + +@Composable +private fun ComposerBar(state: ChatUiState, onSend: (String) -> Unit, onStop: () -> Unit) { + val c = LocalAppColors.current + var input by remember { mutableStateOf("") } + val sending = state.isStreaming + + Row( + modifier = Modifier + .fillMaxWidth() + .background(c.bg) + .padding(horizontal = 12.dp, vertical = 10.dp) + .navigationBarsPadding() + .imePadding(), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + Box( + modifier = Modifier + .weight(1f) + .clip(RoundedCornerShape(16.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(16.dp)), + ) { + BasicTextField( + value = input, + onValueChange = { input = it }, + modifier = Modifier + .fillMaxWidth() + .heightIn(min = 40.dp, max = 180.dp) + .padding(horizontal = 14.dp, vertical = 10.dp), + textStyle = TextStyle( + color = c.text, + fontSize = 15.sp, + lineHeight = 22.sp, + ), + cursorBrush = SolidColor(c.accent), + enabled = !sending, + keyboardOptions = KeyboardOptions.Default, + keyboardActions = KeyboardActions(onSend = { + if (input.isNotBlank()) { onSend(input); input = "" } + }), + decorationBox = { inner -> + if (input.isEmpty()) { + Text("输入消息…", color = c.textFaint, fontSize = 15.sp) + } + inner() + }, + ) + } + if (sending) { + Box( + modifier = Modifier + .size(44.dp) + .clip(RoundedCornerShape(12.dp)) + .background(c.danger) + .clickable(onClick = onStop), + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Filled.Stop, contentDescription = "停止", tint = Color.White) + } + } else { + Box( + modifier = Modifier + .size(44.dp) + .clip(RoundedCornerShape(12.dp)) + .background(c.accentBrush) + .shadow(6.dp, RoundedCornerShape(12.dp), clip = false) + .clickable(enabled = input.isNotBlank()) { + onSend(input); input = "" + }, + contentAlignment = Alignment.Center, + ) { + Icon(Icons.AutoMirrored.Filled.Send, contentDescription = "发送", tint = Color.White) + } + } + } +} + +// ===================== Sidebar ===================== + +@Composable +private fun SidebarContent( + state: ChatUiState, + onNewChat: () -> Unit, + onOpen: (String) -> Unit, + onDelete: (String) -> Unit, + onClearAll: () -> Unit, + onSettings: () -> Unit, + onSearch: (String) -> Unit, + onToggleTheme: () -> Unit, +) { + val c = LocalAppColors.current + ModalDrawerSheet( + drawerContainerColor = c.bg2, + drawerShape = RoundedCornerShape(0.dp), + ) { + Column(modifier = Modifier.fillMaxSize()) { + // brand + Row( + modifier = Modifier.fillMaxWidth().padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + Box( + modifier = Modifier.size(28.dp).clip(CircleShape).background(c.accentBrush), + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Filled.AutoAwesome, contentDescription = null, tint = Color.White, modifier = Modifier.size(16.dp)) + } + Text("FengAI", style = MaterialTheme.typography.titleLarge, color = c.text, fontWeight = FontWeight.Bold) + Spacer(Modifier.weight(1f)) + IconButton(onClick = onToggleTheme) { + Icon( + if (state.isDarkTheme) Icons.Filled.LightMode else Icons.Filled.DarkMode, + contentDescription = "切换主题", + tint = c.text, + ) + } + } + // new chat + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp) + .clip(RoundedCornerShape(9.dp)) + .background(c.accentBrush) + .clickable(onClick = onNewChat) + .padding(vertical = 11.dp), + contentAlignment = Alignment.Center, + ) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp)) { + Icon(Icons.Filled.Add, contentDescription = null, tint = Color.White, modifier = Modifier.size(18.dp)) + Text("新建对话", color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 14.sp) + } + } + // search + OutlinedTextField( + value = state.searchQuery, + onValueChange = onSearch, + placeholder = { Text("搜索对话…", style = MaterialTheme.typography.bodySmall) }, + modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 10.dp), + singleLine = true, + shape = RoundedCornerShape(9.dp), + textStyle = MaterialTheme.typography.bodySmall, + ) + // list + val q = state.searchQuery.trim().lowercase() + val filtered = state.conversations.filter { it.title.lowercase().contains(q) } + LazyColumn(modifier = Modifier.weight(1f).padding(horizontal = 8.dp)) { + items(filtered, key = { it.id }) { meta -> + val active = state.currentConversation?.id == meta.id + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(9.dp)) + .background(if (active) c.accent.copy(alpha = 0.12f) else Color.Transparent) + .clickable { onOpen(meta.id) } + .padding(horizontal = 10.dp, vertical = 9.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + meta.title, + style = MaterialTheme.typography.bodyMedium, + color = c.text, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Text( + timeAgo(meta.updatedAt), + style = MaterialTheme.typography.labelSmall, + color = c.textFaint, + ) + } + IconButton(onClick = { onDelete(meta.id) }, modifier = Modifier.size(28.dp)) { + Icon(Icons.Filled.DeleteOutline, contentDescription = "删除", tint = c.textFaint, modifier = Modifier.size(16.dp)) + } + } + } + if (filtered.isEmpty()) { + item { + Text( + if (state.conversations.isEmpty()) "暂无对话" else "无匹配结果", + style = MaterialTheme.typography.bodySmall, + color = c.textFaint, + modifier = Modifier.padding(16.dp), + ) + } + } + } + HorizontalDivider(color = c.border) + // footer + Column(modifier = Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) { + FooterBtn("清空全部对话", Icons.Filled.DeleteOutline, danger = true, onClick = onClearAll) + FooterBtn("供应商与模型", Icons.Filled.Settings, onClick = onSettings) + } + } + } +} + +@Composable +private fun FooterBtn(label: String, icon: androidx.compose.ui.graphics.vector.ImageVector, danger: Boolean = false, onClick: () -> Unit) { + val c = LocalAppColors.current + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(9.dp)) + .border(1.dp, c.border, RoundedCornerShape(9.dp)) + .clickable(onClick = onClick) + .padding(horizontal = 12.dp, vertical = 9.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + Icon(icon, contentDescription = null, tint = if (danger) c.danger else c.textDim, modifier = Modifier.size(16.dp)) + Text(label, style = MaterialTheme.typography.bodyMedium, color = if (danger) c.danger else c.textDim) + } +} + +// ===================== helpers ===================== + +private fun fmtTokens(n: Long): String = if (n >= 10000) "%.1fk".format(n / 1000.0) else n.toString() + +private fun timeAgo(ts: Long): String { + if (ts == 0L) return "" + val d = System.currentTimeMillis() - ts + val m = d / 60000 + if (m < 1) return "刚刚" + if (m < 60) return "${m}分钟前" + val h = m / 60 + if (h < 24) return "${h}小时前" + val day = h / 24 + if (day < 7) return "${day}天前" + val cal = java.util.Calendar.getInstance().apply { timeInMillis = ts } + return "${cal.get(java.util.Calendar.MONTH) + 1}/${cal.get(java.util.Calendar.DAY_OF_MONTH)}" +} + +private fun copyText(text: String, context: Context) { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + clipboard.setPrimaryClip(ClipData.newPlainText("message", text)) +} diff --git a/app/src/main/java/cn/flyzxf/agentapp/ui/ChatViewModel.kt b/app/src/main/java/cn/flyzxf/agentapp/ui/ChatViewModel.kt new file mode 100644 index 0000000..5ac700d --- /dev/null +++ b/app/src/main/java/cn/flyzxf/agentapp/ui/ChatViewModel.kt @@ -0,0 +1,358 @@ +package cn.flyzxf.agentapp.ui + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import cn.flyzxf.agentapp.data.ApiClient +import cn.flyzxf.agentapp.data.Conversation +import cn.flyzxf.agentapp.data.Message +import cn.flyzxf.agentapp.data.Provider +import cn.flyzxf.agentapp.data.Store +import cn.flyzxf.agentapp.data.StreamOutcome +import cn.flyzxf.agentapp.data.StreamParams +import cn.flyzxf.agentapp.data.Usage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.util.UUID + +data class ChatUiState( + val providers: List = emptyList(), + val conversations: List = emptyList(), + val currentConversation: Conversation? = null, + val selectedProviderId: String? = null, + val selectedModel: String? = null, + val isStreaming: Boolean = false, + val streamContent: String = "", + val streamReasoning: String = "", + val streamUsage: Usage? = null, + val contextLimit: Int = 6, + val thinkingEffort: String = "off", + val systemPrompt: String = "", + val isDarkTheme: Boolean = true, + val error: String? = null, + val toast: String? = null, + val searchQuery: String = "", + val showSettings: Boolean = false, + val drawerOpen: Boolean = false, +) + +class ChatViewModel(app: Application) : AndroidViewModel(app) { + + private val store = Store(app) + private val api = ApiClient() + private val prefs = app.getSharedPreferences("agentapp_prefs", android.content.Context.MODE_PRIVATE) + + private val _ui = MutableStateFlow(ChatUiState()) + val ui: StateFlow = _ui.asStateFlow() + + private var streamJob: Job? = null + + init { + loadPrefs() + loadAll() + } + + // ---------- prefs ---------- + private fun loadPrefs() { + _ui.update { + it.copy( + isDarkTheme = prefs.getBoolean("dark", false), + contextLimit = prefs.getInt("ctx", 6), + thinkingEffort = prefs.getString("effort", "off") ?: "off", + systemPrompt = prefs.getString("system", "") ?: "", + ) + } + } + + fun toggleTheme() { + val next = !_ui.value.isDarkTheme + prefs.edit().putBoolean("dark", next).apply() + _ui.update { it.copy(isDarkTheme = next) } + } + + fun setContextLimit(v: Int) { + val clamped = v.coerceIn(0, 50) + prefs.edit().putInt("ctx", clamped).apply() + _ui.update { it.copy(contextLimit = clamped) } + } + + fun setThinkingEffort(v: String) { + prefs.edit().putString("effort", v).apply() + _ui.update { it.copy(thinkingEffort = v) } + } + + fun setSystemPrompt(v: String) { + prefs.edit().putString("system", v).apply() + _ui.update { it.copy(systemPrompt = v) } + } + + fun setSearchQuery(v: String) = _ui.update { it.copy(searchQuery = v) } + fun setDrawerOpen(v: Boolean) = _ui.update { it.copy(drawerOpen = v) } + fun setShowSettings(v: Boolean) = _ui.update { it.copy(showSettings = v) } + fun clearToast() = _ui.update { it.copy(toast = null) } + fun clearError() = _ui.update { it.copy(error = null) } + + private fun toast(msg: String) = _ui.update { it.copy(toast = msg) } + + // ---------- load ---------- + fun loadAll() { + val providers = store.getProviders() + val convs = store.getConversationList() + val selPid = _ui.value.selectedProviderId ?: providers.firstOrNull()?.id + val selModel = _ui.value.selectedModel + ?: providers.firstOrNull()?.models?.firstOrNull() + _ui.update { + it.copy( + providers = providers, + conversations = convs, + selectedProviderId = selPid, + selectedModel = selModel, + ) + } + } + + fun refreshConversations() { + _ui.update { it.copy(conversations = store.getConversationList()) } + } + + // ---------- conversations ---------- + fun newConversation() { + if (_ui.value.isStreaming) stopStreaming() + val conv = Conversation( + id = UUID.randomUUID().toString(), + title = "新对话", + messages = emptyList(), + ) + _ui.update { + it.copy( + currentConversation = conv, + drawerOpen = false, + ) + } + } + + fun openConversation(id: String) { + val conv = store.getConversation(id) ?: return + if (conv.providerId != null && conv.model != null) { + _ui.update { + it.copy( + currentConversation = conv, + selectedProviderId = conv.providerId, + selectedModel = conv.model, + drawerOpen = false, + ) + } + } else { + _ui.update { it.copy(currentConversation = conv, drawerOpen = false) } + } + } + + fun deleteConversation(id: String) { + store.deleteConversation(id) + if (_ui.value.currentConversation?.id == id) { + _ui.update { it.copy(currentConversation = null) } + } + refreshConversations() + } + + fun renameConversation(id: String, title: String) { + store.renameConversation(id, title) + _ui.value.currentConversation?.let { + if (it.id == id) _ui.update { s -> s.copy(currentConversation = it.copy(title = title)) } + } + refreshConversations() + } + + fun clearAll() { + if (_ui.value.conversations.isEmpty()) { toast("暂无对话"); return } + if (_ui.value.isStreaming) stopStreaming() + store.clearAllConversations() + _ui.update { it.copy(currentConversation = null) } + refreshConversations() + toast("已清空全部对话") + } + + fun clearCurrent() { + val conv = _ui.value.currentConversation ?: return + store.saveConversation(conv.copy(title = "新对话", messages = emptyList())) + _ui.update { it.copy(currentConversation = conv.copy(title = "新对话", messages = emptyList())) } + refreshConversations() + toast("已清空当前对话") + } + + // ---------- model selection ---------- + fun selectModel(providerId: String, model: String) { + _ui.update { it.copy(selectedProviderId = providerId, selectedModel = model) } + _ui.value.currentConversation?.let { conv -> + val updated = conv.copy(providerId = providerId, model = model) + store.saveConversation(updated) + _ui.update { it.copy(currentConversation = updated) } + } + } + + // ---------- send / stream ---------- + fun sendMessage(text: String) { + if (_ui.value.isStreaming) return + val trimmedText = text.trim() + if (trimmedText.isEmpty()) return + val sel = getSelectedProvider() + if (sel == null) { toast("请先配置供应商和模型"); return } + val (provider, model) = sel + + var conv = _ui.value.currentConversation ?: Conversation( + id = UUID.randomUUID().toString(), + title = "新对话", + ) + val userMsg = Message(role = "user", content = trimmedText) + conv = conv.copy( + messages = conv.messages + userMsg, + providerId = provider.id, + model = model, + ) + if (conv.messages.count { it.role == "user" } == 1) { + conv = conv.copy(title = makeTitle(trimmedText)) + } + store.saveConversation(conv) + _ui.update { + it.copy( + currentConversation = conv, + isStreaming = true, + streamContent = "", + streamReasoning = "", + streamUsage = null, + error = null, + conversations = store.getConversationList(), + ) + } + startStream(conv, provider, model) + } + + private fun startStream(conv: Conversation, provider: Provider, model: String) { + streamJob = viewModelScope.launch { + val s = _ui.value + val sys = s.systemPrompt.trim().let { if (it.isNotEmpty()) listOf(mapOf("role" to "system", "content" to it)) else emptyList() } + val history = conv.messages + val limited = if (s.contextLimit > 0) history.takeLast(s.contextLimit) else history + val apiMessages = sys + limited.map { mapOf("role" to it.role, "content" to it.content) } + + val params = StreamParams( + baseURL = provider.baseURL, + apiKey = provider.apiKey, + model = model, + messages = apiMessages, + enableThinking = s.thinkingEffort != "off", + reasoningEffort = if (s.thinkingEffort != "off") s.thinkingEffort else null, + maxTokens = provider.maxTokens, + ) + + try { + api.streamChat( + params = params, + onChunk = { content, reasoning -> + if (content.isNotEmpty()) _ui.update { it.copy(streamContent = it.streamContent + content) } + if (reasoning.isNotEmpty()) _ui.update { it.copy(streamReasoning = it.streamReasoning + reasoning) } + }, + onUsage = { u -> _ui.update { it.copy(streamUsage = u) } }, + ) + finalizeStream(aborted = false, conv) + } catch (e: kotlinx.coroutines.CancellationException) { + withContext(Dispatchers.IO + NonCancellable) { finalizeStream(aborted = true, conv) } + throw e + } catch (e: Exception) { + finalizeStream(aborted = true, conv) + _ui.update { it.copy(error = e.message ?: "请求失败", toast = "请求失败:${e.message ?: "未知错误"}") } + } + } + } + + private fun finalizeStream(aborted: Boolean, conv: Conversation) { + val s = _ui.value + val content = s.streamContent + val reasoning = s.streamReasoning + val usage = s.streamUsage + val updated = if (content.isBlank() && reasoning.isBlank()) { + conv + } else { + conv.copy(messages = conv.messages + Message(role = "assistant", content = content, reasoning = reasoning, usage = usage)) + } + store.saveConversation(updated) + _ui.update { + it.copy( + currentConversation = updated, + isStreaming = false, + streamContent = "", + streamReasoning = "", + streamUsage = null, + conversations = store.getConversationList(), + ) + } + } + + fun stopStreaming() { + streamJob?.cancel() + } + + fun regenerate() { + if (_ui.value.isStreaming) return + val conv = _ui.value.currentConversation ?: return + if (conv.messages.isEmpty()) return + val sel = getSelectedProvider() ?: run { toast("请先配置供应商和模型"); return } + val (provider, model) = sel + var msgs = conv.messages + if (msgs.lastOrNull()?.role == "assistant") msgs = msgs.dropLast(1) + if (msgs.isEmpty() || msgs.last().role != "user") { toast("没有可重新生成的消息"); return } + val updated = conv.copy(messages = msgs) + store.saveConversation(updated) + _ui.update { it.copy(currentConversation = updated, isStreaming = true, streamContent = "", streamReasoning = "", streamUsage = null) } + startStream(updated, provider, model) + } + + // ---------- providers ---------- + fun saveProvider(p: Provider): Provider { + val saved = store.saveProvider(p) + loadAll() + return saved + } + + fun deleteProvider(id: String) { + store.deleteProvider(id) + loadAll() + } + + fun testProvider(provider: Provider, onResult: (ok: Boolean, models: List, error: String) -> Unit) { + viewModelScope.launch { + try { + val models = api.fetchModels(provider.baseURL, provider.apiKey) + onResult(true, models, "") + } catch (e: Exception) { + onResult(false, emptyList(), e.message ?: "连接失败") + } + } + } + + // ---------- helpers ---------- + private fun getSelectedProvider(): Pair? { + val s = _ui.value + val pid = s.selectedProviderId ?: return null + val model = s.selectedModel ?: return null + val provider = s.providers.firstOrNull { it.id == pid } ?: return null + return provider to model + } + + private fun makeTitle(text: String): String { + val t = text.replace(Regex("\\s+"), " ").trim() + return if (t.length > 18) t.take(18) else (if (t.isEmpty()) "新对话" else t) + } + + override fun onCleared() { + super.onCleared() + streamJob?.cancel() + } +} diff --git a/app/src/main/java/cn/flyzxf/agentapp/ui/SettingsScreen.kt b/app/src/main/java/cn/flyzxf/agentapp/ui/SettingsScreen.kt new file mode 100644 index 0000000..27915d6 --- /dev/null +++ b/app/src/main/java/cn/flyzxf/agentapp/ui/SettingsScreen.kt @@ -0,0 +1,367 @@ +package cn.flyzxf.agentapp.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import cn.flyzxf.agentapp.data.Provider +import cn.flyzxf.agentapp.ui.theme.LocalAppColors + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingsScreen(viewModel: ChatViewModel, onDismiss: () -> Unit) { + val state by viewModel.ui.collectAsStateWithLifecycle() + val c = LocalAppColors.current + + var editingId by remember { mutableStateOf(state.providers.firstOrNull()?.id ?: "") } + var name by remember { mutableStateOf("") } + var baseURL by remember { mutableStateOf("") } + var apiKey by remember { mutableStateOf("") } + var models by remember { mutableStateOf("") } + var maxTokens by remember { mutableStateOf("") } + var systemPrompt by remember { mutableStateOf(state.systemPrompt) } + var showKey by remember { mutableStateOf(false) } + var testMsg by remember { mutableStateOf("") } + var testOk by remember { mutableStateOf(null) } + var showDeleteConfirm by remember { mutableStateOf(false) } + + fun loadProvider(id: String) { + val p = state.providers.firstOrNull { it.id == id } + name = p?.name ?: "" + baseURL = p?.baseURL ?: "" + apiKey = p?.apiKey ?: "" + models = p?.models?.joinToString("\n") ?: "" + maxTokens = if (p != null && p.maxTokens > 0) p.maxTokens.toString() else "" + testMsg = "" + testOk = null + } + + LaunchedEffect(editingId) { if (editingId.isNotEmpty()) loadProvider(editingId) } + LaunchedEffect(state.providers) { + if (editingId.isEmpty() && state.providers.isNotEmpty()) { + editingId = state.providers.first().id + } + } + + fun buildProvider(): Provider = Provider( + id = editingId, + name = name.trim().ifEmpty { "(未命名)" }, + baseURL = baseURL.trim(), + apiKey = apiKey.trim(), + models = models.split("\n", ",").map { it.trim() }.filter { it.isNotEmpty() }, + maxTokens = maxTokens.trim().toLongOrNull() ?: 0, + ) + + Box( + modifier = Modifier + .fillMaxSize() + .background(c.bg) + .windowInsetsPadding(WindowInsets.systemBars) + .imePadding(), + ) { + Column(modifier = Modifier.fillMaxSize()) { + // top bar + Row( + modifier = Modifier.fillMaxWidth().height(52.dp).padding(horizontal = 4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + IconButton(onClick = onDismiss) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "返回", tint = c.text) + } + Text("供应商与模型", style = MaterialTheme.typography.titleMedium, color = c.text, modifier = Modifier.weight(1f)) + } + + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 16.dp) + .navigationBarsPadding(), + ) { + // provider selector row + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + ProviderDropdown( + providers = state.providers, + selectedId = editingId, + onSelect = { editingId = it }, + modifier = Modifier.weight(1f), + ) + Box( + modifier = Modifier + .size(40.dp) + .clip(RoundedCornerShape(9.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(9.dp)) + .clickable { + editingId = "" + name = ""; baseURL = ""; apiKey = ""; models = ""; maxTokens = "" + testMsg = ""; testOk = null + }, + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Filled.Add, contentDescription = "新建", tint = c.text) + } + Box( + modifier = Modifier + .size(40.dp) + .clip(RoundedCornerShape(9.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(9.dp)) + .clickable(enabled = editingId.isNotEmpty()) { showDeleteConfirm = true }, + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Filled.Delete, contentDescription = "删除", tint = if (editingId.isNotEmpty()) c.danger else c.textFaint) + } + } + + Spacer(Modifier.height(16.dp)) + FieldLabel("供应商名称") + FieldInput(name, { name = it }, "GLM5.1") + Spacer(Modifier.height(12.dp)) + + FieldLabel("API 地址(自动拼接 /chat/completions)") + FieldInput(baseURL, { baseURL = it }, "https://ark.cn-beijing.volces.com/api/coding/v3") + Spacer(Modifier.height(12.dp)) + + FieldLabel("密钥") + OutlinedTextField( + value = apiKey, + onValueChange = { apiKey = it }, + modifier = Modifier.fillMaxWidth(), + singleLine = true, + shape = RoundedCornerShape(9.dp), + textStyle = MaterialTheme.typography.bodyMedium, + placeholder = { Text("sk-…", style = MaterialTheme.typography.bodyMedium, color = c.textFaint) }, + visualTransformation = if (showKey) VisualTransformation.None else PasswordVisualTransformation(), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + trailingIcon = { + TextButton(onClick = { showKey = !showKey }) { + Text(if (showKey) "隐藏" else "显示", style = MaterialTheme.typography.labelSmall) + } + }, + ) + Spacer(Modifier.height(12.dp)) + + // test & fetch + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(10.dp), + ) { + Row( + modifier = Modifier + .clip(RoundedCornerShape(9.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(9.dp)) + .clickable { + testMsg = "测试中…"; testOk = null + viewModel.testProvider(buildProvider()) { ok, modelsList, err -> + if (ok) { + testOk = true + testMsg = if (modelsList.isNotEmpty()) { + "连接成功,发现 ${modelsList.size} 个模型" + } else "连接成功,未返回模型列表" + if (modelsList.isNotEmpty()) models = modelsList.joinToString("\n") + } else { + testOk = false + testMsg = "失败:$err" + } + } + } + .padding(horizontal = 14.dp, vertical = 9.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(6.dp), + ) { + Icon(Icons.Filled.Refresh, contentDescription = null, tint = c.text, modifier = Modifier.size(16.dp)) + Text("测试并获取模型", style = MaterialTheme.typography.labelLarge, color = c.text) + } + testMsg.takeIf { it.isNotEmpty() }?.let { + Text( + it, + style = MaterialTheme.typography.labelSmall, + color = when (testOk) { + true -> Color(0xFF3EC77A) + false -> c.danger + else -> c.textDim + }, + modifier = Modifier.weight(1f), + ) + } + } + Spacer(Modifier.height(12.dp)) + + FieldLabel("模型列表(每行一个,或逗号分隔)") + FieldInput( + models, { models = it }, "glm-5.2\nkimi-k2.6\ndeepseek-v4-pro", + singleLine = false, minLines = 4, + ) + Spacer(Modifier.height(12.dp)) + + FieldLabel("最大输出 tokens(留空=不限制;GLM-5.2 可填 131072)") + FieldInput(maxTokens, { maxTokens = it.filter { ch -> ch.isDigit() } }, "131072", keyboardType = KeyboardType.Number) + Spacer(Modifier.height(12.dp)) + + // save button + Box( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(9.dp)) + .background(c.accentBrush) + .clickable { + val saved = viewModel.saveProvider(buildProvider()) + editingId = saved.id + testMsg = "已保存"; testOk = true + } + .padding(vertical = 12.dp), + contentAlignment = Alignment.Center, + ) { + Text("保存供应商", color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 14.sp) + } + Spacer(Modifier.height(20.dp)) + + FieldLabel("系统提示词(可选,对所有对话生效)") + FieldInput( + systemPrompt, + { systemPrompt = it; viewModel.setSystemPrompt(it) }, + "你是一个乐于助人的助手…", + singleLine = false, minLines = 3, + ) + Spacer(Modifier.height(24.dp)) + } + } + } + + if (showDeleteConfirm) { + AlertDialog( + onDismissRequest = { showDeleteConfirm = false }, + title = { Text("删除供应商") }, + text = { Text("确定删除该供应商配置吗?") }, + confirmButton = { + TextButton(onClick = { + if (editingId.isNotEmpty()) viewModel.deleteProvider(editingId) + showDeleteConfirm = false + editingId = state.providers.firstOrNull()?.id ?: "" + }) { Text("删除") } + }, + dismissButton = { TextButton(onClick = { showDeleteConfirm = false }) { Text("取消") } }, + ) + } +} + +@Composable +private fun ProviderDropdown(providers: List, selectedId: String, onSelect: (String) -> Unit, modifier: Modifier = Modifier) { + val c = LocalAppColors.current + var expanded by remember { mutableStateOf(false) } + val selected = providers.firstOrNull { it.id == selectedId } + Box(modifier = modifier) { + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(9.dp)) + .background(c.bg3) + .border(1.dp, c.borderSoft, RoundedCornerShape(9.dp)) + .clickable { expanded = true } + .padding(horizontal = 12.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + selected?.name ?: "选择供应商", + style = MaterialTheme.typography.bodyMedium, + color = if (selected == null) c.textFaint else c.text, + modifier = Modifier.weight(1f), + ) + Text("▾", color = c.textDim, fontSize = 12.sp) + } + DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { + providers.forEach { p -> + DropdownMenuItem(text = { Text(p.name) }, onClick = { onSelect(p.id); expanded = false }) + } + if (providers.isEmpty()) { + DropdownMenuItem(text = { Text("暂无供应商") }, onClick = { expanded = false }) + } + } + } +} + +@Composable +private fun FieldLabel(text: String) { + val c = LocalAppColors.current + Text(text, style = MaterialTheme.typography.labelSmall, color = c.textDim, modifier = Modifier.padding(bottom = 4.dp)) +} + +@Composable +private fun FieldInput( + value: String, + onValueChange: (String) -> Unit, + placeholder: String, + singleLine: Boolean = true, + minLines: Int = 1, + keyboardType: KeyboardType = KeyboardType.Text, +) { + val c = LocalAppColors.current + OutlinedTextField( + value = value, + onValueChange = onValueChange, + modifier = Modifier.fillMaxWidth(), + singleLine = singleLine, + minLines = minLines, + shape = RoundedCornerShape(9.dp), + textStyle = MaterialTheme.typography.bodyMedium, + placeholder = { Text(placeholder, style = MaterialTheme.typography.bodyMedium, color = c.textFaint) }, + keyboardOptions = KeyboardOptions(keyboardType = keyboardType), + ) +} diff --git a/app/src/main/java/cn/flyzxf/agentapp/ui/components/MarkdownText.kt b/app/src/main/java/cn/flyzxf/agentapp/ui/components/MarkdownText.kt new file mode 100644 index 0000000..3a66e08 --- /dev/null +++ b/app/src/main/java/cn/flyzxf/agentapp/ui/components/MarkdownText.kt @@ -0,0 +1,278 @@ +package cn.flyzxf.agentapp.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.ClickableText +import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import cn.flyzxf.agentapp.ui.theme.AppColors +import cn.flyzxf.agentapp.ui.theme.LocalAppColors + +private sealed class MdBlock { + data class Paragraph(val text: String) : MdBlock() + data class Header(val level: Int, val text: String) : MdBlock() + data class Code(val lang: String, val code: String) : MdBlock() + data class ListItem(val ordered: Boolean, val index: Int, val text: String) : MdBlock() + data class Quote(val text: String) : MdBlock() + data object Hr : MdBlock() +} + +private enum class Inline { NORMAL, BOLD, ITALIC, CODE, STRIKE, LINK } + +private val inlineRegex = Regex( + """`([^`]+)`|\*\*(.+?)\*\*|\*([^*\n]+?)\*|__(.+?)__|~~(.+?)~~|\[([^\]]+)\]\(([^)]+)\)""" +) + +private fun tokenizeInline(input: String): List> { + val result = mutableListOf>() + var lastEnd = 0 + for (m in inlineRegex.findAll(input)) { + if (m.range.first > lastEnd) result.add(input.substring(lastEnd, m.range.first) to Inline.NORMAL) + val g = m.groupValues + when { + g[1].isNotEmpty() -> result.add(g[1] to Inline.CODE) + g[2].isNotEmpty() -> result.add(g[2] to Inline.BOLD) + g[3].isNotEmpty() -> result.add(g[3] to Inline.ITALIC) + g[4].isNotEmpty() -> result.add(g[4] to Inline.ITALIC) + g[5].isNotEmpty() -> result.add(g[5] to Inline.STRIKE) + g[6].isNotEmpty() -> result.add(g[6] to Inline.LINK) + } + lastEnd = m.range.last + 1 + } + if (lastEnd < input.length) result.add(input.substring(lastEnd) to Inline.NORMAL) + if (result.isEmpty()) result.add(input to Inline.NORMAL) + return result +} + +private fun buildInline(text: String, c: AppColors): AnnotatedString = buildAnnotatedString { + for ((chunk, style) in tokenizeInline(text)) { + when (style) { + Inline.NORMAL -> append(chunk) + Inline.BOLD -> withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(chunk) } + Inline.ITALIC -> withStyle(SpanStyle(fontStyle = FontStyle.Italic)) { append(chunk) } + Inline.CODE -> withStyle( + SpanStyle( + fontFamily = FontFamily.Monospace, + background = c.codeBg, + color = c.accent2, + fontSize = 13.sp, + ) + ) { append(" $chunk ") } + Inline.STRIKE -> withStyle(SpanStyle(textDecoration = androidx.compose.ui.text.style.TextDecoration.LineThrough)) { append(chunk) } + Inline.LINK -> { + pushStringAnnotation(tag = "URL", annotation = chunk) + withStyle(SpanStyle(color = c.accent2, fontWeight = FontWeight.Medium)) { append(chunk) } + pop() + } + } + } +} + +private fun parseMarkdown(raw: String): List { + val blocks = mutableListOf() + val lines = raw.split("\n") + var i = 0 + while (i < lines.size) { + val line = lines[i] + val trimmed = line.trim() + when { + trimmed.startsWith("```") -> { + val lang = trimmed.removePrefix("```").trim() + val sb = StringBuilder() + i++ + while (i < lines.size && !lines[i].trim().startsWith("```")) { + sb.appendLine(lines[i]) + i++ + } + if (i < lines.size) i++ + blocks.add(MdBlock.Code(lang, sb.toString().trimEnd('\n'))) + } + trimmed.matches(Regex("^#{1,6}\\s.+")) -> { + val level = trimmed.takeWhile { it == '#' }.length + val txt = trimmed.drop(level).trim() + blocks.add(MdBlock.Header(level, txt)) + i++ + } + trimmed.matches(Regex("^([-*]){3,}$")) -> { + blocks.add(MdBlock.Hr) + i++ + } + trimmed.startsWith("- ") || trimmed.startsWith("* ") -> { + blocks.add(MdBlock.ListItem(false, 0, trimmed.drop(2).trim())) + i++ + } + trimmed.matches(Regex("^\\d+\\..+")) -> { + val num = trimmed.takeWhile { it.isDigit() }.toIntOrNull() ?: 1 + val txt = trimmed.substringAfter(".").trim() + blocks.add(MdBlock.ListItem(true, num, txt)) + i++ + } + trimmed.startsWith("> ") -> { + val sb = StringBuilder(trimmed.drop(2)) + i++ + while (i < lines.size && lines[i].trim().startsWith("> ")) { + sb.append("\n").append(lines[i].trim().drop(2)) + i++ + } + blocks.add(MdBlock.Quote(sb.toString())) + } + trimmed.isEmpty() -> i++ + else -> { + val sb = StringBuilder(line) + i++ + while (i < lines.size && lines[i].trim().isNotEmpty() && + !lines[i].trimStart().startsWith("#") && + !lines[i].trimStart().startsWith("- ") && + !lines[i].trimStart().startsWith("* ") && + !lines[i].trimStart().startsWith("```") && + !lines[i].trimStart().startsWith("> ") && + !lines[i].trim().matches(Regex("^\\d+\\..+")) && + !lines[i].trim().matches(Regex("^([-*]){3,}$")) + ) { + sb.append("\n").append(lines[i]) + i++ + } + blocks.add(MdBlock.Paragraph(sb.toString())) + } + } + } + return blocks +} + +@Composable +fun MarkdownText( + text: String, + modifier: Modifier = Modifier, +) { + val c = LocalAppColors.current + val blocks = remember(text) { parseMarkdown(text) } + val uriHandler = LocalUriHandler.current + SelectionContainer { + Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(8.dp)) { + for (block in blocks) { + when (block) { + is MdBlock.Paragraph -> { + val styled = remember(block.text) { buildInline(block.text, c) } + ClickableText( + text = styled, + modifier = Modifier.fillMaxWidth(), + onClick = { offset -> + styled.getStringAnnotations("URL", offset, offset) + .firstOrNull()?.let { uriHandler.openUri(it.item) } + }, + style = androidx.compose.material3.MaterialTheme.typography.bodyLarge.copy( + color = c.text, lineHeight = 24.sp + ), + ) + } + is MdBlock.Header -> { + val styled = remember(block.text) { buildInline(block.text, c) } + val size = when { + block.level <= 1 -> 24.sp + block.level == 2 -> 21.sp + block.level == 3 -> 18.sp + else -> 16.sp + } + Text( + text = styled, + fontSize = size, + fontWeight = FontWeight.Bold, + color = c.text, + modifier = Modifier.padding(top = 4.dp), + ) + } + is MdBlock.Code -> { + Box( + modifier = Modifier + .fillMaxWidth() + .background(c.codeBg, RoundedCornerShape(10.dp)) + .border(1.dp, c.borderSoft, RoundedCornerShape(10.dp)) + .padding(14.dp) + ) { + Text( + text = block.code, + fontFamily = FontFamily.Monospace, + fontSize = 13.sp, + lineHeight = 18.sp, + color = c.text, + ) + } + } + is MdBlock.ListItem -> { + Row(modifier = Modifier.fillMaxWidth()) { + Text( + text = if (block.ordered) "${block.index}. " else "• ", + color = c.accent, + fontWeight = FontWeight.Bold, + modifier = Modifier.width(22.dp), + ) + val styled = remember(block.text) { buildInline(block.text, c) } + Text( + text = styled, + color = c.text, + modifier = Modifier.weight(1f), + style = androidx.compose.material3.MaterialTheme.typography.bodyLarge.copy(lineHeight = 24.sp), + ) + } + } + is MdBlock.Quote -> { + val styled = remember(block.text) { buildInline(block.text, c) } + Box( + modifier = Modifier + .fillMaxWidth() + .background(c.bg3, RoundedCornerShape(0.dp, 8.dp, 8.dp, 0.dp)) + .padding(start = 14.dp, end = 12.dp, top = 8.dp, bottom = 8.dp) + ) { + Row { + Box( + modifier = Modifier + .width(3.dp) + .height(18.dp) + .background(c.accent, RoundedCornerShape(3.dp)) + .align(Alignment.CenterVertically) + ) + Text( + text = styled, + color = c.textDim, + modifier = Modifier.padding(start = 12.dp), + ) + } + } + } + is MdBlock.Hr -> HorizontalDivider( + modifier = Modifier.padding(vertical = 4.dp), + thickness = 1.dp, + color = c.border, + ) + } + } + } + } +} diff --git a/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Color.kt b/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Color.kt index 74e96ab..5ca2436 100644 --- a/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Color.kt +++ b/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Color.kt @@ -2,10 +2,42 @@ package cn.flyzxf.agentapp.ui.theme import androidx.compose.ui.graphics.Color -val Purple80 = Color(0xFFD0BCFF) -val PurpleGrey80 = Color(0xFFCCC2DC) -val Pink80 = Color(0xFFEFB8C8) +// ============ Light (default) — clean, high-contrast, tech ============ +val LightBg = Color(0xFFEFF1F8) +val LightBg2 = Color(0xFFFFFFFF) +val LightBg3 = Color(0xFFE4E8F4) +val LightBg4 = Color(0xFFD8DCEC) +val LightSurface = Color(0xFFFFFFFF) +val LightBorder = Color(0xFFD0D5E5) +val LightBorderSoft = Color(0xFFE4E8F4) +val LightText = Color(0xFF1A1D2E) +val LightTextDim = Color(0xFF545978) +val LightTextFaint = Color(0xFF9095AC) +val LightAccent = Color(0xFF6C5CE7) +val LightAccent2 = Color(0xFF00B4D8) +val LightDanger = Color(0xFFFF3B5C) +val LightUserBubble = Color(0xFFEEF0FF) +val LightCodeBg = Color(0xFFF2F4FA) +val LightReasoning = Color(0xFF6C5CE7) -val Purple40 = Color(0xFF6650a4) -val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +// ============ Dark — soft navy, NOT pure black ============ +val DarkBg = Color(0xFF15172A) +val DarkBg2 = Color(0xFF1D1F36) +val DarkBg3 = Color(0xFF272A45) +val DarkBg4 = Color(0xFF313555) +val DarkSurface = Color(0xFF1D1F36) +val DarkBorder = Color(0xFF353960) +val DarkBorderSoft = Color(0xFF272A45) +val DarkText = Color(0xFFEDF0F8) +val DarkTextDim = Color(0xFFA8AECF) +val DarkTextFaint = Color(0xFF6D7295) +val DarkAccent = Color(0xFF8B7FF2) +val DarkAccent2 = Color(0xFF2ED3F7) +val DarkDanger = Color(0xFFFF5B7A) +val DarkUserBubble = Color(0xFF2C2F50) +val DarkCodeBg = Color(0xFF111220) +val DarkReasoning = Color(0xFFB4A7FF) + +// ============ Gradient (shared) ============ +val AccentGradientStart = Color(0xFF6C5CE7) +val AccentGradientEnd = Color(0xFF00B4D8) diff --git a/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Theme.kt b/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Theme.kt index 146edda..a75ac55 100644 --- a/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Theme.kt +++ b/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Theme.kt @@ -1,58 +1,117 @@ package cn.flyzxf.agentapp.ui.theme import android.app.Activity -import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat -private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 +@Immutable +data class AppColors( + val bg: Color, + val bg2: Color, + val bg3: Color, + val bg4: Color, + val surface: Color, + val border: Color, + val borderSoft: Color, + val text: Color, + val textDim: Color, + val textFaint: Color, + val accent: Color, + val accent2: Color, + val danger: Color, + val userBubble: Color, + val codeBg: Color, + val reasoningText: Color, +) { + val accentBrush: Brush + get() = Brush.linearGradient(listOf(AccentGradientStart, AccentGradientEnd)) +} + +val LocalAppColors = compositionLocalOf { + error("AppColors not provided") +} + +val DarkAppColors = AppColors( + bg = DarkBg, bg2 = DarkBg2, bg3 = DarkBg3, bg4 = DarkBg4, + surface = DarkSurface, border = DarkBorder, borderSoft = DarkBorderSoft, + text = DarkText, textDim = DarkTextDim, textFaint = DarkTextFaint, + accent = DarkAccent, accent2 = DarkAccent2, danger = DarkDanger, + userBubble = DarkUserBubble, codeBg = DarkCodeBg, reasoningText = DarkReasoning, ) -private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ +val LightAppColors = AppColors( + bg = LightBg, bg2 = LightBg2, bg3 = LightBg3, bg4 = LightBg4, + surface = LightSurface, border = LightBorder, borderSoft = LightBorderSoft, + text = LightText, textDim = LightTextDim, textFaint = LightTextFaint, + accent = LightAccent, accent2 = LightAccent2, danger = LightDanger, + userBubble = LightUserBubble, codeBg = LightCodeBg, reasoningText = LightReasoning, ) @Composable -fun AgentAppTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, - content: @Composable () -> Unit +fun AppTheme( + darkTheme: Boolean, + content: @Composable () -> Unit, ) { - val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - - darkTheme -> DarkColorScheme - else -> LightColorScheme + val appColors = if (darkTheme) DarkAppColors else LightAppColors + val scheme = if (darkTheme) { + darkColorScheme( + primary = appColors.accent, + onPrimary = Color.White, + secondary = appColors.accent2, + background = appColors.bg, + onBackground = appColors.text, + surface = appColors.surface, + onSurface = appColors.text, + surfaceVariant = appColors.bg3, + onSurfaceVariant = appColors.textDim, + outline = appColors.border, + error = appColors.danger, + ) + } else { + lightColorScheme( + primary = appColors.accent, + onPrimary = Color.White, + secondary = appColors.accent2, + background = appColors.bg, + onBackground = appColors.text, + surface = appColors.surface, + onSurface = appColors.text, + surfaceVariant = appColors.bg3, + onSurfaceVariant = appColors.textDim, + outline = appColors.border, + error = appColors.danger, + ) } - MaterialTheme( - colorScheme = colorScheme, - typography = Typography, - content = content - ) -} \ No newline at end of file + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = Color.Transparent.toArgb() + window.navigationBarColor = Color.Transparent.toArgb() + val controller = WindowCompat.getInsetsController(window, view) + controller.isAppearanceLightStatusBars = !darkTheme + controller.isAppearanceLightNavigationBars = !darkTheme + } + } + + CompositionLocalProvider(LocalAppColors provides appColors) { + MaterialTheme( + colorScheme = scheme, + typography = AppTypography, + content = content, + ) + } +} diff --git a/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Type.kt b/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Type.kt index dcc004a..b3c2cec 100644 --- a/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Type.kt +++ b/app/src/main/java/cn/flyzxf/agentapp/ui/theme/Type.kt @@ -6,29 +6,47 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -// Set of Material typography styles to start with -val Typography = Typography( +val AppTypography = Typography( bodyLarge = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp - ) - /* Other default text styles to override - titleLarge = TextStyle( + fontSize = 15.sp, + lineHeight = 23.sp, + ), + bodyMedium = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp + fontSize = 14.sp, + lineHeight = 21.sp, + ), + bodySmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp, + lineHeight = 17.sp, + ), + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.SemiBold, + fontSize = 18.sp, + lineHeight = 24.sp, + ), + titleMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.SemiBold, + fontSize = 16.sp, + lineHeight = 22.sp, + ), + labelLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.SemiBold, + fontSize = 14.sp, + lineHeight = 20.sp, ), labelSmall = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Medium, fontSize = 11.sp, - lineHeight = 16.sp, - letterSpacing = 0.5.sp - ) - */ -) \ No newline at end of file + lineHeight = 15.sp, + ), +) diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 07d5da9..161b62e 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,170 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 2b068d1..d7c220f 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,30 +1,15 @@ + - - - - - - - - + - \ No newline at end of file + android:pathData="M54,26 C57,42 66,51 82,54 C66,57 57,66 54,82 C51,66 42,57 26,54 C42,51 51,42 54,26 Z" /> + + + diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml new file mode 100644 index 0000000..6855742 --- /dev/null +++ b/app/src/main/res/values-night/colors.xml @@ -0,0 +1,4 @@ + + + #FF15172A + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f8c6127..638ee55 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,10 +1,6 @@ - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 + #FFEFF1F8 #FF000000 #FFFFFFFF - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 60e7927..19c174c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - agentApp + FengAI \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 4d49d3e..939ed53 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,5 +1,9 @@ - - + diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..8a76775 --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/build-fix.txt b/build-fix.txt new file mode 100644 index 0000000..ce68bc2 --- /dev/null +++ b/build-fix.txt @@ -0,0 +1,46 @@ +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :app:preBuild UP-TO-DATE +> Task :app:preDebugBuild UP-TO-DATE +> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE +> Task :app:generateDebugResources UP-TO-DATE +> Task :app:packageDebugResources UP-TO-DATE +> Task :app:processDebugNavigationResources UP-TO-DATE +> Task :app:parseDebugLocalResources UP-TO-DATE +> Task :app:generateDebugRFile UP-TO-DATE +> Task :app:javaPreCompileDebug UP-TO-DATE +> Task :app:generateDebugAssets UP-TO-DATE +> Task :app:mergeDebugAssets UP-TO-DATE +> Task :app:compressDebugAssets UP-TO-DATE +> Task :app:generateDebugGlobalSynthetics UP-TO-DATE +> Task :app:checkDebugDuplicateClasses UP-TO-DATE +> Task :app:desugarDebugFileDependencies UP-TO-DATE +> Task :app:mergeExtDexDebug UP-TO-DATE +> Task :app:mergeLibDexDebug UP-TO-DATE +> Task :app:checkDebugAarMetadata UP-TO-DATE +> Task :app:mapDebugSourceSetPaths UP-TO-DATE +> Task :app:compileDebugNavigationResources UP-TO-DATE +> Task :app:mergeDebugResources UP-TO-DATE +> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE +> Task :app:extractDeepLinksDebug UP-TO-DATE +> Task :app:processDebugMainManifest UP-TO-DATE +> Task :app:processDebugManifest UP-TO-DATE +> Task :app:processDebugManifestForPackage UP-TO-DATE +> Task :app:processDebugResources UP-TO-DATE +> Task :app:mergeDebugJniLibFolders UP-TO-DATE +> Task :app:mergeDebugNativeLibs UP-TO-DATE +> Task :app:stripDebugDebugSymbols UP-TO-DATE +> Task :app:validateSigningDebug UP-TO-DATE +> Task :app:writeDebugAppMetadata UP-TO-DATE +> Task :app:writeDebugSigningConfigVersions UP-TO-DATE +> Task :app:compileDebugKotlin +> Task :app:compileDebugJavaWithJavac NO-SOURCE +> Task :app:processDebugJavaRes UP-TO-DATE +> Task :app:mergeDebugJavaResource UP-TO-DATE +> Task :app:dexBuilderDebug +> Task :app:mergeProjectDexDebug +> Task :app:packageDebug +> Task :app:createDebugApkListingFileRedirect UP-TO-DATE +> Task :app:assembleDebug + +BUILD SUCCESSFUL in 21s +36 actionable tasks: 4 executed, 32 up-to-date diff --git a/build-fix2.txt b/build-fix2.txt new file mode 100644 index 0000000..e95ac42 --- /dev/null +++ b/build-fix2.txt @@ -0,0 +1,45 @@ +> Task :app:preBuild UP-TO-DATE +> Task :app:preDebugBuild UP-TO-DATE +> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE +> Task :app:generateDebugResources UP-TO-DATE +> Task :app:packageDebugResources UP-TO-DATE +> Task :app:processDebugNavigationResources UP-TO-DATE +> Task :app:parseDebugLocalResources UP-TO-DATE +> Task :app:generateDebugRFile UP-TO-DATE +> Task :app:javaPreCompileDebug UP-TO-DATE +> Task :app:generateDebugAssets UP-TO-DATE +> Task :app:mergeDebugAssets UP-TO-DATE +> Task :app:compressDebugAssets UP-TO-DATE +> Task :app:generateDebugGlobalSynthetics UP-TO-DATE +> Task :app:checkDebugDuplicateClasses UP-TO-DATE +> Task :app:desugarDebugFileDependencies UP-TO-DATE +> Task :app:mergeExtDexDebug UP-TO-DATE +> Task :app:mergeLibDexDebug UP-TO-DATE +> Task :app:checkDebugAarMetadata UP-TO-DATE +> Task :app:mapDebugSourceSetPaths UP-TO-DATE +> Task :app:compileDebugNavigationResources UP-TO-DATE +> Task :app:mergeDebugResources UP-TO-DATE +> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE +> Task :app:extractDeepLinksDebug UP-TO-DATE +> Task :app:processDebugMainManifest UP-TO-DATE +> Task :app:processDebugManifest UP-TO-DATE +> Task :app:processDebugManifestForPackage UP-TO-DATE +> Task :app:processDebugResources UP-TO-DATE +> Task :app:mergeDebugJniLibFolders UP-TO-DATE +> Task :app:mergeDebugNativeLibs UP-TO-DATE +> Task :app:stripDebugDebugSymbols UP-TO-DATE +> Task :app:validateSigningDebug UP-TO-DATE +> Task :app:writeDebugAppMetadata UP-TO-DATE +> Task :app:writeDebugSigningConfigVersions UP-TO-DATE +> Task :app:compileDebugKotlin +> Task :app:compileDebugJavaWithJavac NO-SOURCE +> Task :app:processDebugJavaRes UP-TO-DATE +> Task :app:mergeDebugJavaResource UP-TO-DATE +> Task :app:dexBuilderDebug +> Task :app:mergeProjectDexDebug +> Task :app:packageDebug +> Task :app:createDebugApkListingFileRedirect UP-TO-DATE +> Task :app:assembleDebug + +BUILD SUCCESSFUL in 6s +36 actionable tasks: 4 executed, 32 up-to-date diff --git a/build-fix3.txt b/build-fix3.txt new file mode 100644 index 0000000..7a8d249 --- /dev/null +++ b/build-fix3.txt @@ -0,0 +1,45 @@ +> Task :app:preBuild UP-TO-DATE +> Task :app:preDebugBuild UP-TO-DATE +> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE +> Task :app:generateDebugResources UP-TO-DATE +> Task :app:packageDebugResources UP-TO-DATE +> Task :app:processDebugNavigationResources UP-TO-DATE +> Task :app:parseDebugLocalResources UP-TO-DATE +> Task :app:generateDebugRFile UP-TO-DATE +> Task :app:javaPreCompileDebug UP-TO-DATE +> Task :app:generateDebugAssets UP-TO-DATE +> Task :app:mergeDebugAssets UP-TO-DATE +> Task :app:compressDebugAssets UP-TO-DATE +> Task :app:generateDebugGlobalSynthetics UP-TO-DATE +> Task :app:checkDebugDuplicateClasses UP-TO-DATE +> Task :app:desugarDebugFileDependencies UP-TO-DATE +> Task :app:mergeExtDexDebug UP-TO-DATE +> Task :app:mergeLibDexDebug UP-TO-DATE +> Task :app:checkDebugAarMetadata UP-TO-DATE +> Task :app:mapDebugSourceSetPaths UP-TO-DATE +> Task :app:compileDebugNavigationResources UP-TO-DATE +> Task :app:mergeDebugResources UP-TO-DATE +> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE +> Task :app:extractDeepLinksDebug UP-TO-DATE +> Task :app:processDebugMainManifest UP-TO-DATE +> Task :app:processDebugManifest UP-TO-DATE +> Task :app:processDebugManifestForPackage UP-TO-DATE +> Task :app:processDebugResources UP-TO-DATE +> Task :app:mergeDebugJniLibFolders UP-TO-DATE +> Task :app:mergeDebugNativeLibs UP-TO-DATE +> Task :app:stripDebugDebugSymbols UP-TO-DATE +> Task :app:validateSigningDebug UP-TO-DATE +> Task :app:writeDebugAppMetadata UP-TO-DATE +> Task :app:writeDebugSigningConfigVersions UP-TO-DATE +> Task :app:compileDebugKotlin +> Task :app:compileDebugJavaWithJavac NO-SOURCE +> Task :app:processDebugJavaRes UP-TO-DATE +> Task :app:mergeDebugJavaResource UP-TO-DATE +> Task :app:dexBuilderDebug +> Task :app:mergeProjectDexDebug +> Task :app:packageDebug +> Task :app:createDebugApkListingFileRedirect UP-TO-DATE +> Task :app:assembleDebug + +BUILD SUCCESSFUL in 2s +36 actionable tasks: 4 executed, 32 up-to-date diff --git a/build-output.txt b/build-output.txt new file mode 100644 index 0000000..c396be0 --- /dev/null +++ b/build-output.txt @@ -0,0 +1,45 @@ +> Task :app:preBuild UP-TO-DATE +> Task :app:preDebugBuild UP-TO-DATE +> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE +> Task :app:generateDebugResources UP-TO-DATE +> Task :app:packageDebugResources UP-TO-DATE +> Task :app:processDebugNavigationResources UP-TO-DATE +> Task :app:parseDebugLocalResources UP-TO-DATE +> Task :app:generateDebugRFile UP-TO-DATE +> Task :app:compileDebugKotlin UP-TO-DATE +> Task :app:javaPreCompileDebug UP-TO-DATE +> Task :app:compileDebugJavaWithJavac NO-SOURCE +> Task :app:generateDebugAssets UP-TO-DATE +> Task :app:mergeDebugAssets UP-TO-DATE +> Task :app:compressDebugAssets UP-TO-DATE +> Task :app:generateDebugGlobalSynthetics UP-TO-DATE +> Task :app:processDebugJavaRes UP-TO-DATE +> Task :app:mergeDebugJavaResource UP-TO-DATE +> Task :app:checkDebugDuplicateClasses UP-TO-DATE +> Task :app:desugarDebugFileDependencies UP-TO-DATE +> Task :app:mergeLibDexDebug UP-TO-DATE +> Task :app:checkDebugAarMetadata UP-TO-DATE +> Task :app:mapDebugSourceSetPaths UP-TO-DATE +> Task :app:compileDebugNavigationResources UP-TO-DATE +> Task :app:mergeDebugResources UP-TO-DATE +> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE +> Task :app:extractDeepLinksDebug UP-TO-DATE +> Task :app:processDebugMainManifest UP-TO-DATE +> Task :app:processDebugManifest UP-TO-DATE +> Task :app:processDebugManifestForPackage UP-TO-DATE +> Task :app:processDebugResources UP-TO-DATE +> Task :app:dexBuilderDebug UP-TO-DATE +> Task :app:mergeProjectDexDebug UP-TO-DATE +> Task :app:mergeDebugJniLibFolders UP-TO-DATE +> Task :app:mergeDebugNativeLibs UP-TO-DATE +> Task :app:stripDebugDebugSymbols UP-TO-DATE +> Task :app:validateSigningDebug UP-TO-DATE +> Task :app:writeDebugAppMetadata UP-TO-DATE +> Task :app:writeDebugSigningConfigVersions UP-TO-DATE +> Task :app:mergeExtDexDebug +> Task :app:packageDebug +> Task :app:createDebugApkListingFileRedirect +> Task :app:assembleDebug + +BUILD SUCCESSFUL in 5s +36 actionable tasks: 3 executed, 33 up-to-date diff --git a/build-output2.txt b/build-output2.txt new file mode 100644 index 0000000..fa983ff --- /dev/null +++ b/build-output2.txt @@ -0,0 +1,45 @@ +> Task :app:preBuild UP-TO-DATE +> Task :app:preDebugBuild UP-TO-DATE +> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE +> Task :app:generateDebugResources UP-TO-DATE +> Task :app:packageDebugResources UP-TO-DATE +> Task :app:processDebugNavigationResources UP-TO-DATE +> Task :app:parseDebugLocalResources UP-TO-DATE +> Task :app:generateDebugRFile UP-TO-DATE +> Task :app:compileDebugKotlin UP-TO-DATE +> Task :app:javaPreCompileDebug UP-TO-DATE +> Task :app:compileDebugJavaWithJavac NO-SOURCE +> Task :app:generateDebugAssets UP-TO-DATE +> Task :app:mergeDebugAssets UP-TO-DATE +> Task :app:compressDebugAssets UP-TO-DATE +> Task :app:generateDebugGlobalSynthetics UP-TO-DATE +> Task :app:processDebugJavaRes UP-TO-DATE +> Task :app:mergeDebugJavaResource UP-TO-DATE +> Task :app:checkDebugDuplicateClasses UP-TO-DATE +> Task :app:desugarDebugFileDependencies UP-TO-DATE +> Task :app:mergeExtDexDebug UP-TO-DATE +> Task :app:mergeLibDexDebug UP-TO-DATE +> Task :app:checkDebugAarMetadata UP-TO-DATE +> Task :app:mapDebugSourceSetPaths UP-TO-DATE +> Task :app:compileDebugNavigationResources UP-TO-DATE +> Task :app:mergeDebugResources UP-TO-DATE +> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE +> Task :app:extractDeepLinksDebug UP-TO-DATE +> Task :app:processDebugMainManifest +> Task :app:processDebugManifest +> Task :app:mergeDebugJniLibFolders UP-TO-DATE +> Task :app:processDebugManifestForPackage +> Task :app:mergeDebugNativeLibs UP-TO-DATE +> Task :app:stripDebugDebugSymbols UP-TO-DATE +> Task :app:validateSigningDebug UP-TO-DATE +> Task :app:writeDebugAppMetadata UP-TO-DATE +> Task :app:writeDebugSigningConfigVersions UP-TO-DATE +> Task :app:processDebugResources +> Task :app:dexBuilderDebug UP-TO-DATE +> Task :app:mergeProjectDexDebug UP-TO-DATE +> Task :app:packageDebug +> Task :app:createDebugApkListingFileRedirect UP-TO-DATE +> Task :app:assembleDebug + +BUILD SUCCESSFUL in 6s +36 actionable tasks: 5 executed, 31 up-to-date diff --git a/build.gradle.kts b/build.gradle.kts index 18318be..371e867 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,4 +2,5 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.compose) apply false -} \ No newline at end of file + alias(libs.plugins.kotlin.serialization) apply false +} diff --git a/gradle.properties b/gradle.properties index 99fc155..d88c7e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:MaxMetaspaceSize=512m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. For more details, visit # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects @@ -15,5 +15,10 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # phase entirely if nothing that affects the build configuration (such as build scripts) # has changed. Additionally, Gradle applies performance optimizations to task execution. org.gradle.configuration-cache=true -# Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official \ No newline at end of file +# Kotlin code style for "official" or "obsolete": +kotlin.code.style=official +# Use Android Studio's bundled JDK 21 (AGP 9 requires JDK 21) +org.gradle.java.home=C:\\Program Files\\Android\\Android Studio\\jbr +# Register the JBR as a known JDK installation and disable auto-download +org.gradle.java.installations.paths=C:\\Program Files\\Android\\Android Studio\\jbr +org.gradle.java.installations.auto-download=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 394ece7..a21facd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,20 +1,25 @@ [versions] agp = "9.2.1" -coreKtx = "1.10.1" +coreKtx = "1.15.0" junit = "4.13.2" junitVersion = "1.1.5" espressoCore = "3.5.1" -lifecycleRuntimeKtx = "2.6.1" -activityCompose = "1.8.0" +lifecycleRuntimeKtx = "2.8.7" +activityCompose = "1.9.3" kotlin = "2.2.10" composeBom = "2026.02.01" +okhttp = "4.12.0" +kotlinxSerializationJson = "1.7.3" +lifecycle = "2.8.7" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } -androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } +androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" } +androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } @@ -24,8 +29,12 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" } +okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } - +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } diff --git a/replay_pid32560.log b/replay_pid32560.log new file mode 100644 index 0000000..e69de29 diff --git a/screen.png b/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..624b89840af885c5bd80053216d1b7f1b88145fd GIT binary patch literal 185132 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 z�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
    @B7 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℘s_5oNsv?$(e6@k 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