mirror of https://github.com/tasks/tasks
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
7.3 KiB
Kotlin
192 lines
7.3 KiB
Kotlin
package org.tasks.backup
|
|
|
|
import android.app.Activity
|
|
import android.app.ProgressDialog
|
|
import android.app.backup.BackupManager
|
|
import android.content.Context
|
|
import android.net.Uri
|
|
import android.os.Handler
|
|
import com.google.common.io.Files
|
|
import com.google.gson.Gson
|
|
import com.google.gson.GsonBuilder
|
|
import com.todoroo.andlib.utility.DialogUtilities
|
|
import com.todoroo.astrid.data.Task
|
|
import org.tasks.BuildConfig
|
|
import org.tasks.R
|
|
import org.tasks.backup.BackupContainer.TaskBackup
|
|
import org.tasks.caldav.VtodoCache
|
|
import org.tasks.data.AlarmDao
|
|
import org.tasks.data.CaldavDao
|
|
import org.tasks.data.FilterDao
|
|
import org.tasks.data.GoogleTaskDao
|
|
import org.tasks.data.GoogleTaskListDao
|
|
import org.tasks.data.LocationDao
|
|
import org.tasks.data.TagDao
|
|
import org.tasks.data.TagDataDao
|
|
import org.tasks.data.TaskAttachmentDao
|
|
import org.tasks.data.TaskDao
|
|
import org.tasks.data.TaskListMetadataDao
|
|
import org.tasks.data.UserActivityDao
|
|
import org.tasks.date.DateTimeUtils.newDateTime
|
|
import org.tasks.extensions.Context.toast
|
|
import org.tasks.files.FileHelper
|
|
import org.tasks.jobs.WorkManager
|
|
import org.tasks.preferences.Preferences
|
|
import timber.log.Timber
|
|
import java.io.File
|
|
import java.io.IOException
|
|
import java.io.OutputStream
|
|
import java.io.OutputStreamWriter
|
|
import java.nio.charset.Charset
|
|
import javax.inject.Inject
|
|
|
|
class TasksJsonExporter @Inject constructor(
|
|
private val tagDataDao: TagDataDao,
|
|
private val taskDao: TaskDao,
|
|
private val userActivityDao: UserActivityDao,
|
|
private val preferences: Preferences,
|
|
private val alarmDao: AlarmDao,
|
|
private val locationDao: LocationDao,
|
|
private val tagDao: TagDao,
|
|
private val googleTaskDao: GoogleTaskDao,
|
|
private val filterDao: FilterDao,
|
|
private val googleTaskListDao: GoogleTaskListDao,
|
|
private val taskAttachmentDao: TaskAttachmentDao,
|
|
private val caldavDao: CaldavDao,
|
|
private val workManager: WorkManager,
|
|
private val taskListMetadataDao: TaskListMetadataDao,
|
|
private val vtodoCache: VtodoCache,
|
|
) {
|
|
|
|
private var context: Context? = null
|
|
private var exportCount = 0
|
|
private var progressDialog: ProgressDialog? = null
|
|
private var handler: Handler? = null
|
|
|
|
private fun post(runnable: () -> Unit) = handler?.post(runnable)
|
|
|
|
private fun setProgress(taskNumber: Int, total: Int) = post {
|
|
progressDialog?.max = total
|
|
progressDialog?.progress = taskNumber
|
|
}
|
|
|
|
suspend fun exportTasks(context: Context?, exportType: ExportType, progressDialog: ProgressDialog?) {
|
|
this.context = context
|
|
exportCount = 0
|
|
this.progressDialog = progressDialog
|
|
if (exportType == ExportType.EXPORT_TYPE_MANUAL) {
|
|
handler = Handler()
|
|
}
|
|
runBackup(exportType)
|
|
}
|
|
|
|
private suspend fun runBackup(exportType: ExportType) {
|
|
try {
|
|
val filename = getFileName(exportType)
|
|
val tasks = taskDao.getAll()
|
|
val file = File(String.format("%s/%s", context!!.filesDir, BackupConstants.INTERNAL_BACKUP))
|
|
file.delete()
|
|
file.createNewFile()
|
|
val internalStorageBackup = Uri.fromFile(file)
|
|
val os = context!!.contentResolver.openOutputStream(internalStorageBackup)
|
|
doTasksExport(os, tasks)
|
|
os!!.close()
|
|
val externalStorageBackup = FileHelper.newFile(
|
|
context!!,
|
|
preferences.backupDirectory!!,
|
|
MIME,
|
|
Files.getNameWithoutExtension(filename),
|
|
EXTENSION)
|
|
FileHelper.copyStream(context!!, internalStorageBackup, externalStorageBackup)
|
|
workManager.scheduleDriveUpload(externalStorageBackup, exportType == ExportType.EXPORT_TYPE_SERVICE)
|
|
BackupManager(context).dataChanged()
|
|
if (exportType == ExportType.EXPORT_TYPE_MANUAL) {
|
|
onFinishExport(filename)
|
|
}
|
|
} catch (e: IOException) {
|
|
Timber.e(e)
|
|
} finally {
|
|
post {
|
|
if (progressDialog != null && progressDialog!!.isShowing
|
|
&& context is Activity) {
|
|
DialogUtilities.dismissDialog(context as Activity?, progressDialog)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Throws(IOException::class)
|
|
private suspend fun doTasksExport(os: OutputStream?, tasks: List<Task>) {
|
|
val taskBackups: MutableList<TaskBackup> = ArrayList()
|
|
for (task in tasks) {
|
|
setProgress(taskBackups.size, tasks.size)
|
|
val taskId = task.id
|
|
val caldavTasks = caldavDao.getTasks(taskId)
|
|
taskBackups.add(
|
|
TaskBackup(
|
|
task,
|
|
alarmDao.getAlarms(taskId),
|
|
locationDao.getGeofencesForTask(taskId),
|
|
tagDao.getTagsForTask(taskId),
|
|
googleTaskDao.getAllByTaskId(taskId),
|
|
userActivityDao.getCommentsForTask(task.uuid),
|
|
taskAttachmentDao.getAttachments(task.uuid),
|
|
caldavTasks,
|
|
vtodoCache.getVtodo( caldavTasks.firstOrNull { !it.isDeleted() })
|
|
))
|
|
}
|
|
val data: MutableMap<String, Any> = HashMap()
|
|
data["version"] = BuildConfig.VERSION_CODE
|
|
data["timestamp"] = System.currentTimeMillis()
|
|
data["data"] = BackupContainer(
|
|
taskBackups,
|
|
locationDao.getPlaces(),
|
|
tagDataDao.getAll(),
|
|
filterDao.getFilters(),
|
|
googleTaskListDao.getAccounts(),
|
|
googleTaskListDao.getAllLists(),
|
|
caldavDao.getAccounts(),
|
|
caldavDao.getCalendars(),
|
|
taskListMetadataDao.getAll(),
|
|
preferences.getPrefs(Integer::class.java),
|
|
preferences.getPrefs(java.lang.Long::class.java),
|
|
preferences.getPrefs(String::class.java),
|
|
preferences.getPrefs(java.lang.Boolean::class.java),
|
|
preferences.getPrefs(java.util.Set::class.java),
|
|
)
|
|
val out = OutputStreamWriter(os, UTF_8)
|
|
val gson = if (BuildConfig.DEBUG) GsonBuilder().setPrettyPrinting().create() else Gson()
|
|
out.write(gson.toJson(data))
|
|
out.close()
|
|
exportCount = taskBackups.size
|
|
}
|
|
|
|
private fun onFinishExport(outputFile: String) = post {
|
|
context?.toast(
|
|
R.string.export_toast,
|
|
context!!
|
|
.resources
|
|
.getQuantityString(R.plurals.Ntasks, exportCount, exportCount),
|
|
outputFile
|
|
)
|
|
}
|
|
|
|
|
|
private fun getFileName(type: ExportType): String =
|
|
when (type) {
|
|
ExportType.EXPORT_TYPE_SERVICE -> String.format(BackupConstants.BACKUP_FILE_NAME, dateForExport)
|
|
ExportType.EXPORT_TYPE_MANUAL -> String.format(BackupConstants.EXPORT_FILE_NAME, dateForExport)
|
|
}
|
|
|
|
enum class ExportType {
|
|
EXPORT_TYPE_SERVICE, EXPORT_TYPE_MANUAL
|
|
}
|
|
|
|
companion object {
|
|
val UTF_8: Charset = Charset.forName("UTF-8")
|
|
private const val MIME = "application/json"
|
|
private const val EXTENSION = ".json"
|
|
private val dateForExport: String
|
|
get() = newDateTime().toString("yyMMdd-HHmm")
|
|
}
|
|
} |