Add a new entry in the developer settings to check the store sizes

This commit is contained in:
Jorge Martín
2025-12-16 16:53:16 +01:00
committed by Jorge Martin Espinosa
parent 20c0d0190e
commit b201b40639
5 changed files with 62 additions and 0 deletions

View File

@@ -31,21 +31,26 @@ import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase
import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase
import io.element.android.features.preferences.impl.tasks.VacuumStoresUseCase
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState
import io.element.android.libraries.androidutils.filesize.FileSizeFormatter
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.core.data.ByteUnit
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
import io.element.android.libraries.matrix.api.analytics.GetDatabaseSizesUseCase
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
@@ -63,6 +68,8 @@ class DeveloperSettingsPresenter(
private val buildMeta: BuildMeta,
private val enterpriseService: EnterpriseService,
private val vacuumStoresUseCase: VacuumStoresUseCase,
private val databaseSizesUseCase: GetDatabaseSizesUseCase,
private val fileSizeFormatter: FileSizeFormatter,
) : Presenter<DeveloperSettingsState> {
@Composable
override fun present(): DeveloperSettingsState {
@@ -73,6 +80,9 @@ class DeveloperSettingsPresenter(
val cacheSize = remember {
mutableStateOf<AsyncData<String>>(AsyncData.Uninitialized)
}
val databaseSizes = remember {
mutableStateOf<AsyncData<ImmutableMap<String, String>>>(AsyncData.Uninitialized)
}
val clearCacheAction = remember {
mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
}
@@ -96,6 +106,7 @@ class DeveloperSettingsPresenter(
}
LaunchedEffect(Unit) {
computeDatabaseSizes(databaseSizes)
featureFlagService.getAvailableFeatures()
.run {
// Never display room directory search in release builds for Play Store
@@ -162,6 +173,7 @@ class DeveloperSettingsPresenter(
return DeveloperSettingsState(
features = featureUiModels,
cacheSize = cacheSize.value,
databaseSizes = databaseSizes.value,
clearCacheAction = clearCacheAction.value,
rageshakeState = rageshakeState,
customElementCallBaseUrlState = CustomElementCallBaseUrlState(
@@ -214,6 +226,27 @@ class DeveloperSettingsPresenter(
}.runCatchingUpdatingState(cacheSize)
}
private fun CoroutineScope.computeDatabaseSizes(databaseSizes: MutableState<AsyncData<ImmutableMap<String, String>>>) = launch {
suspend {
databaseSizesUseCase(sessionId).getOrThrow().let { sizes ->
buildMap {
sizes.stateStore?.let { stateStoreSize ->
put("State store", fileSizeFormatter.format(stateStoreSize.into(ByteUnit.BYTES), useShortFormat = true))
}
sizes.eventCacheStore?.let { eventCacheStoreSize ->
put("Event cache store", fileSizeFormatter.format(eventCacheStoreSize.into(ByteUnit.BYTES), useShortFormat = true))
}
sizes.mediaStore?.let { mediaStoreSize ->
put("Media store", fileSizeFormatter.format(mediaStoreSize.into(ByteUnit.BYTES), useShortFormat = true))
}
sizes.cryptoStore?.let { cryptoStoreSize ->
put("Crypto store", fileSizeFormatter.format(cryptoStoreSize.into(ByteUnit.BYTES), useShortFormat = true))
}
}
}.toImmutableMap()
}.runCatchingUpdatingState(databaseSizes)
}
private fun CoroutineScope.clearCache(clearCacheAction: MutableState<AsyncAction<Unit>>) = launch {
suspend {
clearCacheUseCase()

View File

@@ -15,10 +15,12 @@ import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap
data class DeveloperSettingsState(
val features: ImmutableList<FeatureUiModel>,
val cacheSize: AsyncData<String>,
val databaseSizes: AsyncData<ImmutableMap<String, String>>,
val rageshakeState: RageshakePreferencesState,
val clearCacheAction: AsyncAction<Unit>,
val customElementCallBaseUrlState: CustomElementCallBaseUrlState,

View File

@@ -15,6 +15,7 @@ import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.featureflag.ui.model.aFeatureUiModelList
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableList
open class DeveloperSettingsStateProvider : PreviewParameterProvider<DeveloperSettingsState> {
@@ -47,6 +48,7 @@ fun aDeveloperSettingsState(
features = aFeatureUiModelList(),
rageshakeState = aRageshakePreferencesState(),
cacheSize = AsyncData.Success("1.2 MB"),
databaseSizes = AsyncData.Success(persistentMapOf("state_store" to "1.2MB")),
clearCacheAction = clearCacheAction,
customElementCallBaseUrlState = customElementCallBaseUrlState,
tracingLogLevel = AsyncData.Success(LogLevelItem.INFO),

View File

@@ -9,6 +9,7 @@
package io.element.android.features.preferences.impl.developer
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.progressSemantics
@@ -146,6 +147,25 @@ fun DeveloperSettingsView(
}
val cache = state.cacheSize
PreferenceCategory(title = "Cache") {
ListItem(
headlineContent = { Text("Database sizes") },
supportingContent = {
if (state.databaseSizes.isLoading()) {
Text("Computing...")
} else {
val dbSizes = state.databaseSizes.dataOrNull()
if (dbSizes != null && dbSizes.isNotEmpty()) {
Column {
for ((dbName, size) in dbSizes) {
Text("$dbName: $size")
}
}
} else {
Text("Unknown")
}
}
}
)
ListItem(
headlineContent = {
Text("Vacuum stores")

View File

@@ -19,6 +19,7 @@ import io.element.android.features.preferences.impl.tasks.FakeClearCacheUseCase
import io.element.android.features.preferences.impl.tasks.FakeComputeCacheSizeUseCase
import io.element.android.features.preferences.impl.tasks.VacuumStoresUseCase
import io.element.android.features.rageshake.api.preferences.aRageshakePreferencesState
import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.core.meta.BuildMeta
@@ -27,6 +28,7 @@ import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeature
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.analytics.GetDatabaseSizesUseCase
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.core.aBuildMeta
@@ -249,6 +251,7 @@ class DeveloperSettingsPresenterTest {
buildMeta: BuildMeta = aBuildMeta(),
enterpriseService: EnterpriseService = FakeEnterpriseService(),
vacuumStoresUseCase: VacuumStoresUseCase = VacuumStoresUseCase {},
datbaseSizesUseCase: GetDatabaseSizesUseCase = GetDatabaseSizesUseCase { Result.success(emptyMap()) },
): DeveloperSettingsPresenter {
return DeveloperSettingsPresenter(
sessionId = sessionId,
@@ -260,6 +263,8 @@ class DeveloperSettingsPresenterTest {
buildMeta = buildMeta,
enterpriseService = enterpriseService,
vacuumStoresUseCase = vacuumStoresUseCase,
databaseSizesUseCase = datbaseSizesUseCase,
fileSizeFormatter = FakeFileSizeFormatter(),
)
}
}