forked from upstream-mirrors/quik
Implement logic to export messages to json
This commit is contained in:
@@ -21,36 +21,51 @@ package com.moez.QKSMS.repository
|
||||
import android.animation.ObjectAnimator
|
||||
import android.os.Environment
|
||||
import androidx.core.animation.addListener
|
||||
import com.moez.QKSMS.model.Backup
|
||||
import com.moez.QKSMS.model.BackupFile
|
||||
import com.moez.QKSMS.model.Message
|
||||
import com.moez.QKSMS.util.QkFileObserver
|
||||
import com.squareup.moshi.Moshi
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import io.reactivex.subjects.Subject
|
||||
import io.realm.Realm
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
||||
@Singleton
|
||||
class BackupRepositoryImpl @Inject constructor() : BackupRepository {
|
||||
class BackupRepositoryImpl @Inject constructor(
|
||||
private val moshi: Moshi
|
||||
) : BackupRepository {
|
||||
|
||||
companion object {
|
||||
private val BACKUP_DIRECTORY = Environment.getExternalStorageDirectory().toString() + "/QKSMS/Backups"
|
||||
}
|
||||
|
||||
data class Backup(
|
||||
val messages: List<BackupMessage>
|
||||
)
|
||||
|
||||
data class BackupMessage(
|
||||
val protocol: Int,
|
||||
val address: String,
|
||||
val date: Long,
|
||||
val type: Int,
|
||||
val type: String,
|
||||
val body: String,
|
||||
val service_center: String?,
|
||||
val serviceCenter: String?,
|
||||
val read: Boolean,
|
||||
val status: Int,
|
||||
val locked: Boolean,
|
||||
val date_sent: Long)
|
||||
val dateSent: Long)
|
||||
|
||||
// Subjects to emit our progress events to
|
||||
private val backupProgress: Subject<BackupRepository.Progress> = BehaviorSubject.createDefault(BackupRepository.Progress.Idle())
|
||||
private val restoreProgress: Subject<BackupRepository.Progress> = BehaviorSubject.createDefault(BackupRepository.Progress.Idle())
|
||||
|
||||
@@ -58,34 +73,75 @@ class BackupRepositoryImpl @Inject constructor() : BackupRepository {
|
||||
// If a backup or restore is already running, don't do anything
|
||||
if (isBackupOrRestoreRunning()) return
|
||||
|
||||
backupProgress.onNext(BackupRepository.Progress.Running(0))
|
||||
// Map all the messages into our object we'll use for the Json mapping
|
||||
val backupMessages = Realm.getDefaultInstance().use { realm ->
|
||||
// Get the messages from realm
|
||||
val messages = realm.where(Message::class.java).findAll().createSnapshot()
|
||||
val messageCount = messages.size
|
||||
|
||||
Thread.sleep(1000)
|
||||
// Map the messages to the new format
|
||||
val startTime = System.currentTimeMillis()
|
||||
messages.mapIndexed { index, message ->
|
||||
val progress = index.toDouble() / messageCount * 100
|
||||
val elapsed = System.currentTimeMillis() - startTime
|
||||
val remaining = when {
|
||||
index > 100 -> TimeUnit.MILLISECONDS.toSeconds((elapsed.toDouble() / index * (messageCount - index)).toLong())
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val animator = ObjectAnimator.ofInt(0, 100)
|
||||
animator.duration = 3000
|
||||
animator.addUpdateListener {
|
||||
val remaining = TimeUnit.MILLISECONDS.toSeconds(it.duration - it.currentPlayTime) + 1
|
||||
backupProgress.onNext(BackupRepository.Progress.Running(it.animatedValue as Int, "$remaining seconds remaining"))
|
||||
// Update the progress
|
||||
backupProgress.onNext(BackupRepository.Progress.Running(progress.toInt(), "$remaining seconds remaining"))
|
||||
messageToBackupMessage(message)
|
||||
}
|
||||
}
|
||||
animator.addListener(onEnd = {
|
||||
backupProgress.onNext(BackupRepository.Progress.Idle())
|
||||
})
|
||||
AndroidSchedulers.mainThread().scheduleDirect { animator.start() }
|
||||
|
||||
// Update the status, and set the progress to be indeterminate since we can no longer calculate progress
|
||||
backupProgress.onNext(BackupRepository.Progress.Running(0, "Saving..."))
|
||||
|
||||
// Convert the data to json
|
||||
val adapter = moshi.adapter(Backup::class.java).indent("\t")
|
||||
val json = adapter.toJson(Backup(backupMessages)).toByteArray()
|
||||
|
||||
try {
|
||||
// Create the directory and file
|
||||
val dir = File(BACKUP_DIRECTORY).apply { mkdirs() }
|
||||
val file = File(dir, "backup-${SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(System.currentTimeMillis())}.json")
|
||||
|
||||
// Write the log to the file
|
||||
FileOutputStream(file, true).use { fileOutputStream -> fileOutputStream.write(json) }
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
|
||||
backupProgress.onNext(BackupRepository.Progress.Idle())
|
||||
}
|
||||
|
||||
private fun messageToBackupMessage(message: Message): BackupMessage = BackupMessage(
|
||||
protocol = 0,
|
||||
address = message.address,
|
||||
date = message.date,
|
||||
type = message.type,
|
||||
body = message.body,
|
||||
serviceCenter = null,
|
||||
read = message.read,
|
||||
status = message.deliveryStatus,
|
||||
locked = message.locked,
|
||||
dateSent = message.dateSent)
|
||||
|
||||
override fun getBackupProgress(): Observable<BackupRepository.Progress> = backupProgress
|
||||
|
||||
override fun getBackups(): Observable<List<Backup>> = QkFileObserver(BACKUP_DIRECTORY)
|
||||
.observable
|
||||
.map { path -> File(path).listFiles() }
|
||||
override fun getBackups(): Observable<List<BackupFile>> = QkFileObserver(BACKUP_DIRECTORY).observable
|
||||
.map { File(BACKUP_DIRECTORY).listFiles() ?: arrayOf() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
.map { files ->
|
||||
files.map { file ->
|
||||
val date = file.lastModified()
|
||||
val messages = 0
|
||||
val size = file.length()
|
||||
Backup(date, listOf(), size)
|
||||
BackupFile(date, messages, size)
|
||||
}
|
||||
}
|
||||
.map { files -> files.sortedByDescending { file -> file.date } }
|
||||
|
||||
override fun performRestore() {
|
||||
// If a backup or restore is already running, don't do anything
|
||||
|
||||
@@ -22,7 +22,7 @@ import android.os.FileObserver
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
|
||||
class QkFileObserver(path: String) : FileObserver(path) {
|
||||
class QkFileObserver(private val path: String) : FileObserver(path) {
|
||||
|
||||
private val subject = BehaviorSubject.createDefault<String>(path).toSerialized()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user