feat(android): 设置持久化(推流参数与连接信息)

This commit is contained in:
2026-09-14 20:40:16 +08:00
parent d27845ef43
commit 5737a66afd
@@ -0,0 +1,94 @@
package com.opendance.studio.data
import android.content.Context
import androidx.core.content.edit
/**
* 应用设置(SharedPreferences)。
*
* 契约 websocket-keypoints.md §3.3 的 config 字段与这里的前四项一一对应。
*/
class AppSettings(context: Context) {
private val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
/** Windows 客户端主机地址 */
var host: String
get() = prefs.getString(KEY_HOST, DEFAULT_HOST) ?: DEFAULT_HOST
set(value) = prefs.edit { putString(KEY_HOST, value.trim()) }
var port: Int
get() = prefs.getInt(KEY_PORT, DEFAULT_PORT)
set(value) = prefs.edit { putInt(KEY_PORT, value.coerceIn(1, 65535)) }
/** 目标帧率(契约 config.targetFps) */
var targetFps: Int
get() = prefs.getInt(KEY_TARGET_FPS, DEFAULT_FPS)
set(value) = prefs.edit { putInt(KEY_TARGET_FPS, value.coerceIn(5, 60)) }
/** 是否镜像画面(契约 flags.bit0 / config.mirror) */
var mirror: Boolean
get() = prefs.getBoolean(KEY_MIRROR, true)
set(value) = prefs.edit { putBoolean(KEY_MIRROR, value) }
/** 仅上半身模式(契约 flags.bit2) */
var upperBodyOnly: Boolean
get() = prefs.getBoolean(KEY_UPPER_BODY, false)
set(value) = prefs.edit { putBoolean(KEY_UPPER_BODY, value) }
/** 分辨率档位,取值见 [Resolutions] */
var resolution: String
get() = prefs.getString(KEY_RESOLUTION, Resolutions.MEDIUM) ?: Resolutions.MEDIUM
set(value) = prefs.edit { putString(KEY_RESOLUTION, value) }
/** 上次连接的设备名(hello 上报用) */
var deviceLabel: String
get() = prefs.getString(KEY_DEVICE_LABEL, "") ?: ""
set(value) = prefs.edit { putString(KEY_DEVICE_LABEL, value) }
/** 自动重连 */
var autoReconnect: Boolean
get() = prefs.getBoolean(KEY_AUTO_RECONNECT, true)
set(value) = prefs.edit { putBoolean(KEY_AUTO_RECONNECT, value) }
fun webSocketUrl(): String = "ws://$host:$port/pose"
companion object {
const val PREFS_NAME = "opendance_settings"
const val DEFAULT_HOST = "192.168.1.100"
const val DEFAULT_PORT = 8765
const val DEFAULT_FPS = 30
private const val KEY_HOST = "host"
private const val KEY_PORT = "port"
private const val KEY_TARGET_FPS = "target_fps"
private const val KEY_MIRROR = "mirror"
private const val KEY_UPPER_BODY = "upper_body_only"
private const val KEY_RESOLUTION = "resolution"
private const val KEY_DEVICE_LABEL = "device_label"
private const val KEY_AUTO_RECONNECT = "auto_reconnect"
}
}
/** 分辨率档位 —— 与契约 config.resolution 的取值格式一致 */
object Resolutions {
const val LOW = "480x360"
const val MEDIUM = "640x480"
const val HIGH = "1280x720"
val ALL = listOf(LOW, MEDIUM, HIGH)
/** 返回 (宽, 高) */
fun parse(value: String): Pair<Int, Int> {
val parts = value.split("x")
val w = parts.getOrNull(0)?.toIntOrNull() ?: 640
val h = parts.getOrNull(1)?.toIntOrNull() ?: 480
return w to h
}
fun label(value: String): String = when (value) {
LOW -> "低(480×360,最省电)"
HIGH -> "高(1280×720,最清晰)"
else -> "中(640×480,推荐)"
}
}