fix(sync): стабилизировал синхронизацию, Yandex I/O и вёрстку карточки storage

Добавил TRASH вместо DELETE для moveToTrash, компакцию журналов и отчёт об ошибках apply.
Исправил проброс ошибок upload Yandex при close, CAS lock и загрузку OAuth-токена.
Упростил совместимость sync-групп (только encInfo), поправил растягивание StorageTree при недоступных meta.
This commit is contained in:
2026-05-21 18:46:03 +03:00
parent ef40aa9e73
commit 51e6f40587
18 changed files with 268 additions and 89 deletions

View File

@@ -5,14 +5,12 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.LockOpen
@@ -90,17 +88,16 @@ fun StorageTree(
Column(modifier) {
Box(
modifier = Modifier
.height(IntrinsicSize.Min)
.fillMaxWidth()
.wrapContentHeight()
.zIndex(100f),
) {
val interactionSource = remember { MutableInteractionSource() }
Box(
modifier = Modifier
.clip(
CardDefaults.shape,
)
.padding(0.dp, 0.dp, 16.dp, 0.dp)
.fillMaxSize()
.matchParentSize()
.padding(end = 16.dp)
.clip(CardDefaults.shape)
.background(borderColor)
.clickable(
interactionSource = interactionSource,
@@ -112,8 +109,9 @@ fun StorageTree(
Card(
interactionSource = interactionSource,
modifier = Modifier
.padding(8.dp, 0.dp, 0.dp, 0.dp)
.fillMaxWidth(),
.padding(start = 8.dp)
.fillMaxWidth()
.wrapContentHeight(),
elevation = CardDefaults.cardElevation(
defaultElevation = 4.dp,
),
@@ -124,8 +122,16 @@ fun StorageTree(
}
},
) {
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
Column(modifier = Modifier.padding(8.dp)) {
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
) {
Column(
modifier = Modifier
.weight(1f)
.padding(8.dp),
) {
Text(metaInfo.name ?: stringResource(R.string.no_name))
Text(
text = stringResource(
@@ -170,7 +176,9 @@ fun StorageTree(
}
}
Column(
modifier = Modifier,
modifier = Modifier
.widthIn(min = 112.dp)
.padding(end = 4.dp),
horizontalAlignment = Alignment.End,
) {
var expanded by remember { mutableStateOf(false) }
@@ -368,7 +376,6 @@ fun StorageTree(
)
}
}
Spacer(modifier = Modifier.weight(1f))
if (isEncrypted) {
IconButton(
onClick = { showLockDialog = true },
@@ -382,18 +389,14 @@ fun StorageTree(
}
Text(
modifier = Modifier
.fillMaxWidth()
.padding(0.dp, 0.dp, 12.dp, 0.dp)
.align(Alignment.End),
.padding(top = 4.dp, end = 8.dp),
text = stringResource(getStatusTextRes(tree)),
textAlign = TextAlign.End,
fontSize = 11.sp,
)
Text(
modifier = Modifier
.fillMaxWidth()
.padding(0.dp, 0.dp, 12.dp, 8.dp)
.align(Alignment.End),
.padding(end = 8.dp, bottom = 8.dp),
text = cur.uuid.toString(),
textAlign = TextAlign.End,
fontSize = 8.sp,

View File

@@ -37,6 +37,8 @@ fun TaskProgressLabel.resolve(resolver: UiStringResolver): String = when (this)
resolver(R.string.sync_progress_group_entry, groupId, current, total)
is TaskProgressLabel.SyncGroupCompleted ->
resolver(R.string.sync_progress_group_completed, groupId)
is TaskProgressLabel.SyncGroupEntriesFailed ->
resolver.plurals(R.plurals.sync_progress_group_entries_failed, failedCount, groupId, failedCount)
is TaskProgressLabel.SyncGroupRenewingLocks ->
resolver(R.string.sync_progress_group_renewing_locks, groupId)
is TaskProgressLabel.SyncGroupLockRenewalFailed ->

View File

@@ -383,7 +383,6 @@ class StorageSyncViewModel @Inject constructor(
!isStorageCompatibleWithGroup(
storage = storage,
group = group,
resolveStorageKey = vaultsManager.unlockManager::getOpenedStorageKey,
)
}
StorageSyncGroupUi(

View File

@@ -12,4 +12,10 @@
<item quantity="many">Синхронизация: группа «%1$s» — обработка %2$d записей</item>
<item quantity="other">Синхронизация: группа «%1$s» — обработка %2$d записей</item>
</plurals>
<plurals name="sync_progress_group_entries_failed">
<item quantity="one">Синхронизация: группа «%1$s» — не применена %2$d запись</item>
<item quantity="few">Синхронизация: группа «%1$s» — не применены %2$d записи</item>
<item quantity="many">Синхронизация: группа «%1$s» — не применено %2$d записей</item>
<item quantity="other">Синхронизация: группа «%1$s» — не применено %2$d записей</item>
</plurals>
</resources>

View File

@@ -8,4 +8,8 @@
<item quantity="one">Storage sync: group "%1$s" processing %2$d entry</item>
<item quantity="other">Storage sync: group "%1$s" processing %2$d entries</item>
</plurals>
<plurals name="sync_progress_group_entries_failed">
<item quantity="one">Storage sync: group "%1$s" — %2$d entry failed</item>
<item quantity="other">Storage sync: group "%1$s" — %2$d entries failed</item>
</plurals>
</resources>