diff --git a/storage/lib/src/main/java/org/calyxos/backup/storage/api/CheckResult.kt b/storage/lib/src/main/java/org/calyxos/backup/storage/api/CheckResult.kt index 2867b434a..4dc13dc4c 100644 --- a/storage/lib/src/main/java/org/calyxos/backup/storage/api/CheckResult.kt +++ b/storage/lib/src/main/java/org/calyxos/backup/storage/api/CheckResult.kt @@ -28,11 +28,11 @@ public sealed class CheckResult { val goodSnapshots: List val badSnapshots: List + val badChunkIds: Set get() = missingChunkIds + malformedChunkIds init { val good = mutableListOf() val bad = mutableListOf() - val badChunkIds = missingChunkIds + malformedChunkIds snapshots.forEach { snapshot -> val chunkIds = (snapshot.mediaFilesList.flatMap { it.chunkIdsList } + snapshot.documentFilesList.flatMap { it.chunkIdsList }).toSet() diff --git a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/check/SnapshotFilesFragment.kt b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/check/SnapshotFilesFragment.kt index 69aaf8d19..98612a2c4 100644 --- a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/check/SnapshotFilesFragment.kt +++ b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/check/SnapshotFilesFragment.kt @@ -70,7 +70,8 @@ public class SnapshotFilesFragment : Fragment() { Toast.makeText(requireContext(), R.string.check_error_no_result, LENGTH_LONG).show() parentFragmentManager.popBackStack() } else { - fileSelectionManager.onSnapshotChosen(snapshot) + val badChunkIds = (checkResult as? CheckResult.Error)?.badChunkIds + fileSelectionManager.onSnapshotChosen(snapshot, badChunkIds) val textView: TextView = requireView().requireViewById(R.id.textView) textView.text = getString(R.string.check_files_text, snapshot.name) diff --git a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FileSelectionManager.kt b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FileSelectionManager.kt index b0f433c01..6318f3a6b 100644 --- a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FileSelectionManager.kt +++ b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FileSelectionManager.kt @@ -23,7 +23,7 @@ public class FileSelectionManager { public val files: StateFlow> = mFiles.asStateFlow() @UiThread - public fun onSnapshotChosen(snapshot: BackupSnapshot) { + public fun onSnapshotChosen(snapshot: BackupSnapshot, badChunkIds: Set? = null) { // clear previous state if existing clearState() // store snapshot for later @@ -31,10 +31,10 @@ public class FileSelectionManager { // cache files from snapshot within [RestorableFile] (for easier processing) snapshot.mediaFilesList.forEach { mediaFile -> - cacheFileItem(RestorableFile(mediaFile)) + cacheFileItem(RestorableFile(mediaFile), badChunkIds) } snapshot.documentFilesList.forEach { documentFile -> - cacheFileItem(RestorableFile(documentFile)) + cacheFileItem(RestorableFile(documentFile), badChunkIds) } // figure out indentation level and display names for folders val sortedFolders = allFiles.keys.sorted() @@ -55,6 +55,7 @@ public class FileSelectionManager { size = size, lastModified = if (lastModified == -1L) null else lastModified, selected = true, + hasIssue = fileItems.any { it.hasIssue }, partiallySelected = false, expanded = false, ) @@ -117,8 +118,15 @@ public class FileSelectionManager { return snapshotBuilder.build() } - private fun cacheFileItem(restorableFile: RestorableFile) { - val fileItem = FileItem(restorableFile, 0, true) + private fun cacheFileItem(restorableFile: RestorableFile, badChunkIds: Set?) { + val fileItem = FileItem( + file = restorableFile, + level = 0, + selected = true, + hasIssue = if (badChunkIds == null) false else { + restorableFile.chunkIds.intersect(badChunkIds).isNotEmpty() + }, + ) allFiles.getOrPut(restorableFile.dir) { mutableListOf() }.add(fileItem) diff --git a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesAdapter.kt b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesAdapter.kt index 04f28914c..fe2e7182d 100644 --- a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesAdapter.kt +++ b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesAdapter.kt @@ -63,7 +63,9 @@ internal class FilesAdapter( private val context = itemView.context private val expandView: ImageView = itemView.findViewById(R.id.expandView) + private val warningView: ImageView = itemView.findViewById(R.id.warningImageView) private val nameView: TextView = itemView.findViewById(R.id.nameView) + private val errorView: TextView = itemView.findViewById(R.id.errorView) private val infoView: TextView = itemView.findViewById(R.id.infoView) private val checkBox: CheckBox = itemView.findViewById(R.id.checkBox) @@ -89,7 +91,9 @@ internal class FilesAdapter( else checkBox.toggle() } itemView.updatePadding(left = indentPadding * item.level) + warningView.visibility = if (item.hasIssue) VISIBLE else GONE nameView.text = item.name + errorView.visibility = if (item.hasIssue && item is FileItem) VISIBLE else GONE val now = System.currentTimeMillis() var text = Formatter.formatShortFileSize(context, item.size) diff --git a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesItem.kt b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesItem.kt index b584c3810..64cfa6ae9 100644 --- a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesItem.kt +++ b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/restore/FilesItem.kt @@ -14,12 +14,14 @@ public sealed interface FilesItem { public val selected: Boolean public val size: Long public val lastModified: Long? + public val hasIssue: Boolean } public data class FileItem internal constructor( internal val file: RestorableFile, override val level: Int, override val selected: Boolean, + override val hasIssue: Boolean = false, ) : FilesItem { override val name: String get() = file.name override val dir: String get() = file.dir @@ -35,6 +37,7 @@ public data class FolderItem( override val size: Long, override val lastModified: Long?, override val selected: Boolean, + override val hasIssue: Boolean = false, val partiallySelected: Boolean, val expanded: Boolean, ) : FilesItem { diff --git a/storage/lib/src/main/res/drawable/ic_warning.xml b/storage/lib/src/main/res/drawable/ic_warning.xml new file mode 100644 index 000000000..a71c771ef --- /dev/null +++ b/storage/lib/src/main/res/drawable/ic_warning.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/storage/lib/src/main/res/layout/header_snapshot_files.xml b/storage/lib/src/main/res/layout/header_snapshot_files.xml index e92645ef1..376e8976a 100644 --- a/storage/lib/src/main/res/layout/header_snapshot_files.xml +++ b/storage/lib/src/main/res/layout/header_snapshot_files.xml @@ -7,6 +7,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@color/background" android:paddingBottom="16dp"> + + + + This backup has some errors. You may be able to restore it partly. Files in backup The \"%s\" includes the following files: + Backup data is corrupted. File won\'t fully restore.