Fix license list loading and crash on duplicate subs.
Read admin token from DataStore before API calls, reload licenses after save, and use unique product key as LazyColumn item key. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,12 +4,11 @@ import android.app.Application
|
|||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.update
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import ru.mailib.ttrpg.licensemanager.data.AppSettings
|
import ru.mailib.ttrpg.licensemanager.data.AppSettings
|
||||||
import ru.mailib.ttrpg.licensemanager.data.CreateProductKeyRequest
|
import ru.mailib.ttrpg.licensemanager.data.CreateProductKeyRequest
|
||||||
import ru.mailib.ttrpg.licensemanager.data.LicenseEntry
|
import ru.mailib.ttrpg.licensemanager.data.LicenseEntry
|
||||||
@@ -45,8 +44,7 @@ class LicenseViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
private val settingsRepository = SettingsRepository(application)
|
private val settingsRepository = SettingsRepository(application)
|
||||||
private val licenseRepository = LicenseRepository(settingsRepository)
|
private val licenseRepository = LicenseRepository(settingsRepository)
|
||||||
|
|
||||||
val settings: StateFlow<AppSettings> = settingsRepository.settings
|
private suspend fun currentSettings(): AppSettings = settingsRepository.settings.first()
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), AppSettings())
|
|
||||||
|
|
||||||
private val _listState = MutableStateFlow(LicenseListUiState())
|
private val _listState = MutableStateFlow(LicenseListUiState())
|
||||||
val listState: StateFlow<LicenseListUiState> = _listState.asStateFlow()
|
val listState: StateFlow<LicenseListUiState> = _listState.asStateFlow()
|
||||||
@@ -59,17 +57,14 @@ class LicenseViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
settings.collect { appSettings ->
|
val initial = settingsRepository.settings.first()
|
||||||
_settingsState.update {
|
_settingsState.update { it.copy(adminToken = initial.adminToken) }
|
||||||
it.copy(adminToken = appSettings.adminToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadLicenses() {
|
fun loadLicenses() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val currentSettings = settings.value
|
val currentSettings = currentSettings()
|
||||||
_listState.update { it.copy(isLoading = true, error = null) }
|
_listState.update { it.copy(isLoading = true, error = null) }
|
||||||
licenseRepository.listLicenses(currentSettings)
|
licenseRepository.listLicenses(currentSettings)
|
||||||
.onSuccess { licenses ->
|
.onSuccess { licenses ->
|
||||||
@@ -84,7 +79,7 @@ class LicenseViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
fun revokeLicense(sub: String) {
|
fun revokeLicense(sub: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_listState.update { it.copy(revokingSub = sub, error = null) }
|
_listState.update { it.copy(revokingSub = sub, error = null) }
|
||||||
licenseRepository.revokeLicense(settings.value, sub)
|
licenseRepository.revokeLicense(currentSettings(), sub)
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
loadLicenses()
|
loadLicenses()
|
||||||
_listState.update { it.copy(revokingSub = null) }
|
_listState.update { it.copy(revokingSub = null) }
|
||||||
@@ -136,7 +131,7 @@ class LicenseViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_generateState.update { it.copy(isSubmitting = true, error = null, createdKey = null) }
|
_generateState.update { it.copy(isSubmitting = true, error = null, createdKey = null) }
|
||||||
licenseRepository.createProductKey(
|
licenseRepository.createProductKey(
|
||||||
settings.value,
|
currentSettings(),
|
||||||
CreateProductKeyRequest(
|
CreateProductKeyRequest(
|
||||||
pid = state.pid.trim(),
|
pid = state.pid.trim(),
|
||||||
maxDevices = maxDevices,
|
maxDevices = maxDevices,
|
||||||
@@ -161,11 +156,13 @@ class LicenseViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveSettings() {
|
fun saveSettings(onSaved: () -> Unit = {}) {
|
||||||
val draft = _settingsState.value
|
val draft = _settingsState.value
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
settingsRepository.save(draft.adminToken)
|
settingsRepository.save(draft.adminToken)
|
||||||
_settingsState.update { it.copy(savedMessage = "Сохранено") }
|
_settingsState.update { it.copy(savedMessage = "Сохранено") }
|
||||||
|
loadLicenses()
|
||||||
|
onSaved()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ fun LicenseListScreen(viewModel: LicenseViewModel) {
|
|||||||
ErrorMessage(message = state.error ?: "")
|
ErrorMessage(message = state.error ?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items(state.licenses, key = { it.sub }) { license ->
|
items(state.licenses, key = { it.key }) { license ->
|
||||||
LicenseCard(
|
LicenseCard(
|
||||||
license = license,
|
license = license,
|
||||||
isRevoking = state.revokingSub == license.sub,
|
isRevoking = state.revokingSub == license.sub,
|
||||||
|
|||||||
@@ -64,10 +64,7 @@ fun SettingsScreen(viewModel: LicenseViewModel, onBack: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = { viewModel.saveSettings(onSaved = onBack) },
|
||||||
viewModel.saveSettings()
|
|
||||||
onBack()
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
Text("Сохранить")
|
Text("Сохранить")
|
||||||
|
|||||||
Reference in New Issue
Block a user