fix(settings): keep the update badge across PROCESS_TEXT relaunches
Persist NeedsUpdate with its source ids and restore today's persisted status — UpToDate and NeedsUpdate alike — through one shared helper used by both startup paths, falling back to a fresh evaluation when the persisted status can no longer be trusted (stale date, removed sources, or the update already installed).
This commit is contained in:
1 parent
731340fd13
commit
e20af9c1ff
1 file changed
+88
-26
@@ -37,6 +37,16 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
private const val STATUS_UP_TO_DATE = "UpToDate"
|
||||||
|
private const val STATUS_NEEDS_UPDATE = "NeedsUpdate"
|
||||||
|
private const val STATUS_EMPTY = "Empty"
|
||||||
|
|
||||||
|
private data class PersistedDictionaryStatus(
|
||||||
|
val name: String,
|
||||||
|
val date: String,
|
||||||
|
val sourceIds: Set<String>,
|
||||||
|
)
|
||||||
|
|
||||||
private data class DictionaryStateInputs(
|
private data class DictionaryStateInputs(
|
||||||
val theme: AppTheme,
|
val theme: AppTheme,
|
||||||
val dictionarySources: List<DictionarySource>,
|
val dictionarySources: List<DictionarySource>,
|
||||||
@@ -115,14 +125,18 @@ class SettingsViewModel(
|
|||||||
private fun persistDictionaryStatus() {
|
private fun persistDictionaryStatus() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
dictionaryStatus.collect { status ->
|
dictionaryStatus.collect { status ->
|
||||||
val persistedName = when (status) {
|
val persisted = when (status) {
|
||||||
DictionaryStatus.UpToDate -> "UpToDate"
|
DictionaryStatus.UpToDate ->
|
||||||
is DictionaryStatus.NeedsUpdate -> "NeedsUpdate"
|
"$STATUS_UP_TO_DATE|${DateUtils.getCurrentDateString()}"
|
||||||
DictionaryStatus.Empty -> "Empty"
|
is DictionaryStatus.NeedsUpdate ->
|
||||||
|
"$STATUS_NEEDS_UPDATE|${DateUtils.getCurrentDateString()}|" +
|
||||||
|
status.sourceIds.joinToString(",")
|
||||||
|
DictionaryStatus.Empty ->
|
||||||
|
"$STATUS_EMPTY|${DateUtils.getCurrentDateString()}"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (persistedName != null) {
|
if (persisted != null) {
|
||||||
preferencesManager.saveDictionaryStatus("$persistedName|${DateUtils.getCurrentDateString()}")
|
preferencesManager.saveDictionaryStatus(persisted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,7 +297,7 @@ class SettingsViewModel(
|
|||||||
scanCompleted = if (localDictionaryRepository.dictionaries.value.isEmpty()) {
|
scanCompleted = if (localDictionaryRepository.dictionaries.value.isEmpty()) {
|
||||||
scanDirectoryInternal(preferencesManager.dictionaryPath) is OperationResult.Success
|
scanDirectoryInternal(preferencesManager.dictionaryPath) is OperationResult.Success
|
||||||
} else {
|
} else {
|
||||||
dictionaryStatus.value = DictionaryStatus.UpToDate
|
restoreOrEvaluateDictionaryStatus()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -551,6 +565,71 @@ class SettingsViewModel(
|
|||||||
): List<DictionarySource> =
|
): List<DictionarySource> =
|
||||||
DictionarySourceFileMatcher.installedSources(sources, dictionaries)
|
DictionarySourceFileMatcher.installedSources(sources, dictionaries)
|
||||||
|
|
||||||
|
private suspend fun restoreOrEvaluateDictionaryStatus() {
|
||||||
|
val restored = restorePersistedDictionaryStatus()
|
||||||
|
if (restored != null) {
|
||||||
|
dictionaryStatus.value = restored
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dictionaryStatus.value = DictionaryStatus.Checking
|
||||||
|
dictionaryStatus.value = withContext(Dispatchers.IO) { evaluateDictionaryStatus() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun restorePersistedDictionaryStatus(): DictionaryStatus? {
|
||||||
|
val persisted = readPersistedDictionaryStatus() ?: return null
|
||||||
|
if (persisted.date != DateUtils.getCurrentDateString()) return null
|
||||||
|
return when (persisted.name) {
|
||||||
|
STATUS_UP_TO_DATE ->
|
||||||
|
if (withContext(Dispatchers.IO) { installedDictionariesAreCurrent() }) {
|
||||||
|
DictionaryStatus.UpToDate
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
STATUS_NEEDS_UPDATE -> {
|
||||||
|
val updatableIds = withContext(Dispatchers.IO) { sourcesMissingTodaysFile() }
|
||||||
|
val restorableIds = persisted.sourceIds intersect updatableIds
|
||||||
|
if (restorableIds.isNotEmpty()) DictionaryStatus.NeedsUpdate(restorableIds) else null
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun readPersistedDictionaryStatus(): PersistedDictionaryStatus? {
|
||||||
|
val raw = preferencesManager.dictionaryStatus() ?: return null
|
||||||
|
val parts = raw.split('|')
|
||||||
|
if (parts.isEmpty() || parts.first().isEmpty()) return null
|
||||||
|
return PersistedDictionaryStatus(
|
||||||
|
name = parts.first(),
|
||||||
|
date = parts.getOrElse(1) { "" },
|
||||||
|
sourceIds = parts.getOrElse(2) { "" }
|
||||||
|
.split(',')
|
||||||
|
.map(String::trim)
|
||||||
|
.filter(String::isNotEmpty)
|
||||||
|
.toSet(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun sourcesMissingTodaysFile(): Set<String> {
|
||||||
|
val sources = preferencesManager.dictionarySources.first()
|
||||||
|
val dictionaries = localDictionaryRepository.dictionaries.first()
|
||||||
|
val datedEnabledSources = installedEnabledSources(sources, dictionaries)
|
||||||
|
.filter { DictionarySource.hasDatePlaceholder(it.urlTemplate) }
|
||||||
|
if (datedEnabledSources.isEmpty()) return emptySet()
|
||||||
|
val fileNames = localDictionaryRepository.listDictionaryPayloadFileNames(
|
||||||
|
preferencesManager.dictionaryPath
|
||||||
|
) ?: return emptySet()
|
||||||
|
val today = DateUtils.getCurrentDateString()
|
||||||
|
return datedEnabledSources
|
||||||
|
.filterNot { source -> fileNames.any { it.startsWith(fileBaseNameFor(source, today)) } }
|
||||||
|
.mapTo(mutableSetOf(), DictionarySource::id)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fileBaseNameFor(source: DictionarySource, date: String): String =
|
||||||
|
DictionarySource.extractFileName(source.urlTemplate, date)
|
||||||
|
.removeSuffix(".gz")
|
||||||
|
.removeSuffix(".dsl")
|
||||||
|
.removeSuffix(".dz")
|
||||||
|
|
||||||
private suspend fun installedDictionariesAreCurrent(): Boolean {
|
private suspend fun installedDictionariesAreCurrent(): Boolean {
|
||||||
val sources = preferencesManager.dictionarySources.first()
|
val sources = preferencesManager.dictionarySources.first()
|
||||||
val dictionaries = localDictionaryRepository.dictionaries.first()
|
val dictionaries = localDictionaryRepository.dictionaries.first()
|
||||||
@@ -562,11 +641,7 @@ class SettingsViewModel(
|
|||||||
) ?: return true
|
) ?: return true
|
||||||
val today = DateUtils.getCurrentDateString()
|
val today = DateUtils.getCurrentDateString()
|
||||||
return datedEnabledSources.all { source ->
|
return datedEnabledSources.all { source ->
|
||||||
val baseName = DictionarySource.extractFileName(source.urlTemplate, today)
|
fileNames.any { it.startsWith(fileBaseNameFor(source, today)) }
|
||||||
.removeSuffix(".gz")
|
|
||||||
.removeSuffix(".dsl")
|
|
||||||
.removeSuffix(".dz")
|
|
||||||
fileNames.any { it.startsWith(baseName) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,20 +697,7 @@ class SettingsViewModel(
|
|||||||
dictionaryStatus.value = DictionaryStatus.UpToDate
|
dictionaryStatus.value = DictionaryStatus.UpToDate
|
||||||
isDownloadInProgress = false
|
isDownloadInProgress = false
|
||||||
} else {
|
} else {
|
||||||
val savedStatus = preferencesManager.dictionaryStatus()
|
restoreOrEvaluateDictionaryStatus()
|
||||||
val savedStatusName = savedStatus?.substringBefore('|')
|
|
||||||
val savedStatusDate = savedStatus?.substringAfter('|', "")
|
|
||||||
val restoredStatus = if (savedStatusName == "UpToDate") DictionaryStatus.UpToDate else null
|
|
||||||
if (restoredStatus != null &&
|
|
||||||
savedStatusDate == DateUtils.getCurrentDateString() &&
|
|
||||||
withContext(Dispatchers.IO) { installedDictionariesAreCurrent() }
|
|
||||||
) {
|
|
||||||
dictionaryStatus.value = restoredStatus
|
|
||||||
} else {
|
|
||||||
dictionaryStatus.value = DictionaryStatus.Checking
|
|
||||||
val status = withContext(Dispatchers.IO) { evaluateDictionaryStatus() }
|
|
||||||
dictionaryStatus.value = status
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.data > 0) {
|
if (result.data > 0) {
|
||||||
|
|||||||
Reference in new issue
Block a user