From 4a4039c03d3faaa79aa7c745af5c552af4b28f22 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 30 Jun 2026 21:37:08 +0300 Subject: [PATCH] Improve Android retrain start feedback --- android/TradeBotMonitor/app/build.gradle.kts | 4 ++-- .../kusoft/tradebotmonitor/MainActivity.kt | 23 +++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/android/TradeBotMonitor/app/build.gradle.kts b/android/TradeBotMonitor/app/build.gradle.kts index 53c2cb9..f142a52 100644 --- a/android/TradeBotMonitor/app/build.gradle.kts +++ b/android/TradeBotMonitor/app/build.gradle.kts @@ -10,7 +10,7 @@ android { applicationId = "xyz.kusoft.tradebotmonitor" minSdk = 26 targetSdk = 36 - versionCode = 11 - versionName = "0.2.8" + versionCode = 12 + versionName = "0.2.9" } } diff --git a/android/TradeBotMonitor/app/src/main/java/xyz/kusoft/tradebotmonitor/MainActivity.kt b/android/TradeBotMonitor/app/src/main/java/xyz/kusoft/tradebotmonitor/MainActivity.kt index fb04b0d..1aa325d 100644 --- a/android/TradeBotMonitor/app/src/main/java/xyz/kusoft/tradebotmonitor/MainActivity.kt +++ b/android/TradeBotMonitor/app/src/main/java/xyz/kusoft/tradebotmonitor/MainActivity.kt @@ -39,6 +39,7 @@ class MainActivity : Activity() { private var activeTab: String = "ai" private var palette: AppPalette = AppPalette.dark() private var trainingStatusSignature: String = "" + private var retrainRequestInFlight: Boolean = false private val refreshRunnable = object : Runnable { override fun run() { @@ -643,14 +644,23 @@ class MainActivity : Activity() { LinearLayout(this).apply { val activeJob = coordination.optJSONObject("active_job") val latestJob = coordination.optJSONObject("latest_job") - val job = activeJob ?: latestJob orientation = LinearLayout.VERTICAL addView(text("Процесс переобучения", 12f, Typeface.NORMAL, palette.muted)) - if (job == null) { + if (activeJob == null) { val agentOnline = coordination.optBoolean("agent_online", false) addView(keyValueLine("Состояние", if (agentOnline) "готов к запуску" else "ждет Windows-agent", if (agentOnline) palette.green else palette.amber).top(dp(8))) + if (latestJob != null) { + val latestStatus = latestJob.optStringClean("status") + val latestPhase = latestJob.optStringClean("phase") + val latestMessage = latestJob.optStringClean("message") + addView(keyValueLine("Последнее обучение", trainingJobLabel(latestStatus, latestPhase), trainingJobColor(latestStatus, latestPhase)).top(dp(8))) + if (latestMessage.isNotBlank()) { + addView(text(latestMessage.take(160), 12f, Typeface.NORMAL, palette.muted).top(dp(6))) + } + } return@apply } + val job = activeJob val status = job.optStringClean("status") val phase = job.optStringClean("phase") val progress = job.optInt("progress_percent", if (status == "completed") 100 else 0).coerceIn(0, 100) @@ -674,7 +684,7 @@ class MainActivity : Activity() { private fun retrainSettingsBlock(retrain: JSONObject, backtest: JSONObject): View { val coordination = retrain.optJSONObject("coordination") ?: JSONObject() val activeJob = coordination.optJSONObject("active_job") - val isTrainingActive = activeJob?.optStringClean("status") in setOf("pending", "running") + val isTrainingActive = retrainRequestInFlight || (activeJob?.optStringClean("status") in setOf("pending", "running")) return LinearLayout(this).apply { orientation = LinearLayout.VERTICAL addView(trainingComputerPanel(retrain).top(dp(12))) @@ -687,7 +697,7 @@ class MainActivity : Activity() { addView(keyValueLine("Replay сделок", replay.optInt("trades", 0).toString()).top(dp(4))) addView(keyValueLine("Replay PnL", signedMoney(replay.optDouble("net_pnl", 0.0)), colorForSigned(replay.optDouble("net_pnl", 0.0))).top(dp(4))) if (isTrainingActive) { - addView(disabledActionButton("Обучение уже идет").top(dp(10))) + addView(disabledActionButton(if (retrainRequestInFlight) "Отправляю команду" else "Обучение уже идет").top(dp(10))) } else { addView(actionRow( "Запустить сейчас" to { @@ -1101,15 +1111,20 @@ class MainActivity : Activity() { } private fun triggerRetrainNow() { + if (retrainRequestInFlight) return + retrainRequestInFlight = true + render() executor.execute { try { val message = TradeBotApi(prefs.apiBaseUrl, prefs.commandToken).requestRetrain() mainHandler.post { + retrainRequestInFlight = false toast(message.take(180)) refreshData(silent = false) } } catch (error: Exception) { mainHandler.post { + retrainRequestInFlight = false toast(error.message ?: "retrain не запущен") refreshData(silent = false) }