mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 10:20:25 +01:00
Add restore local backupv2 infra.
This commit is contained in:
@@ -365,8 +365,7 @@ object BackupRepository {
|
||||
private fun import(
|
||||
backupKey: BackupKey,
|
||||
frameReader: BackupImportReader,
|
||||
selfData: SelfData,
|
||||
importExtras: ((EventTimer) -> Unit)? = null
|
||||
selfData: SelfData
|
||||
): ImportResult {
|
||||
val eventTimer = EventTimer()
|
||||
|
||||
@@ -444,23 +443,27 @@ object BackupRepository {
|
||||
eventTimer.emit("chatItem")
|
||||
}
|
||||
|
||||
importExtras?.invoke(eventTimer)
|
||||
|
||||
importState.chatIdToLocalThreadId.values.forEach {
|
||||
SignalDatabase.threads.update(it, unarchive = false, allowDeletion = false)
|
||||
}
|
||||
}
|
||||
|
||||
SignalDatabase.groups.getGroups().use { groups ->
|
||||
while (groups.hasNext()) {
|
||||
val group = groups.next()
|
||||
if (group.id.isV2) {
|
||||
AppDependencies.jobManager.add(RequestGroupV2InfoJob(group.id as GroupId.V2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "import() ${eventTimer.stop().summary}")
|
||||
|
||||
val groupJobs = SignalDatabase.groups.getGroups().use { groups ->
|
||||
groups
|
||||
.asSequence()
|
||||
.mapNotNull { group ->
|
||||
if (group.id.isV2) {
|
||||
RequestGroupV2InfoJob(group.id as GroupId.V2)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
AppDependencies.jobManager.addAll(groupJobs)
|
||||
|
||||
return ImportResult.Success(backupTime = header.backupTimeMs)
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ class ArchiveFileSystem private constructor(private val context: Context, root:
|
||||
fun fromFile(context: Context, backupDirectory: File): ArchiveFileSystem {
|
||||
return ArchiveFileSystem(context, DocumentFile.fromFile(backupDirectory))
|
||||
}
|
||||
|
||||
fun openInputStream(context: Context, uri: Uri): InputStream? {
|
||||
return context.contentResolver.openInputStream(uri)
|
||||
}
|
||||
}
|
||||
|
||||
private val signalBackups: DocumentFile
|
||||
@@ -284,29 +288,22 @@ class FilesFileSystem(private val context: Context, private val root: DocumentFi
|
||||
* undefined and should be avoided.
|
||||
*/
|
||||
fun fileOutputStream(mediaName: MediaName): OutputStream? {
|
||||
val subFileDirectoryName = mediaName.name.substring(0..1)
|
||||
val subFileDirectory = subFolders[subFileDirectoryName]!!
|
||||
val subFileDirectory = subFileDirectoryFor(mediaName)
|
||||
val file = subFileDirectory.createFile("application/octet-stream", mediaName.name)
|
||||
return file?.outputStream(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a [file], open and return an [InputStream].
|
||||
*/
|
||||
fun fileInputStream(file: DocumentFileInfo): InputStream? {
|
||||
return file.documentFile.inputStream(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file for the given [mediaName] if it exists.
|
||||
*
|
||||
* @return true if deleted, false if not, null if not found
|
||||
*/
|
||||
fun delete(mediaName: MediaName): Boolean? {
|
||||
val subFileDirectoryName = mediaName.name.substring(0..1)
|
||||
val subFileDirectory = subFolders[subFileDirectoryName]!!
|
||||
return subFileDirectoryFor(mediaName).delete(context, mediaName.name)
|
||||
}
|
||||
|
||||
return subFileDirectory.delete(context, mediaName.name)
|
||||
private fun subFileDirectoryFor(mediaName: MediaName): DocumentFile {
|
||||
return subFolders[mediaName.name.substring(0..1)]!!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,14 @@ import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@@ -45,11 +46,13 @@ private const val NONE = -1
|
||||
@Composable
|
||||
fun BackupStatus(
|
||||
data: BackupStatusData,
|
||||
onActionClick: () -> Unit = {}
|
||||
onActionClick: () -> Unit = {},
|
||||
contentPadding: PaddingValues = PaddingValues(horizontal = 12.dp, vertical = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.border(1.dp, color = MaterialTheme.colorScheme.outline.copy(alpha = 0.38f), shape = RoundedCornerShape(12.dp))
|
||||
.fillMaxWidth()
|
||||
.padding(14.dp)
|
||||
@@ -71,7 +74,8 @@ fun BackupStatus(
|
||||
) {
|
||||
Text(
|
||||
text = data.title,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
if (data.progress >= 0f) {
|
||||
@@ -108,17 +112,19 @@ fun BackupStatus(
|
||||
@Composable
|
||||
fun BackupStatusPreview() {
|
||||
Previews.Preview {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Column {
|
||||
BackupStatus(
|
||||
data = BackupStatusData.CouldNotCompleteBackup
|
||||
)
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
BackupStatus(
|
||||
data = BackupStatusData.NotEnoughFreeSpace("12 GB")
|
||||
)
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
BackupStatus(
|
||||
data = BackupStatusData.RestoringMedia(50, 100)
|
||||
)
|
||||
@@ -201,7 +207,7 @@ sealed interface BackupStatusData {
|
||||
)
|
||||
|
||||
override val statusRes: Int = when (status) {
|
||||
Status.NONE -> R.string.default_error_msg
|
||||
Status.NONE -> NONE
|
||||
Status.LOW_BATTERY -> R.string.default_error_msg
|
||||
Status.WAITING_FOR_INTERNET -> R.string.default_error_msg
|
||||
Status.WAITING_FOR_WIFI -> R.string.default_error_msg
|
||||
|
||||
Reference in New Issue
Block a user