feat(proxy): CN/INTL 配置与模型列表完全分离
- 模型 Provider 改为按区域独立列表:Trae CN/INTL、WorkBuddy CN/INTL 各自拉取,不再互相覆盖 - 拉模型按区域取账号:未配置该区域账号时返回失败并保留内置兜底 - WorkBuddy 凭据表单补充区域(CN/INTL)选择,解决国际版无处配置的问题 - 账号管理列表显示 CN/INTL 区域徽标,一眼区分 - 版本升至 1.7.8
This commit is contained in:
parent
1a96bcb105
commit
eb4451c4de
@ -16,8 +16,8 @@ android {
|
|||||||
applicationId = "com.rainy.token"
|
applicationId = "com.rainy.token"
|
||||||
minSdk = 31
|
minSdk = 31
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 27
|
versionCode = 28
|
||||||
versionName = "1.7.7"
|
versionName = "1.7.8"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
|
|||||||
@ -38,8 +38,13 @@ class TraeModelProvider @Inject constructor(
|
|||||||
private val prefs: SharedPreferences =
|
private val prefs: SharedPreferences =
|
||||||
context.getSharedPreferences("rainytoken_proxy", Context.MODE_PRIVATE)
|
context.getSharedPreferences("rainytoken_proxy", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
private val _models = MutableStateFlow(defaultModels())
|
private val _modelsByRegion = MutableStateFlow(
|
||||||
val models: StateFlow<List<TraeModel>> = _models.asStateFlow()
|
ProviderRegion.entries.associateWith { defaultModels() }
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 获取指定区域模型列表(在线拉取成功后该区域独立更新)。 */
|
||||||
|
fun modelsFor(region: ProviderRegion): List<TraeModel> =
|
||||||
|
_modelsByRegion.value[region] ?: defaultModels()
|
||||||
|
|
||||||
private val json = Json { ignoreUnknownKeys = true }
|
private val json = Json { ignoreUnknownKeys = true }
|
||||||
|
|
||||||
@ -61,20 +66,16 @@ class TraeModelProvider @Inject constructor(
|
|||||||
fun supports(modelId: String, region: ProviderRegion): Boolean {
|
fun supports(modelId: String, region: ProviderRegion): Boolean {
|
||||||
val want = modelId.trim().lowercase()
|
val want = modelId.trim().lowercase()
|
||||||
if (want.isBlank() || want == "auto") return true
|
if (want.isBlank() || want == "auto") return true
|
||||||
if (models.value.any { it.id.equals(modelId, ignoreCase = true) }) return true
|
if (modelsFor(region).any { it.id.equals(modelId, ignoreCase = true) }) return true
|
||||||
return TraeChatProxy.resolveAlias(modelId) != null
|
return TraeChatProxy.resolveAlias(modelId) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 拉取账号在线模型列表;失败时保留内置列表并返回 false。 */
|
/** 拉取指定区域账号的在线模型列表;该区域未配置或失败时保留内置列表并返回 false。 */
|
||||||
suspend fun refreshFor(forcedRegion: ProviderRegion?): Boolean = withContext(Dispatchers.IO) {
|
suspend fun refreshFor(forcedRegion: ProviderRegion?): Boolean = withContext(Dispatchers.IO) {
|
||||||
val credential = credentialRepository.get(ServiceType.TRAE, null)
|
val effectiveRegion = forcedRegion ?: ProviderRegion.CN
|
||||||
?: return@withContext false
|
val credential = pickCredential(effectiveRegion) ?: return@withContext false
|
||||||
if (credential !is Credential.TraeCredential) return@withContext false
|
|
||||||
val jwt = credential.jwt.trim().takeIf { it.isNotBlank() } ?: return@withContext false
|
val jwt = credential.jwt.trim().takeIf { it.isNotBlank() } ?: return@withContext false
|
||||||
|
|
||||||
val effectiveRegion = forcedRegion ?: runCatching {
|
|
||||||
ProviderRegion.valueOf(credential.region.uppercase())
|
|
||||||
}.getOrNull()
|
|
||||||
val intl = effectiveRegion == ProviderRegion.INTL
|
val intl = effectiveRegion == ProviderRegion.INTL
|
||||||
val base = if (intl) "https://a0ai-api-sg.byteintlapi.com" else "https://trae-api-cn.mchost.guru"
|
val base = if (intl) "https://a0ai-api-sg.byteintlapi.com" else "https://trae-api-cn.mchost.guru"
|
||||||
val origin = if (intl) "https://solo.trae.ai" else "https://solo.trae.cn"
|
val origin = if (intl) "https://solo.trae.ai" else "https://solo.trae.cn"
|
||||||
@ -106,10 +107,22 @@ class TraeModelProvider @Inject constructor(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
if (parsed.isNullOrEmpty()) return@withContext false
|
if (parsed.isNullOrEmpty()) return@withContext false
|
||||||
_models.value = parsed
|
_modelsByRegion.value = _modelsByRegion.value + (effectiveRegion to parsed)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun pickCredential(region: ProviderRegion): Credential.TraeCredential? {
|
||||||
|
val accounts = credentialRepository.accountsFor(ServiceType.TRAE)
|
||||||
|
if (accounts.isEmpty()) {
|
||||||
|
val legacy = credentialRepository.get(ServiceType.TRAE, null)
|
||||||
|
return (legacy as? Credential.TraeCredential)
|
||||||
|
?.takeIf { it.region.equals(region.name, ignoreCase = true) }
|
||||||
|
}
|
||||||
|
return accounts.mapNotNull { account ->
|
||||||
|
credentialRepository.get(ServiceType.TRAE, account.id) as? Credential.TraeCredential
|
||||||
|
}.firstOrNull { it.region.equals(region.name, ignoreCase = true) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseModelList(body: String): List<TraeModel>? {
|
private fun parseModelList(body: String): List<TraeModel>? {
|
||||||
val root = runCatching { json.parseToJsonElement(body) as? JsonObject }.getOrNull()
|
val root = runCatching { json.parseToJsonElement(body) as? JsonObject }.getOrNull()
|
||||||
?: return null
|
?: return null
|
||||||
|
|||||||
@ -36,8 +36,13 @@ class WorkBuddyModelProvider @Inject constructor(
|
|||||||
private val prefs: SharedPreferences =
|
private val prefs: SharedPreferences =
|
||||||
context.getSharedPreferences("rainytoken_proxy", Context.MODE_PRIVATE)
|
context.getSharedPreferences("rainytoken_proxy", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
private val _models = MutableStateFlow(defaultModels())
|
private val _modelsByRegion = MutableStateFlow(
|
||||||
val models: StateFlow<List<TraeModelProvider.TraeModel>> = _models.asStateFlow()
|
ProviderRegion.entries.associateWith { defaultModels() }
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 获取指定区域模型列表(在线拉取成功后该区域独立更新)。 */
|
||||||
|
fun modelsFor(region: ProviderRegion): List<TraeModelProvider.TraeModel> =
|
||||||
|
_modelsByRegion.value[region] ?: defaultModels()
|
||||||
|
|
||||||
private val json = Json { ignoreUnknownKeys = true }
|
private val json = Json { ignoreUnknownKeys = true }
|
||||||
|
|
||||||
@ -56,13 +61,11 @@ class WorkBuddyModelProvider @Inject constructor(
|
|||||||
fun supports(modelId: String, region: ProviderRegion): Boolean {
|
fun supports(modelId: String, region: ProviderRegion): Boolean {
|
||||||
val want = modelId.trim().lowercase()
|
val want = modelId.trim().lowercase()
|
||||||
if (want.isBlank() || want == "auto") return true
|
if (want.isBlank() || want == "auto") return true
|
||||||
return models.value.any { it.id.equals(modelId, ignoreCase = true) }
|
return modelsFor(region).any { it.id.equals(modelId, ignoreCase = true) }
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun refreshFor(region: ProviderRegion): Boolean = withContext(Dispatchers.IO) {
|
suspend fun refreshFor(region: ProviderRegion): Boolean = withContext(Dispatchers.IO) {
|
||||||
val credential = credentialRepository.get(ServiceType.WORKBUDDY, null)
|
val credential = pickCredential(region) ?: return@withContext false
|
||||||
?: return@withContext false
|
|
||||||
if (credential !is Credential.WorkBuddyCredential) return@withContext false
|
|
||||||
val accessToken = credential.accessToken.trim().takeIf { it.isNotBlank() }
|
val accessToken = credential.accessToken.trim().takeIf { it.isNotBlank() }
|
||||||
?: return@withContext false
|
?: return@withContext false
|
||||||
val intl = region == ProviderRegion.INTL
|
val intl = region == ProviderRegion.INTL
|
||||||
@ -90,10 +93,22 @@ class WorkBuddyModelProvider @Inject constructor(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
if (parsed.isNullOrEmpty()) return@withContext false
|
if (parsed.isNullOrEmpty()) return@withContext false
|
||||||
_models.value = parsed
|
_modelsByRegion.value = _modelsByRegion.value + (region to parsed)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun pickCredential(region: ProviderRegion): Credential.WorkBuddyCredential? {
|
||||||
|
val accounts = credentialRepository.accountsFor(ServiceType.WORKBUDDY)
|
||||||
|
if (accounts.isEmpty()) {
|
||||||
|
val legacy = credentialRepository.get(ServiceType.WORKBUDDY, null)
|
||||||
|
return (legacy as? Credential.WorkBuddyCredential)
|
||||||
|
?.takeIf { it.region.equals(region.name, ignoreCase = true) }
|
||||||
|
}
|
||||||
|
return accounts.mapNotNull { account ->
|
||||||
|
credentialRepository.get(ServiceType.WORKBUDDY, account.id) as? Credential.WorkBuddyCredential
|
||||||
|
}.firstOrNull { it.region.equals(region.name, ignoreCase = true) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseModelList(body: String): List<TraeModelProvider.TraeModel>? {
|
private fun parseModelList(body: String): List<TraeModelProvider.TraeModel>? {
|
||||||
val root = runCatching { json.parseToJsonElement(body) as? JsonObject }.getOrNull()
|
val root = runCatching { json.parseToJsonElement(body) as? JsonObject }.getOrNull()
|
||||||
?: return null
|
?: return null
|
||||||
|
|||||||
@ -156,10 +156,12 @@ fun AccountManagementScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items(uiState.accounts, key = { it.id }) { account ->
|
items(uiState.accounts, key = { it.account.id }) { item ->
|
||||||
val ordinal = accountOrdinal(uiState.accounts, account)
|
val account = item.account
|
||||||
|
val ordinal = accountOrdinal(uiState.accounts.map { it.account }, account)
|
||||||
AccountRow(
|
AccountRow(
|
||||||
account = account,
|
account = account,
|
||||||
|
region = item.region,
|
||||||
displayName = account.label?.takeIf { it.isNotBlank() }
|
displayName = account.label?.takeIf { it.isNotBlank() }
|
||||||
?: stringResource(R.string.account_fallback_name, ordinal),
|
?: stringResource(R.string.account_fallback_name, ordinal),
|
||||||
menuExpanded = menuAccountId == account.id,
|
menuExpanded = menuAccountId == account.id,
|
||||||
@ -262,6 +264,7 @@ fun AccountManagementScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun AccountRow(
|
private fun AccountRow(
|
||||||
account: ServiceAccountInfo,
|
account: ServiceAccountInfo,
|
||||||
|
region: String?,
|
||||||
displayName: String,
|
displayName: String,
|
||||||
menuExpanded: Boolean,
|
menuExpanded: Boolean,
|
||||||
onMenuToggle: () -> Unit,
|
onMenuToggle: () -> Unit,
|
||||||
@ -306,6 +309,26 @@ private fun AccountRow(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (region != null) {
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = if (region.equals("INTL", ignoreCase = true)) {
|
||||||
|
stringResource(R.string.option_region_intl)
|
||||||
|
} else {
|
||||||
|
stringResource(R.string.option_region_cn)
|
||||||
|
},
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
color = MaterialTheme.colorScheme.outline,
|
||||||
|
maxLines = 1,
|
||||||
|
softWrap = false,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 6.dp, vertical = 2.dp)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box {
|
Box {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rainy.token.R
|
import com.rainy.token.R
|
||||||
import com.rainy.token.data.repository.CredentialRepository
|
import com.rainy.token.data.repository.CredentialRepository
|
||||||
|
import com.rainy.token.domain.model.Credential
|
||||||
import com.rainy.token.domain.model.ServiceAccountInfo
|
import com.rainy.token.domain.model.ServiceAccountInfo
|
||||||
import com.rainy.token.domain.service.ServiceType
|
import com.rainy.token.domain.service.ServiceType
|
||||||
import com.rainy.token.ui.components.UiText
|
import com.rainy.token.ui.components.UiText
|
||||||
@ -46,13 +47,22 @@ class AccountManagementViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_uiState.update { it.copy(loading = true) }
|
_uiState.update { it.copy(loading = true) }
|
||||||
val accounts = credentialRepository.accountsFor(type)
|
val accounts = credentialRepository.accountsFor(type)
|
||||||
|
val items = accounts.mapNotNull { account ->
|
||||||
|
val region = credentialRepository.get(type, account.id)
|
||||||
|
?.let { c -> when (c) {
|
||||||
|
is Credential.TraeCredential -> c.region.uppercase()
|
||||||
|
is Credential.WorkBuddyCredential -> c.region.uppercase()
|
||||||
|
else -> null
|
||||||
|
} }
|
||||||
|
AccountItem(account = account, region = region)
|
||||||
|
}
|
||||||
if (generation != loadGeneration) return@launch
|
if (generation != loadGeneration) return@launch
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
loading = false,
|
loading = false,
|
||||||
accounts = accounts,
|
accounts = items,
|
||||||
// 账号列表可能为空(用户刚删光),保持消息残留会误导,这里清掉
|
// 账号列表可能为空(用户刚删光),保持消息残留会误导,这里清掉
|
||||||
message = if (accounts.isEmpty()) null else it.message
|
message = if (items.isEmpty()) null else it.message
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,8 +100,13 @@ class AccountManagementViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class AccountItem(
|
||||||
|
val account: ServiceAccountInfo,
|
||||||
|
val region: String?,
|
||||||
|
)
|
||||||
|
|
||||||
data class AccountManagementUiState(
|
data class AccountManagementUiState(
|
||||||
val loading: Boolean = false,
|
val loading: Boolean = false,
|
||||||
val accounts: List<ServiceAccountInfo> = emptyList(),
|
val accounts: List<AccountItem> = emptyList(),
|
||||||
val message: UiText? = null
|
val message: UiText? = null
|
||||||
)
|
)
|
||||||
@ -169,6 +169,8 @@ fun CredentialEditScreen(
|
|||||||
hasExisting = uiState.hasExisting,
|
hasExisting = uiState.hasExisting,
|
||||||
onAccessChange = viewModel::updateWorkBuddyAccess,
|
onAccessChange = viewModel::updateWorkBuddyAccess,
|
||||||
onRefreshChange = viewModel::updateWorkBuddyRefresh,
|
onRefreshChange = viewModel::updateWorkBuddyRefresh,
|
||||||
|
region = uiState.workBuddyRegion,
|
||||||
|
onRegionChange = viewModel::updateWorkBuddyRegion,
|
||||||
onStartInAppLogin = { onStartWebViewLogin(ServiceType.WORKBUDDY, accountId) },
|
onStartInAppLogin = { onStartWebViewLogin(ServiceType.WORKBUDDY, accountId) },
|
||||||
onSave = viewModel::saveWorkBuddyCredential
|
onSave = viewModel::saveWorkBuddyCredential
|
||||||
)
|
)
|
||||||
@ -916,9 +918,11 @@ private fun RegionButton(label: String, selected: Boolean, onSelect: () -> Unit)
|
|||||||
private fun WorkBuddyCredentialForm(
|
private fun WorkBuddyCredentialForm(
|
||||||
access: String,
|
access: String,
|
||||||
refresh: String,
|
refresh: String,
|
||||||
|
region: String,
|
||||||
hasExisting: Boolean,
|
hasExisting: Boolean,
|
||||||
onAccessChange: (String) -> Unit,
|
onAccessChange: (String) -> Unit,
|
||||||
onRefreshChange: (String) -> Unit,
|
onRefreshChange: (String) -> Unit,
|
||||||
|
onRegionChange: (String) -> Unit,
|
||||||
onStartInAppLogin: () -> Unit,
|
onStartInAppLogin: () -> Unit,
|
||||||
onSave: () -> Unit
|
onSave: () -> Unit
|
||||||
) {
|
) {
|
||||||
@ -934,6 +938,23 @@ private fun WorkBuddyCredentialForm(
|
|||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.action_login_in_app))
|
Text(stringResource(R.string.action_login_in_app))
|
||||||
}
|
}
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.field_trae_region),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.outline
|
||||||
|
)
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
|
RegionButton(
|
||||||
|
label = stringResource(R.string.option_region_cn),
|
||||||
|
selected = region.uppercase() != "INTL",
|
||||||
|
onSelect = { onRegionChange("CN") }
|
||||||
|
)
|
||||||
|
RegionButton(
|
||||||
|
label = stringResource(R.string.option_region_intl),
|
||||||
|
selected = region.uppercase() == "INTL",
|
||||||
|
onSelect = { onRegionChange("INTL") }
|
||||||
|
)
|
||||||
|
}
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = access,
|
value = access,
|
||||||
onValueChange = onAccessChange,
|
onValueChange = onAccessChange,
|
||||||
|
|||||||
@ -126,6 +126,7 @@ class CredentialEditViewModel @Inject constructor(
|
|||||||
traeCheckinDeviceId = (existing as? Credential.TraeCredential)?.checkinDeviceId.orEmpty(),
|
traeCheckinDeviceId = (existing as? Credential.TraeCredential)?.checkinDeviceId.orEmpty(),
|
||||||
workBuddyAccess = (existing as? Credential.WorkBuddyCredential)?.accessToken.orEmpty(),
|
workBuddyAccess = (existing as? Credential.WorkBuddyCredential)?.accessToken.orEmpty(),
|
||||||
workBuddyRefresh = (existing as? Credential.WorkBuddyCredential)?.refreshToken.orEmpty(),
|
workBuddyRefresh = (existing as? Credential.WorkBuddyCredential)?.refreshToken.orEmpty(),
|
||||||
|
workBuddyRegion = (existing as? Credential.WorkBuddyCredential)?.region ?: "CN",
|
||||||
sub2BaseUrl = (existing as? Credential.Sub2ApiCredential)?.baseUrl.orEmpty(),
|
sub2BaseUrl = (existing as? Credential.Sub2ApiCredential)?.baseUrl.orEmpty(),
|
||||||
sub2SiteIcon = (existing as? Credential.Sub2ApiCredential)?.siteIcon,
|
sub2SiteIcon = (existing as? Credential.Sub2ApiCredential)?.siteIcon,
|
||||||
sub2Email = (existing as? Credential.Sub2ApiCredential)?.email.orEmpty(),
|
sub2Email = (existing as? Credential.Sub2ApiCredential)?.email.orEmpty(),
|
||||||
@ -353,6 +354,10 @@ class CredentialEditViewModel @Inject constructor(
|
|||||||
_uiState.update { it.copy(workBuddyRefresh = value) }
|
_uiState.update { it.copy(workBuddyRefresh = value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateWorkBuddyRegion(value: String) {
|
||||||
|
_uiState.update { it.copy(workBuddyRegion = value) }
|
||||||
|
}
|
||||||
|
|
||||||
fun saveWorkBuddyCredential() {
|
fun saveWorkBuddyCredential() {
|
||||||
val type = serviceType ?: return
|
val type = serviceType ?: return
|
||||||
val current = _uiState.value
|
val current = _uiState.value
|
||||||
@ -371,10 +376,11 @@ class CredentialEditViewModel @Inject constructor(
|
|||||||
credentialRepository.get(type, accountId) as? Credential.WorkBuddyCredential
|
credentialRepository.get(type, accountId) as? Credential.WorkBuddyCredential
|
||||||
}
|
}
|
||||||
val effectiveId = credentialRepository.save(
|
val effectiveId = credentialRepository.save(
|
||||||
(existing ?: Credential.WorkBuddyCredential(service = type, accessToken = access, refreshToken = refresh))
|
(existing ?: Credential.WorkBuddyCredential(service = type, accessToken = access, refreshToken = refresh, region = "CN"))
|
||||||
.copy(
|
.copy(
|
||||||
accessToken = access,
|
accessToken = access,
|
||||||
refreshToken = refresh,
|
refreshToken = refresh,
|
||||||
|
region = if (current.workBuddyRegion.uppercase() == "INTL") "INTL" else "CN",
|
||||||
expiresAt = existing?.expiresAt ?: 0L,
|
expiresAt = existing?.expiresAt ?: 0L,
|
||||||
lastVerifiedAt = existing?.lastVerifiedAt ?: 0L
|
lastVerifiedAt = existing?.lastVerifiedAt ?: 0L
|
||||||
),
|
),
|
||||||
@ -852,6 +858,7 @@ class CredentialEditViewModel @Inject constructor(
|
|||||||
traeCheckinDeviceId = "",
|
traeCheckinDeviceId = "",
|
||||||
workBuddyAccess = "",
|
workBuddyAccess = "",
|
||||||
workBuddyRefresh = "",
|
workBuddyRefresh = "",
|
||||||
|
workBuddyRegion = "CN",
|
||||||
sub2BaseUrl = "",
|
sub2BaseUrl = "",
|
||||||
sub2Email = "",
|
sub2Email = "",
|
||||||
sub2Password = "",
|
sub2Password = "",
|
||||||
@ -974,9 +981,10 @@ data class CredentialEditUiState(
|
|||||||
val traeRegion: String = "CN",
|
val traeRegion: String = "CN",
|
||||||
/** Trae 签到设备 ID(官方客户端绑定 did;留空用内置默认) */
|
/** Trae 签到设备 ID(官方客户端绑定 did;留空用内置默认) */
|
||||||
val traeCheckinDeviceId: String = "",
|
val traeCheckinDeviceId: String = "",
|
||||||
/** WorkBuddy:OAuth tokens */
|
/** WorkBuddy:OAuth tokens + 区域 */
|
||||||
val workBuddyAccess: String = "",
|
val workBuddyAccess: String = "",
|
||||||
val workBuddyRefresh: String = "",
|
val workBuddyRefresh: String = "",
|
||||||
|
val workBuddyRegion: String = "CN",
|
||||||
/** Sub2API:自托管实例连接 */
|
/** Sub2API:自托管实例连接 */
|
||||||
val sub2BaseUrl: String = "",
|
val sub2BaseUrl: String = "",
|
||||||
val sub2Email: String = "",
|
val sub2Email: String = "",
|
||||||
|
|||||||
@ -84,7 +84,7 @@ class SettingsViewModel @Inject constructor(
|
|||||||
private val _selectedProxy = MutableStateFlow(ProxyTarget.TRAE_CN)
|
private val _selectedProxy = MutableStateFlow(ProxyTarget.TRAE_CN)
|
||||||
val selectedProxy: StateFlow<ProxyTarget> = _selectedProxy.asStateFlow()
|
val selectedProxy: StateFlow<ProxyTarget> = _selectedProxy.asStateFlow()
|
||||||
|
|
||||||
private val _proxyModels = MutableStateFlow<List<TraeModelProvider.TraeModel>>(traeModelProvider.models.value)
|
private val _proxyModels = MutableStateFlow<List<TraeModelProvider.TraeModel>>(traeModelProvider.modelsFor(ProviderRegion.CN))
|
||||||
val proxyModels: StateFlow<List<TraeModelProvider.TraeModel>> = _proxyModels.asStateFlow()
|
val proxyModels: StateFlow<List<TraeModelProvider.TraeModel>> = _proxyModels.asStateFlow()
|
||||||
|
|
||||||
private val _proxyModel = MutableStateFlow(traeModelProvider.selectedFor(ProviderRegion.CN))
|
private val _proxyModel = MutableStateFlow(traeModelProvider.selectedFor(ProviderRegion.CN))
|
||||||
@ -95,8 +95,8 @@ class SettingsViewModel @Inject constructor(
|
|||||||
_selectedProxy.value = target
|
_selectedProxy.value = target
|
||||||
val region = target.region()
|
val region = target.region()
|
||||||
_proxyModels.value = when (target) {
|
_proxyModels.value = when (target) {
|
||||||
ProxyTarget.TRAE_CN, ProxyTarget.TRAE_INTL -> traeModelProvider.models.value
|
ProxyTarget.TRAE_CN, ProxyTarget.TRAE_INTL -> traeModelProvider.modelsFor(region)
|
||||||
else -> workBuddyModelProvider.models.value
|
else -> workBuddyModelProvider.modelsFor(region)
|
||||||
}
|
}
|
||||||
_proxyModel.value = when (target) {
|
_proxyModel.value = when (target) {
|
||||||
ProxyTarget.TRAE_CN, ProxyTarget.TRAE_INTL -> traeModelProvider.selectedFor(region)
|
ProxyTarget.TRAE_CN, ProxyTarget.TRAE_INTL -> traeModelProvider.selectedFor(region)
|
||||||
@ -125,8 +125,8 @@ class SettingsViewModel @Inject constructor(
|
|||||||
else -> workBuddyModelProvider.refreshFor(region)
|
else -> workBuddyModelProvider.refreshFor(region)
|
||||||
}
|
}
|
||||||
_proxyModels.value = when (target) {
|
_proxyModels.value = when (target) {
|
||||||
ProxyTarget.TRAE_CN, ProxyTarget.TRAE_INTL -> traeModelProvider.models.value
|
ProxyTarget.TRAE_CN, ProxyTarget.TRAE_INTL -> traeModelProvider.modelsFor(region)
|
||||||
else -> workBuddyModelProvider.models.value
|
else -> workBuddyModelProvider.modelsFor(region)
|
||||||
}
|
}
|
||||||
if (!ok) _proxyDebug.value = "模型列表更新失败(当前显示内置列表)"
|
if (!ok) _proxyDebug.value = "模型列表更新失败(当前显示内置列表)"
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user