feat: 添加特殊任务模式、生气表情和版本显示

- 新增特殊任务模式开关,带状态指示灯
- 扩展表情系统,增加生气表情并支持眉毛绘制
- 在设置界面显示版本号
- 优化任务管理逻辑,支持特殊任务状态同步
- 改进导航指令命名,将充电功能重命名为 recharge
- 增强人机交互,添加基于时间和任务的智能问候
- 优化家庭基站检测逻辑,添加开门/关门提示
This commit is contained in:
2026-03-13 15:27:12 +08:00
parent 3def989a8b
commit b15c5c9021
13 changed files with 491 additions and 148 deletions

View File

@@ -39,7 +39,7 @@ class AnimatedEmojiView @JvmOverloads constructor(
private var mouthOpenRatio = 0.1f
private var noddingOffset = 0f
enum class Expression { SMILE, NEUTRAL, TALKING, HAPPY, SAD, WINK }
enum class Expression { SMILE, NEUTRAL, TALKING, HAPPY, SAD, WINK, ANGRY }
var currentExpression = Expression.SMILE
set(value) {
field = value
@@ -81,6 +81,27 @@ class AnimatedEmojiView @JvmOverloads constructor(
canvas.drawCircle(centerX + eyeOffsetX, centerY - eyeOffsetY, eyeRadius, eyePaint)
}
// 2.1 画眉毛 (仅在生气时)
if (currentExpression == Expression.ANGRY) {
val eyebrowWidth = eyeRadius * 2.5f
val eyebrowOffsetY = eyeOffsetY + eyeRadius * 1.5f
mouthPaint.strokeWidth = 10f // 眉毛可以细一点
// 左眉毛
canvas.save()
canvas.rotate(15f, centerX - eyeOffsetX, centerY - eyebrowOffsetY)
canvas.drawLine(centerX - eyeOffsetX - eyebrowWidth / 2, centerY - eyebrowOffsetY, centerX - eyeOffsetX + eyebrowWidth / 2, centerY - eyebrowOffsetY, mouthPaint)
canvas.restore()
// 右眉毛
canvas.save()
canvas.rotate(-15f, centerX + eyeOffsetX, centerY - eyebrowOffsetY)
canvas.drawLine(centerX + eyeOffsetX - eyebrowWidth / 2, centerY - eyebrowOffsetY, centerX + eyeOffsetX + eyebrowWidth / 2, centerY - eyebrowOffsetY, mouthPaint)
canvas.restore()
mouthPaint.strokeWidth = 15f // 恢复嘴巴的宽度
}
// 3. 画嘴巴
mouthPaint.style = Paint.Style.STROKE
val mouthWidth = radius * 0.6f
@@ -97,6 +118,7 @@ class AnimatedEmojiView @JvmOverloads constructor(
canvas.drawArc(happyMouthPath, 0f, 180f, false, mouthPaint)
}
Expression.SAD -> canvas.drawArc(mouthPath, 200f, -140f, false, mouthPaint)
Expression.ANGRY -> canvas.drawArc(mouthPath, 200f, -140f, false, mouthPaint)
Expression.NEUTRAL -> canvas.drawLine(mouthLeft, mouthTop + mouthHeight / 2, mouthLeft + mouthWidth, mouthTop + mouthHeight / 2, mouthPaint)
Expression.WINK -> canvas.drawArc(mouthPath, 20f, 140f, false, mouthPaint)
Expression.TALKING -> {

View File

@@ -25,6 +25,9 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.cancel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnGoToLocationStatusChangedListener,
OnDetectionStateChangedListener, OnReposeStatusChangedListener, SharedPreferences.OnSharedPreferenceChangeListener,
OnRequestPermissionResultListener {
@@ -43,6 +46,9 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
private val baseFaceSizeDp = 1000f
private var currentTask: String = ""
private var closeDoorJob: Job? = null
private var receptionLocation: String = ""
private var receptionText: String = ""
private var receptionDestination: String = ""
@@ -60,13 +66,16 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
permissionManager = PermissionManager(robot)
prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
if (prefs.getBoolean("special_task_mode", false)) {
currentTask = "special"
}
binding.btnSettings.setOnClickListener {
startActivity(Intent(this, SettingsActivity::class.java))
}
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.SMILE
applyFaceScale(fixedFaceScale)
// applyFaceScale(fixedFaceScale) // Use XML constraints for layout
binding.btnReception.setOnClickListener {
val destination = receptionDestination
@@ -88,6 +97,7 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
robot.addOnReposeStatusChangedListener(this)
robot.addOnRequestPermissionResultListener(this)
prefs.registerOnSharedPreferenceChangeListener(this)
robot.constraintBeWith()
mqttManager?.connect()
}
@@ -139,13 +149,14 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
Log.i("MainActivity", "TTS started")
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.TALKING
}
TtsRequest.Status.COMPLETED -> {
Log.i("MainActivity", "TTS completed: ${ttsRequest.speech}")
TtsRequest.Status.COMPLETED,
TtsRequest.Status.CANCELED -> {
Log.i("MainActivity", "TTS finished: ${ttsRequest.speech}")
if (currentTask == "patrol") {
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.ANGRY
} else {
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.SMILE
}
TtsRequest.Status.CANCELED -> {
Log.w("MainActivity", "TTS canceled: ${ttsRequest.speech}")
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.SMILE
}
TtsRequest.Status.ERROR -> {
Log.e("MainActivity", "TTS error: ${ttsRequest.speech}")
@@ -173,6 +184,12 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
}
override fun onDetectionStateChanged(state: Int) {
if (currentTask == "patrol" && state == DETECTED) {
val ttsRequest = TtsRequest.create("别妨碍我,我正在巡逻呢", false, language = TtsRequest.Language.ZH_CN)
robot.speak(ttsRequest)
return
}
if (currentTask == "reception" && lastArrivalLocation == receptionLocation) {
when (state) {
DETECTED -> {
@@ -191,9 +208,13 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
}
// Home Base logic
// if (lastArrivalLocation?.lowercase() == "home base") {
// when (state) {
// DETECTED -> {
if (lastArrivalLocation?.lowercase() == "home base") {
when (state) {
DETECTED -> {
closeDoorJob?.cancel()
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.WINK
val ttsRequest = TtsRequest.create("正在为你开门,请稍等。", false, language = TtsRequest.Language.ZH_CN)
robot.speak(ttsRequest)
// mainScope.launch {
// HttpManager.workflow_execute(
// context = this@MainActivity,
@@ -202,8 +223,12 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
// inputs = emptyMap<String, Any>()
// )
// }
// }
// IDLE -> {
}
IDLE -> {
closeDoorJob = mainScope.launch {
delay(5000)
val ttsRequest = TtsRequest.create("正准备关门,请小心被夹。", false, language = TtsRequest.Language.ZH_CN)
robot.speak(ttsRequest)
// mainScope.launch {
// HttpManager.workflow_execute(
// context = this@MainActivity,
@@ -212,13 +237,26 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
// inputs = emptyMap<String, Any>()
// )
// }
// }
// }
// }
}
}
}
}
if (state == DETECTED && currentTask.isEmpty() && lastArrivalLocation?.lowercase() != "home base") {
val hour = java.util.Calendar.getInstance().get(java.util.Calendar.HOUR_OF_DAY)
val greeting = when (hour) {
in 6..11 -> "早上好"
in 12..13 -> "中午好"
in 14..18 -> "下午好"
else -> "晚上好"
}
val ttsRequest = TtsRequest.create(greeting, false, language = TtsRequest.Language.ZH_CN)
robot.speak(ttsRequest)
}
}
fun startReceptionMode(location: String, text: String, destination: String) {
currentTask = "reception"
setCurrentTask("reception")
receptionLocation = location
receptionText = text
receptionDestination = destination
@@ -240,6 +278,12 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
fun setCurrentTask(task: String) {
currentTask = task
Log.i("MainActivity", "Current task set to: $task")
// Update expression based on task
if (task == "patrol") {
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.ANGRY
} else {
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.SMILE
}
}
override fun onReposeStatusChanged(status: Int, description: String) {
@@ -267,6 +311,13 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
Log.i("MainActivity", "IP address changed, re-initializing MQTT connection.")
updateMqttConnection()
}
if (key == "special_task_mode") {
if (sharedPreferences?.getBoolean("special_task_mode", false) == true) {
setCurrentTask("special")
} else if (currentTask == "special") {
setCurrentTask("")
}
}
}
private fun updateMqttConnection() {

View File

@@ -161,9 +161,9 @@ class MqttManager(
private fun handleJsonCommand(obj: JSONObject) {
val action = obj.optString("action", obj.optString("cmd", obj.optString("type", ""))).lowercase()
when (action) {
"charge" -> {
"recharge" -> {
speak("前往充电桩", "zh")
navController.charge()
navController.recharge()
}
"goto" -> {
val location = obj.optString("location", obj.optString("target", ""))
@@ -184,6 +184,7 @@ class MqttManager(
Log.i(TAG, "Repose command sent: $ok")
}
"stop" -> {
(context as? MainActivity)?.setCurrentTask("")
navController.stop()
stopTts()
}

View File

@@ -7,7 +7,7 @@ class NavController(private val robot: Robot) {
private val TAG = "NavController"
private var playmode = false
fun charge(): Boolean {
fun recharge(): Boolean {
playmode = !playmode
robot.goTo("home base", playmode)
return true

View File

@@ -5,6 +5,7 @@ import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
@@ -15,11 +16,14 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.lzwcai_terminal_temi.databinding.ActivitySettingsBinding
import kotlin.system.exitProcess
import android.graphics.drawable.GradientDrawable
import androidx.core.content.ContextCompat
class SettingsActivity : AppCompatActivity() {
private lateinit var binding: ActivitySettingsBinding
private var restartAnimator: ValueAnimator? = null
private lateinit var prefs: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -28,10 +32,14 @@ class SettingsActivity : AppCompatActivity() {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
val prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
val savedIp = prefs.getString("network_ip", "")
binding.etIpAddress.setText(savedIp)
// Set Version Name
val versionName = "2603121722"
binding.tvVersion.text = getString(R.string.version_prefix, versionName)
binding.root.setOnClickListener { hideKeyboard() }
binding.btnSave.setOnClickListener {
@@ -54,6 +62,28 @@ class SettingsActivity : AppCompatActivity() {
}
setupRestartButton()
setupSpecialTaskSwitch()
}
private fun setupSpecialTaskSwitch() {
val isSpecialTaskMode = prefs.getBoolean("special_task_mode", false)
binding.switchSpecialTask.isChecked = isSpecialTaskMode
updateStatusIndicator(isSpecialTaskMode)
binding.switchSpecialTask.setOnCheckedChangeListener { _, isChecked ->
prefs.edit().putBoolean("special_task_mode", isChecked).apply()
updateStatusIndicator(isChecked)
}
}
private fun updateStatusIndicator(isSpecialTaskMode: Boolean) {
val indicatorColor = if (isSpecialTaskMode) {
ContextCompat.getColor(this, android.R.color.holo_red_dark)
} else {
ContextCompat.getColor(this, android.R.color.holo_green_dark)
}
val indicatorDrawable = binding.statusIndicator.background as GradientDrawable
indicatorDrawable.setColor(indicatorColor)
}
private fun setupRestartButton() {

View File

@@ -3,14 +3,14 @@
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dp" />
<solid android:color="#E0E0E0" />
<solid android:color="#424242" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dp" />
<solid android:color="#4CAF50" />
<solid android:color="@color/primary_teal" />
</shape>
</clip>
</item>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@android:color/darker_gray" />
<size android:width="24dp" android:height="24dp" />
</shape>

View File

@@ -1,37 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:background="@color/background_dark"
tools:context=".MainActivity">
<ImageButton
android:id="@+id/btnSettings"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/btn_settings"
android:src="@android:drawable/ic_menu_manage" />
android:src="@android:drawable/ic_menu_manage"
app:tint="@color/text_secondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.example.lzwcai_terminal_temi.AnimatedEmojiView
android:id="@+id/animatedEmojiView"
android:layout_width="500dp"
android:layout_height="500dp"
android:layout_centerInParent="true" />
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45"
app:layout_constraintWidth_percent="0.6" />
<Button
android:id="@+id/btnReception"
style="@style/Widget.App.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="100dp"
android:layout_marginBottom="80dp"
android:paddingStart="48dp"
android:paddingTop="16dp"
android:paddingEnd="48dp"
android:paddingBottom="16dp"
android:text="是的"
android:textSize="24sp"
android:padding="20dp"
android:visibility="gone" />
android:textSize="20sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,95 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
android:background="@color/background_dark"
tools:context=".SettingsActivity">
<RelativeLayout
<!-- Header -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/headerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp">
android:layout_height="?attr/actionBarSize"
android:background="@color/surface_dark"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/btnBack"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/btn_back"
android:src="@android:drawable/ic_menu_revert" />
android:src="@android:drawable/ic_menu_revert"
app:tint="@color/text_primary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvSettingsTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="24dp"
android:text="@string/title_settings"
android:textSize="32sp"
android:textStyle="bold" />
android:textColor="@color/text_primary"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/headerLayout">
<LinearLayout
android:id="@+id/ipConfigLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tvSettingsTitle"
android:layout_marginTop="24dp"
android:gravity="center_vertical"
android:orientation="horizontal">
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/etIpAddress"
android:layout_width="0dp"
<!-- Network Config Card -->
<androidx.cardview.widget.CardView
style="@style/CardView.App"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/label_ip_config"
android:textColor="@color/text_primary"
android:textSize="18sp"
android:textStyle="bold" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.App.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_ip_address">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etIpAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:hint="@string/hint_ip_address"
android:inputType="number|numberDecimal"
android:digits="0123456789."
android:minHeight="60dp"
android:textSize="24sp" />
android:textColor="@color/text_primary" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnSave"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:text="@string/btn_save"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/restartLayout"
style="@style/Widget.App.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/btn_save" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Mode Config Card -->
<androidx.cardview.widget.CardView
style="@style/CardView.App"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<LinearLayout
android:id="@+id/specialTaskLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="特殊任务模式"
android:textColor="@color/text_primary"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="启用特定场景下的任务逻辑"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
</LinearLayout>
<View
android:id="@+id/statusIndicator"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginEnd="16dp"
android:background="@drawable/status_indicator" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switchSpecialTask"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- System Actions Card -->
<androidx.cardview.widget.CardView
style="@style/CardView.App"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ipConfigLayout"
android:layout_marginTop="32dp"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btnRestart"
android:layout_width="200dp"
android:layout_height="80dp"
android:text="@string/btn_restart_app"
android:textSize="18sp" />
style="@style/Widget.App.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/btn_restart_app" />
<ProgressBar
android:id="@+id/restartProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="200dp"
android:layout_height="80dp"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_gravity="bottom"
android:indeterminate="false"
android:max="100"
android:progress="0"
android:progressDrawable="@drawable/custom_progress_bar"
android:visibility="invisible" />
</FrameLayout>
</LinearLayout>
</RelativeLayout>
</ScrollView>
<TextView
android:id="@+id/tvVersion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Version: --"
android:textColor="@color/text_secondary"
android:textSize="12sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,16 +1,62 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Lzwcaiterminaltemi" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.Lzwcaiterminaltemi" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorPrimary">@color/primary_teal</item>
<item name="colorPrimaryVariant">@color/primary_variant_teal</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorSecondary">@color/secondary_purple</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="android:statusBarColor">@color/background_dark</item>
<!-- Backgrounds -->
<item name="android:windowBackground">@color/background_dark</item>
<item name="android:textColorPrimary">@color/text_primary</item>
<item name="android:textColorSecondary">@color/text_secondary</item>
<!-- Customize your theme here. -->
<item name="materialButtonStyle">@style/Widget.App.Button</item>
<item name="textInputStyle">@style/Widget.App.TextInputLayout</item>
</style>
<style name="Widget.App.Button" parent="Widget.MaterialComponents.Button">
<item name="backgroundTint">@color/primary_teal</item>
<item name="android:textColor">@color/black</item>
<item name="cornerRadius">12dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:fontFamily">sans-serif-medium</item>
</style>
<style name="Widget.App.OutlinedButton" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="strokeColor">@color/primary_teal</item>
<item name="android:textColor">@color/primary_teal</item>
<item name="cornerRadius">12dp</item>
<item name="android:textAllCaps">false</item>
</style>
<style name="Widget.App.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="boxStrokeColor">@color/primary_teal</item>
<item name="boxBackgroundColor">@color/input_background</item>
<item name="boxCornerRadiusTopStart">12dp</item>
<item name="boxCornerRadiusTopEnd">12dp</item>
<item name="boxCornerRadiusBottomStart">12dp</item>
<item name="boxCornerRadiusBottomEnd">12dp</item>
<item name="android:textColorHint">@color/text_secondary</item>
<item name="hintTextColor">@color/primary_teal</item>
</style>
<style name="TextAppearance.App.Headline" parent="TextAppearance.MaterialComponents.Headline4">
<item name="android:textColor">@color/text_primary</item>
<item name="android:fontFamily">sans-serif-light</item>
<item name="android:textStyle">bold</item>
</style>
<style name="CardView.App" parent="Widget.MaterialComponents.CardView">
<item name="cardBackgroundColor">@color/surface_dark</item>
<item name="cardCornerRadius">16dp</item>
<item name="cardElevation">4dp</item>
<item name="contentPadding">16dp</item>
</style>
</resources>

View File

@@ -7,4 +7,15 @@
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<!-- New Theme Colors -->
<color name="background_dark">#121212</color>
<color name="surface_dark">#1E1E1E</color>
<color name="primary_teal">#03DAC6</color>
<color name="primary_variant_teal">#018786</color>
<color name="secondary_purple">#BB86FC</color>
<color name="text_primary">#FFFFFF</color>
<color name="text_secondary">#B0B0B0</color>
<color name="divider">#2C2C2C</color>
<color name="input_background">#2C2C2C</color>
</resources>

View File

@@ -10,6 +10,7 @@
<string name="btn_back">返回主界面</string>
<string name="msg_ip_saved">IP 已保存: %1$s</string>
<string name="msg_invalid_ip">请输入有效的 IP 地址</string>
<string name="version_prefix">Version: %1$s</string>
<string name="btn_random_expression">随机表情</string>
<string name="btn_speak">让机器人说话</string>
<string name="btn_restart_app">长按重启应用</string>

View File

@@ -1,16 +1,63 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Lzwcaiterminaltemi" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.Lzwcaiterminaltemi" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorPrimary">@color/primary_teal</item>
<item name="colorPrimaryVariant">@color/primary_variant_teal</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondary">@color/secondary_purple</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="android:statusBarColor">@color/background_dark</item>
<!-- Backgrounds -->
<item name="android:windowBackground">@color/background_dark</item>
<item name="android:textColorPrimary">@color/text_primary</item>
<item name="android:textColorSecondary">@color/text_secondary</item>
<!-- Customize your theme here. -->
<item name="materialButtonStyle">@style/Widget.App.Button</item>
<item name="textInputStyle">@style/Widget.App.TextInputLayout</item>
</style>
<style name="Widget.App.Button" parent="Widget.MaterialComponents.Button">
<item name="backgroundTint">@color/primary_teal</item>
<item name="android:textColor">@color/black</item>
<item name="cornerRadius">12dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:fontFamily">sans-serif-medium</item>
</style>
<style name="Widget.App.OutlinedButton" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="strokeColor">@color/primary_teal</item>
<item name="android:textColor">@color/primary_teal</item>
<item name="cornerRadius">12dp</item>
<item name="android:textAllCaps">false</item>
</style>
<style name="Widget.App.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="boxStrokeColor">@color/primary_teal</item>
<item name="boxBackgroundColor">@color/input_background</item>
<item name="boxCornerRadiusTopStart">12dp</item>
<item name="boxCornerRadiusTopEnd">12dp</item>
<item name="boxCornerRadiusBottomStart">12dp</item>
<item name="boxCornerRadiusBottomEnd">12dp</item>
<item name="android:textColorHint">@color/text_secondary</item>
<item name="hintTextColor">@color/primary_teal</item>
</style>
<style name="TextAppearance.App.Headline" parent="TextAppearance.MaterialComponents.Headline4">
<item name="android:textColor">@color/text_primary</item>
<item name="android:fontFamily">sans-serif-light</item>
<item name="android:textStyle">bold</item>
</style>
<style name="CardView.App" parent="Widget.MaterialComponents.CardView">
<item name="cardBackgroundColor">@color/surface_dark</item>
<item name="cardCornerRadius">16dp</item>
<item name="cardElevation">4dp</item>
<item name="contentPadding">16dp</item>
</style>
</resources>