Skip to content

Commit

Permalink
Improve RestoreSet display
Browse files Browse the repository at this point in the history
when user is asked to choose a backup to restore
  • Loading branch information
grote committed Sep 30, 2024
1 parent f9da316 commit 44d4e58
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,23 @@ public object SnapshotKt {
public fun hasApk(): kotlin.Boolean {
return _builder.hasApk()
}

/**
* <code>uint64 size = 8;</code>
*/
public var size: kotlin.Long
@JvmName("getSize")
get() = _builder.getSize()
@JvmName("setSize")
set(value) {
_builder.setSize(value)
}
/**
* <code>uint64 size = 8;</code>
*/
public fun clearSize() {
_builder.clearSize()
}
}
}
@kotlin.jvm.JvmName("-initializeapk")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -41,32 +41,40 @@ internal class RestoreSetAdapter(
inner class RestoreSetViewHolder(private val v: View) : ViewHolder(v) {

private val titleView = v.requireViewById<TextView>(R.id.titleView)
private val subtitleView = v.requireViewById<TextView>(R.id.subtitleView)
private val sizeView = v.requireViewById<TextView>(R.id.sizeView)
private val appView = v.requireViewById<TextView>(R.id.appView)
private val apkView = v.requireViewById<TextView>(R.id.apkView)
private val timeView = v.requireViewById<TextView>(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
appView.text = if (item.sizeAppData > 0) {
v.context.getString(
R.string.restore_restore_set_apps,
item.numAppData,
formatShortFileSize(v.context, item.sizeAppData),
)
} else {
sizeView.text = v.context.getString(
R.string.restore_restore_set_size,
Formatter.formatShortFileSize(v.context, size),
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),
)
sizeView.visibility = VISIBLE
} 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)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand All @@ -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

Expand Down
1 change: 1 addition & 0 deletions app/src/main/proto/snapshot.proto
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ message Snapshot {
bool launchableSystemApp = 5;
repeated bytes chunkIds = 6;
Apk apk = 7;
uint64 size = 8;
}

enum BackupType {
Expand Down
46 changes: 32 additions & 14 deletions app/src/main/res/layout/list_item_restore_set.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
SPDX-FileCopyrightText: 2020 The Calyx Institute
SPDX-License-Identifier: Apache-2.0
-->
Expand All @@ -25,37 +24,56 @@

<TextView
android:id="@+id/titleView"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:textColor="?android:attr/textColorSecondary"
android:textSize="18sp"
android:textColor="?android:textColorPrimary"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="@+id/appView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageView"
app:layout_constraintTop_toTopOf="parent"
tools:text="Pixel 2 XL backup" />

<TextView
android:id="@+id/subtitleView"
android:id="@+id/appView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="?android:attr/textColorTertiary"
android:layout_marginTop="4dp"
android:textColor="?android:textColorSecondary"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/titleView"
app:layout_constraintTop_toBottomOf="@+id/titleView"
tools:text="@string/restore_restore_set_times" />
tools:text="@string/restore_restore_set_apps" />

<TextView
android:id="@+id/sizeView"
android:id="@+id/apkView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="4dp"
android:textColor="?android:textColorTertiary"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/timeView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/titleView"
app:layout_constraintTop_toBottomOf="@+id/appView"
tools:text="@string/restore_restore_set_apks" />

<TextView
android:id="@+id/timeView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
android:gravity="end"
android:textColor="?android:textColorSecondary"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/titleView"
app:layout_constraintTop_toBottomOf="@+id/subtitleView"
tools:text="Size: 5 GB" />
app:layout_constraintTop_toBottomOf="@+id/apkView"
tools:text="5 days ago" />

</androidx.constraintlayout.widget.ConstraintLayout>
6 changes: 4 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,10 @@
<!-- Restore -->
<string name="restore_title">Restore from backup</string>
<string name="restore_choose_restore_set">Choose a backup to restore</string>
<string name="restore_restore_set_times">Last backup %1$s · First %2$s.</string>
<string name="restore_restore_set_size">Size: <xliff:g example="1 GB" id="size">%1$s</xliff:g></string>
<string name="restore_restore_set_apps">Has user data for <xliff:g example="42" id="apps">%1$d</xliff:g> apps (<xliff:g example="1 GB" id="size">%2$s</xliff:g>)</string>
<string name="restore_restore_set_apps_no_size">Has user data for <xliff:g example="42" id="apps">%1$d</xliff:g> apps</string>
<string name="restore_restore_set_apks">Contains <xliff:g example="42" id="apps">%1$d</xliff:g> apps (<xliff:g example="1 GB" id="size">%2$s</xliff:g>)</string>
<string name="restore_restore_set_apks_no_size">Contains <xliff:g example="42" id="apps">%1$d</xliff:g> apps</string>
<string name="restore_skip">Don\'t restore</string>
<string name="restore_skip_apps">Skip restoring apps</string>
<string name="restore_invalid_location_title">No backups found</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 44d4e58

Please sign in to comment.