Улучшение UI/UX
This commit is contained in:
@@ -254,13 +254,16 @@ fun MainScreen(
|
||||
val route: TextSecretEditRoute = entry.toRoute()
|
||||
TextSecretEditScreen(
|
||||
onSaved = { savedSecretId ->
|
||||
val editingExisting = route.secretId != null
|
||||
navState.navHostController.popBackStack()
|
||||
navState.push(
|
||||
TextSecretDetailsRoute(
|
||||
storageUuid = route.storageUuid,
|
||||
secretId = savedSecretId,
|
||||
),
|
||||
)
|
||||
if (!editingExisting) {
|
||||
navState.push(
|
||||
TextSecretDetailsRoute(
|
||||
storageUuid = route.storageUuid,
|
||||
secretId = savedSecretId,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,20 +2,26 @@ package com.github.nullptroma.wallenc.ui.screens.main.screens.storage
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Lock
|
||||
import androidx.compose.material.icons.outlined.Notes
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
@@ -83,45 +89,21 @@ fun StorageHomeScreen(
|
||||
)
|
||||
}
|
||||
|
||||
Card(colors = CardDefaults.cardColors()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.storage_home_two_fa_title, uiState.twoFaCount),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
Button(
|
||||
onClick = { onOpenTwoFa(uiState.storageUuid) },
|
||||
enabled = uiState.isAvailable,
|
||||
) {
|
||||
Text(stringResource(R.string.storage_home_open_two_fa))
|
||||
}
|
||||
}
|
||||
}
|
||||
StorageSectionCard(
|
||||
title = stringResource(R.string.storage_home_two_fa_title, uiState.twoFaCount),
|
||||
description = stringResource(R.string.storage_home_two_fa_subtitle),
|
||||
icon = Icons.Outlined.Lock,
|
||||
enabled = uiState.isAvailable,
|
||||
onClick = { onOpenTwoFa(uiState.storageUuid) },
|
||||
)
|
||||
|
||||
Card(colors = CardDefaults.cardColors()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.storage_home_text_secrets_title, uiState.textSecretsCount),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
Button(
|
||||
onClick = { onOpenTextSecrets(uiState.storageUuid) },
|
||||
enabled = uiState.isAvailable,
|
||||
) {
|
||||
Text(stringResource(R.string.storage_home_open_text_secrets))
|
||||
}
|
||||
}
|
||||
}
|
||||
StorageSectionCard(
|
||||
title = stringResource(R.string.storage_home_text_secrets_title, uiState.textSecretsCount),
|
||||
description = stringResource(R.string.storage_home_text_secrets_subtitle),
|
||||
icon = Icons.Outlined.Notes,
|
||||
enabled = uiState.isAvailable,
|
||||
onClick = { onOpenTextSecrets(uiState.storageUuid) },
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.storage_home_future_sections),
|
||||
@@ -131,3 +113,48 @@ fun StorageHomeScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StorageSectionCard(
|
||||
title: String,
|
||||
description: String,
|
||||
icon: ImageVector,
|
||||
enabled: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
),
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(28.dp),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
Text(
|
||||
text = description,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.github.nullptroma.wallenc.usecases.FindStorageUseCase
|
||||
import com.github.nullptroma.wallenc.usecases.ManageTextSecretsUseCase
|
||||
import com.github.nullptroma.wallenc.usecases.ManageTwoFaTokensUseCase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -22,10 +22,10 @@ class StorageHomeViewModel @Inject constructor(
|
||||
private val storageUuid = savedStateHandle.requireStorageUuid()
|
||||
|
||||
init {
|
||||
refresh()
|
||||
observeStorageState()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
private fun observeStorageState() {
|
||||
viewModelScope.launch {
|
||||
val storage = findStorageUseCase.find(storageUuid)
|
||||
if (storage == null) {
|
||||
@@ -38,21 +38,25 @@ class StorageHomeViewModel @Inject constructor(
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val twoFa = manageTwoFaTokensUseCase.list(storage)
|
||||
val secrets = manageTextSecretsUseCase.list(storage)
|
||||
updateState(
|
||||
combine(
|
||||
storage.isAvailable,
|
||||
storage.metaInfo,
|
||||
manageTwoFaTokensUseCase.observe(storage),
|
||||
manageTextSecretsUseCase.observe(storage),
|
||||
) { available, meta, twoFa, secrets ->
|
||||
state.value.copy(
|
||||
isLoading = false,
|
||||
storageUuid = storage.uuid.toString(),
|
||||
storageName = storage.metaInfo.value.name.orEmpty(),
|
||||
isAvailable = storage.isAvailable.first(),
|
||||
isEncrypted = storage.metaInfo.value.encInfo != null,
|
||||
storageName = meta.name.orEmpty(),
|
||||
isAvailable = available,
|
||||
isEncrypted = meta.encInfo != null,
|
||||
twoFaCount = twoFa.size,
|
||||
textSecretsCount = secrets.size,
|
||||
errorMessage = null,
|
||||
),
|
||||
)
|
||||
)
|
||||
}.collect { ui ->
|
||||
updateState(ui)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
@@ -64,12 +66,28 @@ fun TextSecretDetailsScreen(
|
||||
|
||||
LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
items(secret.items) { item ->
|
||||
Column {
|
||||
Text(
|
||||
text = item.label ?: stringResource(R.string.text_secret_item_without_label),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
)
|
||||
Text(text = item.value)
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = item.label ?: stringResource(R.string.text_secret_item_without_label),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Text(
|
||||
text = item.value,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import com.github.nullptroma.wallenc.ui.screens.main.screens.storage.requireStor
|
||||
import com.github.nullptroma.wallenc.usecases.FindStorageUseCase
|
||||
import com.github.nullptroma.wallenc.usecases.ManageTextSecretsUseCase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -23,10 +24,10 @@ class TextSecretDetailsViewModel @Inject constructor(
|
||||
?: error("Missing secret id")
|
||||
|
||||
init {
|
||||
refresh()
|
||||
observeSecret()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
private fun observeSecret() {
|
||||
viewModelScope.launch {
|
||||
val storage = findStorageUseCase.find(storageUuid)
|
||||
if (storage == null) {
|
||||
@@ -38,15 +39,21 @@ class TextSecretDetailsViewModel @Inject constructor(
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
val secret = manageTextSecretsUseCase.get(storage, secretId)
|
||||
updateState(
|
||||
combine(
|
||||
storage.isAvailable,
|
||||
manageTextSecretsUseCase.observe(storage).map { list ->
|
||||
list.firstOrNull { it.id == secretId }
|
||||
},
|
||||
) { available, secret ->
|
||||
state.value.copy(
|
||||
isLoading = false,
|
||||
isAvailable = storage.isAvailable.first(),
|
||||
isAvailable = available,
|
||||
secret = secret,
|
||||
errorMessage = if (secret == null) "Secret not found" else null,
|
||||
),
|
||||
)
|
||||
)
|
||||
}.collect { ui ->
|
||||
updateState(ui)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,15 @@ import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.outlined.Notes
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -68,28 +73,51 @@ fun TextSecretsScreen(
|
||||
} else {
|
||||
LazyColumn(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
items(uiState.items) { secret ->
|
||||
Row(
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
onClick = { onOpenSecret(secret) },
|
||||
enabled = uiState.isAvailable,
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 12.dp),
|
||||
.fillMaxWidth()
|
||||
.padding(14.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(text = secret.title)
|
||||
Text(
|
||||
text = stringResource(R.string.text_secret_items_count, secret.items.size),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
Row(
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Notes,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(22.dp)
|
||||
.padding(top = 2.dp),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.padding(end = 12.dp),
|
||||
) {
|
||||
Text(
|
||||
text = secret.title,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.text_secret_items_count, secret.items.size),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
Icon(
|
||||
imageVector = Icons.Default.KeyboardArrowRight,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
androidx.compose.material3.TextButton(
|
||||
onClick = { onOpenSecret(secret) },
|
||||
enabled = uiState.isAvailable,
|
||||
) {
|
||||
Text(stringResource(R.string.open))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.github.nullptroma.wallenc.ui.screens.main.screens.storage.requireStor
|
||||
import com.github.nullptroma.wallenc.usecases.FindStorageUseCase
|
||||
import com.github.nullptroma.wallenc.usecases.ManageTextSecretsUseCase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -21,10 +21,10 @@ class TextSecretsViewModel @Inject constructor(
|
||||
private val storageUuid = savedStateHandle.requireStorageUuid()
|
||||
|
||||
init {
|
||||
refresh()
|
||||
observeSecrets()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
private fun observeSecrets() {
|
||||
viewModelScope.launch {
|
||||
val storage = findStorageUseCase.find(storageUuid)
|
||||
if (storage == null) {
|
||||
@@ -36,15 +36,19 @@ class TextSecretsViewModel @Inject constructor(
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
val items = manageTextSecretsUseCase.list(storage)
|
||||
updateState(
|
||||
combine(
|
||||
storage.isAvailable,
|
||||
manageTextSecretsUseCase.observe(storage),
|
||||
) { available, items ->
|
||||
state.value.copy(
|
||||
isLoading = false,
|
||||
isAvailable = storage.isAvailable.first(),
|
||||
isAvailable = available,
|
||||
items = items,
|
||||
errorMessage = null,
|
||||
),
|
||||
)
|
||||
)
|
||||
}.collect { ui ->
|
||||
updateState(ui)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,21 +3,27 @@ package com.github.nullptroma.wallenc.ui.screens.main.screens.storage.twofa
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.outlined.Lock
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
@@ -66,6 +72,7 @@ fun TwoFaTokensScreen(
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
if (uiState.isLoading) {
|
||||
CircularProgressIndicator()
|
||||
@@ -81,23 +88,62 @@ fun TwoFaTokensScreen(
|
||||
} else {
|
||||
LazyColumn(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
items(uiState.items) { item ->
|
||||
Row(
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
),
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(text = item.issuer)
|
||||
Text(text = item.account)
|
||||
Text(text = item.secret)
|
||||
}
|
||||
IconButton(onClick = { editingToken = item }, enabled = uiState.isAvailable) {
|
||||
Icon(Icons.Default.Edit, contentDescription = stringResource(R.string.edit))
|
||||
}
|
||||
IconButton(
|
||||
onClick = { viewModel.deleteToken(item.id) },
|
||||
enabled = uiState.isAvailable,
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(14.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Icon(Icons.Default.Delete, contentDescription = stringResource(R.string.remove))
|
||||
Row(
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Lock,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(22.dp)
|
||||
.padding(top = 2.dp),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Column {
|
||||
Text(
|
||||
text = item.issuer,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
Text(
|
||||
text = item.account,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(modifier = Modifier.size(4.dp))
|
||||
Text(
|
||||
text = maskedSecret(item.secret),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
Row {
|
||||
IconButton(
|
||||
onClick = { editingToken = item },
|
||||
enabled = uiState.isAvailable,
|
||||
) {
|
||||
Icon(Icons.Default.Edit, contentDescription = stringResource(R.string.edit))
|
||||
}
|
||||
IconButton(
|
||||
onClick = { viewModel.deleteToken(item.id) },
|
||||
enabled = uiState.isAvailable,
|
||||
) {
|
||||
Icon(Icons.Default.Delete, contentDescription = stringResource(R.string.remove))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,3 +248,8 @@ private fun TwoFaTokenEditDialog(
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun maskedSecret(secret: String): String {
|
||||
if (secret.isBlank()) return "—"
|
||||
return "••••••••••••"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.github.nullptroma.wallenc.ui.screens.main.screens.storage.requireStor
|
||||
import com.github.nullptroma.wallenc.usecases.FindStorageUseCase
|
||||
import com.github.nullptroma.wallenc.usecases.ManageTwoFaTokensUseCase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -22,10 +22,10 @@ class TwoFaTokensViewModel @Inject constructor(
|
||||
private val storageUuid = savedStateHandle.requireStorageUuid()
|
||||
|
||||
init {
|
||||
refresh()
|
||||
observeStorageTokens()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
private fun observeStorageTokens() {
|
||||
viewModelScope.launch {
|
||||
val storage = findStorageUseCase.find(storageUuid)
|
||||
if (storage == null) {
|
||||
@@ -37,15 +37,19 @@ class TwoFaTokensViewModel @Inject constructor(
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
val tokens = manageTwoFaTokensUseCase.list(storage)
|
||||
updateState(
|
||||
combine(
|
||||
storage.isAvailable,
|
||||
manageTwoFaTokensUseCase.observe(storage),
|
||||
) { available, items ->
|
||||
state.value.copy(
|
||||
isLoading = false,
|
||||
isAvailable = storage.isAvailable.first(),
|
||||
items = tokens,
|
||||
isAvailable = available,
|
||||
items = items,
|
||||
errorMessage = null,
|
||||
),
|
||||
)
|
||||
)
|
||||
}.collect { ui ->
|
||||
updateState(ui)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +82,6 @@ class TwoFaTokensViewModel @Inject constructor(
|
||||
),
|
||||
)
|
||||
}
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +89,6 @@ class TwoFaTokensViewModel @Inject constructor(
|
||||
viewModelScope.launch {
|
||||
val storage = findStorageUseCase.find(storageUuid) ?: return@launch
|
||||
manageTwoFaTokensUseCase.delete(storage, id)
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,8 +183,10 @@
|
||||
<string name="storage_home_status_not_encrypted">не зашифровано</string>
|
||||
<string name="storage_home_two_fa_title">2FA токены (%1$d)</string>
|
||||
<string name="storage_home_open_two_fa">Открыть 2FA</string>
|
||||
<string name="storage_home_two_fa_subtitle">Коды и секреты двухфакторной аутентификации</string>
|
||||
<string name="storage_home_text_secrets_title">Текстовые секреты (%1$d)</string>
|
||||
<string name="storage_home_open_text_secrets">Открыть текстовые секреты</string>
|
||||
<string name="storage_home_text_secrets_subtitle">Заметки, токены и произвольные пары ключ-значение</string>
|
||||
<string name="storage_home_future_sections">Скоро здесь появятся Files, Media и другие типы данных.</string>
|
||||
|
||||
<string name="two_fa_add_token">Добавить токен</string>
|
||||
|
||||
Reference in New Issue
Block a user