diff --git a/app/build/generated/source/proto/debug/kotlin/com/stevesoltys/seedvault/proto/SnapshotKt.kt b/app/build/generated/source/proto/debug/kotlin/com/stevesoltys/seedvault/proto/SnapshotKt.kt
index f5141adc..1a4bc94c 100644
--- a/app/build/generated/source/proto/debug/kotlin/com/stevesoltys/seedvault/proto/SnapshotKt.kt
+++ b/app/build/generated/source/proto/debug/kotlin/com/stevesoltys/seedvault/proto/SnapshotKt.kt
@@ -537,6 +537,23 @@ public object SnapshotKt {
public fun hasApk(): kotlin.Boolean {
return _builder.hasApk()
}
+
+ /**
+ * uint64 size = 8;
+ */
+ public var size: kotlin.Long
+ @JvmName("getSize")
+ get() = _builder.getSize()
+ @JvmName("setSize")
+ set(value) {
+ _builder.setSize(value)
+ }
+ /**
+ * uint64 size = 8;
+ */
+ public fun clearSize() {
+ _builder.clearSize()
+ }
}
}
@kotlin.jvm.JvmName("-initializeapk")
diff --git a/app/src/main/java/com/stevesoltys/seedvault/repo/SnapshotCreator.kt b/app/src/main/java/com/stevesoltys/seedvault/repo/SnapshotCreator.kt
index eda04826..37d615a8 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/repo/SnapshotCreator.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/repo/SnapshotCreator.kt
@@ -97,6 +97,7 @@ internal class SnapshotCreator(
system = isSystemApp
launchableSystemApp = isSystemApp && launchableSystemApps.contains(packageName)
addAllChunkIds(chunkIds)
+ size = backupData.size
}
blobsMap.putAll(backupData.blobMap)
metadataManager.onPackageBackedUp(packageInfo, backupType, backupData.size)
diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreSetAdapter.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreSetAdapter.kt
index cdf15cc0..bf89c92e 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreSetAdapter.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreSetAdapter.kt
@@ -6,9 +6,9 @@
package com.stevesoltys.seedvault.restore
import android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE
-import android.text.format.DateUtils.HOUR_IN_MILLIS
+import android.text.format.DateUtils.MINUTE_IN_MILLIS
import android.text.format.DateUtils.getRelativeTimeSpanString
-import android.text.format.Formatter
+import android.text.format.Formatter.formatShortFileSize
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
@@ -41,32 +41,40 @@ internal class RestoreSetAdapter(
inner class RestoreSetViewHolder(private val v: View) : ViewHolder(v) {
private val titleView = v.requireViewById(R.id.titleView)
- private val subtitleView = v.requireViewById(R.id.subtitleView)
- private val sizeView = v.requireViewById(R.id.sizeView)
+ private val appView = v.requireViewById(R.id.appView)
+ private val apkView = v.requireViewById(R.id.apkView)
+ private val timeView = v.requireViewById(R.id.timeView)
internal fun bind(item: RestorableBackup) {
v.setOnClickListener { listener.onRestorableBackupClicked(item) }
titleView.text = item.name
- val lastBackup = getRelativeTime(item.time)
- val setup = getRelativeTime(item.token)
- subtitleView.text =
- v.context.getString(R.string.restore_restore_set_times, lastBackup, setup)
- val size = item.size
- if (size == null) {
- sizeView.visibility = GONE
- } else {
- sizeView.text = v.context.getString(
- R.string.restore_restore_set_size,
- Formatter.formatShortFileSize(v.context, size),
+ appView.text = if (item.sizeAppData > 0) {
+ v.context.getString(
+ R.string.restore_restore_set_apps,
+ item.numAppData,
+ formatShortFileSize(v.context, item.sizeAppData),
)
- sizeView.visibility = VISIBLE
+ } else {
+ v.context.getString(R.string.restore_restore_set_apps_no_size, item.numAppData)
}
+ appView.visibility = if (item.numAppData > 0) VISIBLE else GONE
+ apkView.text = if (item.sizeApks > 0) {
+ v.context.getString(
+ R.string.restore_restore_set_apks,
+ item.numApks,
+ formatShortFileSize(v.context, item.sizeApks),
+ )
+ } else {
+ v.context.getString(R.string.restore_restore_set_apks_no_size, item.numApks)
+ }
+ apkView.visibility = if (item.numApks > 0) VISIBLE else GONE
+ timeView.text = getRelativeTime(item.time)
}
private fun getRelativeTime(time: Long): CharSequence {
val now = System.currentTimeMillis()
- return getRelativeTimeSpanString(time, now, HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE)
+ return getRelativeTimeSpanString(time, now, MINUTE_IN_MILLIS, FORMAT_ABBREV_RELATIVE)
}
}
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestorableBackup.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestorableBackup.kt
index cbadca53..2dc7de45 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestorableBackup.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestorableBackup.kt
@@ -7,6 +7,7 @@ package com.stevesoltys.seedvault.transport.restore
import com.stevesoltys.seedvault.metadata.BackupMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
+import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA
import com.stevesoltys.seedvault.proto.Snapshot
sealed class RestorableBackupResult {
@@ -20,7 +21,6 @@ data class RestorableBackup(
val snapshot: Snapshot? = null,
) {
- // FIXME creating this mapping is expensive, a single call can take several seconds to complete
constructor(repoId: String, snapshot: Snapshot) : this(
backupMetadata = BackupMetadata.fromSnapshot(snapshot),
repoId = repoId,
@@ -40,18 +40,33 @@ data class RestorableBackup(
get() = backupMetadata.salt
val time: Long
- get() = backupMetadata.time
+ get() = snapshot?.token ?: backupMetadata.time
- val size: Long
- get() = snapshot?.blobsMap?.values?.sumOf { it.uncompressedLength.toLong() }
- ?: backupMetadata.size
+ val size: Long = snapshot?.blobsMap?.values?.sumOf { it.uncompressedLength.toLong() }
+ ?: backupMetadata.size
val deviceName: String
get() = backupMetadata.deviceName
+ val user: String?
+ get() = snapshot?.user?.takeIf { it.isNotBlank() }
+
val d2dBackup: Boolean
get() = backupMetadata.d2dBackup
+ val numAppData: Int = snapshot?.appsMap?.values?.count { it.chunkIdsCount > 0 }
+ ?: packageMetadataMap.values.count { packageMetadata ->
+ packageMetadata.backupType != null && packageMetadata.state == APK_AND_DATA
+ }
+
+ val sizeAppData: Long = snapshot?.appsMap?.values?.sumOf { it.size }
+ ?: packageMetadataMap.values.sumOf { it.size ?: 0L }
+
+ val numApks: Int = snapshot?.appsMap?.values?.count { it.apk.splitsCount > 0 }
+ ?: packageMetadataMap.values.count { it.hasApk() }
+
+ val sizeApks: Long = size - sizeAppData
+
val packageMetadataMap: PackageMetadataMap
get() = backupMetadata.packageMetadataMap
diff --git a/app/src/main/proto/snapshot.proto b/app/src/main/proto/snapshot.proto
index 142a3ea7..80ac4b4f 100644
--- a/app/src/main/proto/snapshot.proto
+++ b/app/src/main/proto/snapshot.proto
@@ -25,6 +25,7 @@ message Snapshot {
bool launchableSystemApp = 5;
repeated bytes chunkIds = 6;
Apk apk = 7;
+ uint64 size = 8;
}
enum BackupType {
diff --git a/app/src/main/res/layout/list_item_restore_set.xml b/app/src/main/res/layout/list_item_restore_set.xml
index df9c65c0..8ea4b827 100644
--- a/app/src/main/res/layout/list_item_restore_set.xml
+++ b/app/src/main/res/layout/list_item_restore_set.xml
@@ -1,5 +1,4 @@
-
-
@@ -25,37 +24,56 @@
+ tools:text="@string/restore_restore_set_apps" />
+ app:layout_constraintTop_toBottomOf="@+id/appView"
+ tools:text="@string/restore_restore_set_apks" />
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5bf7309e..610858d2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -205,8 +205,10 @@
Restore from backup
Choose a backup to restore
- Last backup %1$s ยท First %2$s.
- Size: %1$s
+ Has user data for %1$d apps (%2$s)
+ Has user data for %1$d apps
+ Contains %1$d apps (%2$s)
+ Contains %1$d apps
Don\'t restore
Skip restoring apps
No backups found
diff --git a/app/src/test/java/com/stevesoltys/seedvault/repo/SnapshotCreatorTest.kt b/app/src/test/java/com/stevesoltys/seedvault/repo/SnapshotCreatorTest.kt
index d4e4005a..52f1f876 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/repo/SnapshotCreatorTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/repo/SnapshotCreatorTest.kt
@@ -77,6 +77,7 @@ internal class SnapshotCreatorTest : TransportTest() {
assertEquals(name, s.appsMap[packageName]?.name)
assertEquals(token, s.appsMap[packageName]?.time)
assertEquals(Snapshot.BackupType.FULL, s.appsMap[packageName]?.type)
+ assertEquals(size, s.appsMap[packageName]?.size)
assertEquals(isSystem, s.appsMap[packageName]?.system)
assertEquals(isSystem, s.appsMap[packageName]?.launchableSystemApp)
assertEquals(apkBackupData.chunkIds.forProto(), s.appsMap[packageName]?.chunkIdsList)