v1.0.26: fix multi-selection reactivity, redesign icon, security review
Fix multi-selection: selectedKeys exposed as StateFlow, collected in FilesScreen so checkboxes and highlights update correctly on every tap. fileKey() made public so UI can check membership without ViewModel calls. Icon: white cloud body with two cyan/teal circular sync arcs (AutoSync style), deep blue-to-teal gradient background. Security review clean: no hardcoded credentials, cleartext blocked by network_security_config, allowBackup=false, path traversal guards in place on both server responses and local resolution. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,8 +39,9 @@ fun FilesScreen(
|
||||
val selectedPair by vm.selectedPair.collectAsState()
|
||||
val files by vm.files.collectAsState()
|
||||
val isDownloading by vm.isDownloading.collectAsState()
|
||||
val isSelectionMode by vm.isSelectionMode.collectAsState()
|
||||
val selectedCount by vm.selectedCount.collectAsState()
|
||||
val selectedKeys by vm.selectedKeys.collectAsState()
|
||||
val isSelectionMode = selectedKeys.isNotEmpty()
|
||||
val selectedCount = selectedKeys.size
|
||||
val context = LocalContext.current
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -252,12 +253,11 @@ fun FilesScreen(
|
||||
}
|
||||
}
|
||||
items(dirFiles, key = { "${it.syncPairId}_${it.relativePath}" }) { file ->
|
||||
val selected = vm.isSelected(file)
|
||||
FileRow(
|
||||
file = file,
|
||||
isInSubDir = dir.isNotEmpty() && !isSelectionMode,
|
||||
isSelectionMode = isSelectionMode,
|
||||
isSelected = selected,
|
||||
isSelected = vm.fileKey(file) in selectedKeys,
|
||||
vm = vm,
|
||||
)
|
||||
HorizontalDivider(
|
||||
|
||||
@@ -60,6 +60,7 @@ class FilesViewModel @Inject constructor(
|
||||
val isDownloading: StateFlow<Boolean> = _isDownloading
|
||||
|
||||
private val _selectedKeys = MutableStateFlow<Set<String>>(emptySet())
|
||||
val selectedKeys: StateFlow<Set<String>> = _selectedKeys
|
||||
val isSelectionMode: StateFlow<Boolean> = _selectedKeys.map { it.isNotEmpty() }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), false)
|
||||
val selectedCount: StateFlow<Int> = _selectedKeys.map { it.size }
|
||||
@@ -152,7 +153,7 @@ class FilesViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun fileKey(file: SyncFileStateEntity) = "${file.syncPairId}:${file.relativePath}"
|
||||
fun fileKey(file: SyncFileStateEntity) = "${file.syncPairId}:${file.relativePath}"
|
||||
|
||||
// ── Download-then-open/share ──────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user