Hardcode production license server URL in app.
Remove editable server URL from settings; only admin token is configured by user. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -17,30 +17,29 @@ import retrofit2.converter.gson.GsonConverterFactory
|
|||||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||||
|
|
||||||
data class AppSettings(
|
data class AppSettings(
|
||||||
val serverUrl: String = DEFAULT_SERVER_URL,
|
val serverUrl: String = SERVER_URL,
|
||||||
val adminToken: String = "",
|
val adminToken: String = "",
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val DEFAULT_SERVER_URL = "https://license.mailib.ru/"
|
/** Продакшен-сервер лицензий (захардкожен, не меняется в UI). */
|
||||||
|
const val SERVER_URL = "https://license.mailib.ru/"
|
||||||
|
@Deprecated("Use SERVER_URL", ReplaceWith("SERVER_URL"))
|
||||||
|
const val DEFAULT_SERVER_URL = SERVER_URL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsRepository(private val context: Context) {
|
class SettingsRepository(private val context: Context) {
|
||||||
private val serverUrlKey = stringPreferencesKey("server_url")
|
|
||||||
private val adminTokenKey = stringPreferencesKey("admin_token")
|
private val adminTokenKey = stringPreferencesKey("admin_token")
|
||||||
|
|
||||||
val settings: Flow<AppSettings> = context.dataStore.data.map { prefs ->
|
val settings: Flow<AppSettings> = context.dataStore.data.map { prefs ->
|
||||||
AppSettings(
|
AppSettings(
|
||||||
serverUrl = prefs[serverUrlKey] ?: AppSettings.DEFAULT_SERVER_URL,
|
serverUrl = AppSettings.SERVER_URL,
|
||||||
adminToken = prefs[adminTokenKey].orEmpty(),
|
adminToken = prefs[adminTokenKey].orEmpty(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun save(serverUrl: String, adminToken: String) {
|
suspend fun save(adminToken: String) {
|
||||||
context.dataStore.edit { prefs ->
|
context.dataStore.edit { prefs ->
|
||||||
prefs[serverUrlKey] = serverUrl.trim().let { url ->
|
|
||||||
if (url.endsWith("/")) url else "$url/"
|
|
||||||
}
|
|
||||||
prefs[adminTokenKey] = adminToken.trim()
|
prefs[adminTokenKey] = adminToken.trim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ data class GenerateKeyUiState(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data class SettingsUiState(
|
data class SettingsUiState(
|
||||||
val serverUrl: String = AppSettings.DEFAULT_SERVER_URL,
|
|
||||||
val adminToken: String = "",
|
val adminToken: String = "",
|
||||||
val savedMessage: String? = null,
|
val savedMessage: String? = null,
|
||||||
)
|
)
|
||||||
@@ -62,10 +61,7 @@ class LicenseViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
settings.collect { appSettings ->
|
settings.collect { appSettings ->
|
||||||
_settingsState.update {
|
_settingsState.update {
|
||||||
it.copy(
|
it.copy(adminToken = appSettings.adminToken)
|
||||||
serverUrl = appSettings.serverUrl,
|
|
||||||
adminToken = appSettings.adminToken,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,16 +155,16 @@ class LicenseViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSettingsDraft(serverUrl: String, adminToken: String) {
|
fun updateAdminToken(value: String) {
|
||||||
_settingsState.update {
|
_settingsState.update {
|
||||||
it.copy(serverUrl = serverUrl, adminToken = adminToken, savedMessage = null)
|
it.copy(adminToken = value, savedMessage = null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveSettings() {
|
fun saveSettings() {
|
||||||
val draft = _settingsState.value
|
val draft = _settingsState.value
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
settingsRepository.save(draft.serverUrl, draft.adminToken)
|
settingsRepository.save(draft.adminToken)
|
||||||
_settingsState.update { it.copy(savedMessage = "Сохранено") }
|
_settingsState.update { it.copy(savedMessage = "Сохранено") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import ru.mailib.ttrpg.licensemanager.data.AppSettings
|
||||||
import ru.mailib.ttrpg.licensemanager.ui.LicenseViewModel
|
import ru.mailib.ttrpg.licensemanager.ui.LicenseViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -29,23 +30,27 @@ fun SettingsScreen(viewModel: LicenseViewModel, onBack: () -> Unit) {
|
|||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Настройки сервера",
|
text = "Настройки",
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
)
|
)
|
||||||
|
|
||||||
OutlinedTextField(
|
Text(
|
||||||
value = state.serverUrl,
|
text = "Сервер: ${AppSettings.SERVER_URL}",
|
||||||
onValueChange = { value -> viewModel.updateSettingsDraft(value, state.adminToken) },
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
label = { Text("URL сервера") },
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
)
|
||||||
singleLine = true,
|
|
||||||
|
Text(
|
||||||
|
text = "Токен администратора (LICENSE_ADMIN_TOKEN) — см. инструкцию в README или спросите у администратора сервера.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = state.adminToken,
|
value = state.adminToken,
|
||||||
onValueChange = { value -> viewModel.updateSettingsDraft(state.serverUrl, value) },
|
onValueChange = viewModel::updateAdminToken,
|
||||||
label = { Text("Admin token (LICENSE_ADMIN_TOKEN)") },
|
label = { Text("Admin token") },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
|
|||||||
Reference in New Issue
Block a user