Convert json import/export to Kotlin

pull/1032/head
Alex Baker 6 years ago
parent 6d023fd700
commit 9d7df21deb

@ -1,159 +0,0 @@
package org.tasks.backup;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import com.todoroo.astrid.data.Task;
import java.util.List;
import java.util.Map;
import org.tasks.backup.TasksJsonImporter.LegacyLocation;
import org.tasks.data.Alarm;
import org.tasks.data.CaldavAccount;
import org.tasks.data.CaldavCalendar;
import org.tasks.data.CaldavTask;
import org.tasks.data.Filter;
import org.tasks.data.Geofence;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskAccount;
import org.tasks.data.GoogleTaskList;
import org.tasks.data.Place;
import org.tasks.data.Tag;
import org.tasks.data.TagData;
import org.tasks.data.TaskAttachment;
import org.tasks.data.UserActivity;
class BackupContainer {
private final List<TaskBackup> tasks;
private final List<Place> places;
private final List<TagData> tags;
private final List<Filter> filters;
private final List<GoogleTaskList> googleTaskLists;
private final List<GoogleTaskAccount> googleTaskAccounts;
private final List<CaldavAccount> caldavAccounts;
private final List<CaldavCalendar> caldavCalendars;
private final Map<String, Integer> intPrefs;
private final Map<String, Long> longPrefs;
private final Map<String, String> stringPrefs;
private final Map<String, Boolean> boolPrefs;
BackupContainer(
List<TaskBackup> tasks,
List<Place> places,
List<TagData> tags,
List<Filter> filters,
List<GoogleTaskAccount> googleTaskAccounts,
List<GoogleTaskList> googleTaskLists,
List<CaldavAccount> caldavAccounts,
List<CaldavCalendar> caldavCalendars,
Map<String, Integer> intPrefs,
Map<String, Long> longPrefs,
Map<String, String> stringPrefs,
Map<String, Boolean> boolPrefs) {
this.tasks = tasks;
this.places = places;
this.tags = tags;
this.filters = filters;
this.googleTaskAccounts = googleTaskAccounts;
this.googleTaskLists = googleTaskLists;
this.caldavAccounts = caldavAccounts;
this.caldavCalendars = caldavCalendars;
this.intPrefs = intPrefs;
this.longPrefs = longPrefs;
this.stringPrefs = stringPrefs;
this.boolPrefs = boolPrefs;
}
public List<TaskBackup> getTasks() {
return tasks == null ? emptyList() : tasks;
}
public List<TagData> getTags() {
return tags == null ? emptyList() : tags;
}
public List<Filter> getFilters() {
return filters == null ? emptyList() : filters;
}
List<GoogleTaskList> getGoogleTaskLists() {
return googleTaskLists == null ? emptyList() : googleTaskLists;
}
List<CaldavAccount> getCaldavAccounts() {
return caldavAccounts == null ? emptyList() : caldavAccounts;
}
List<CaldavCalendar> getCaldavCalendars() {
return caldavCalendars == null ? emptyList() : caldavCalendars;
}
List<GoogleTaskAccount> getGoogleTaskAccounts() {
return googleTaskAccounts == null ? emptyList() : googleTaskAccounts;
}
public List<Place> getPlaces() {
return places == null ? emptyList() : places;
}
Map<String, Integer> getIntPrefs() {
return intPrefs == null ? emptyMap() : intPrefs;
}
Map<String, Long> getLongPrefs() {
return longPrefs == null ? emptyMap() : longPrefs;
}
Map<String, String> getStringPrefs() {
return stringPrefs == null ? emptyMap() : stringPrefs;
}
Map<String, Boolean> getBoolPrefs() {
return boolPrefs == null ? emptyMap() : boolPrefs;
}
static class TaskBackup {
final Task task;
final List<Alarm> alarms;
final List<LegacyLocation> locations;
final List<Tag> tags;
final List<GoogleTask> google;
final List<UserActivity> comments;
private final List<Geofence> geofences;
private final List<TaskAttachment> attachments;
private final List<CaldavTask> caldavTasks;
TaskBackup(
Task task,
List<Alarm> alarms,
List<Geofence> geofences,
List<Tag> tags,
List<GoogleTask> google,
List<UserActivity> comments,
List<TaskAttachment> attachments,
List<CaldavTask> caldavTasks) {
this.task = task;
this.alarms = alarms;
this.geofences = geofences;
this.tags = tags;
this.google = google;
this.comments = comments;
this.attachments = attachments;
this.caldavTasks = caldavTasks;
locations = emptyList();
}
List<TaskAttachment> getAttachments() {
return attachments == null ? emptyList() : attachments;
}
List<CaldavTask> getCaldavTasks() {
return caldavTasks == null ? emptyList() : caldavTasks;
}
List<Geofence> getGeofences() {
return geofences == null ? emptyList() : geofences;
}
}
}

@ -0,0 +1,33 @@
package org.tasks.backup
import com.todoroo.astrid.data.Task
import org.tasks.backup.TasksJsonImporter.LegacyLocation
import org.tasks.data.*
class BackupContainer(
val tasks: List<TaskBackup>?,
val places: List<Place>?,
val tags: List<TagData>?,
val filters: List<Filter>?,
val googleTaskAccounts: List<GoogleTaskAccount>?,
val googleTaskLists: List<GoogleTaskList>?,
val caldavAccounts: List<CaldavAccount>?,
val caldavCalendars: List<CaldavCalendar>?,
val intPrefs: Map<String, Int>?,
val longPrefs: Map<String, Long>?,
val stringPrefs: Map<String, String>?,
val boolPrefs: Map<String, Boolean>?) {
class TaskBackup(
val task: Task,
val alarms: List<Alarm>,
val geofences: List<Geofence>?,
val tags: List<Tag>,
val google: List<GoogleTask>,
val comments: List<UserActivity>,
val attachments: List<TaskAttachment>?,
val caldavTasks: List<CaldavTask>?) {
val locations: List<LegacyLocation> = emptyList()
}
}

@ -1,266 +0,0 @@
package org.tasks.backup;
import static org.tasks.date.DateTimeUtils.newDateTime;
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 android.widget.Toast;
import androidx.annotation.Nullable;
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.backup.BackupConstants;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.tasks.BuildConfig;
import org.tasks.R;
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.UserActivityDao;
import org.tasks.files.FileHelper;
import org.tasks.jobs.WorkManager;
import org.tasks.preferences.Preferences;
import timber.log.Timber;
public class TasksJsonExporter {
@SuppressWarnings("CharsetObjectCanBeUsed")
static final Charset UTF_8 = Charset.forName("UTF-8");
private static final String MIME = "application/json";
private static final String EXTENSION = ".json";
// --- public interface
private final TagDataDao tagDataDao;
// --- implementation
private final AlarmDao alarmDao;
private final LocationDao locationDao;
private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final FilterDao filterDao;
private final GoogleTaskListDao googleTaskListDao;
private final TaskAttachmentDao taskAttachmentDao;
private final CaldavDao caldavDao;
private final WorkManager workManager;
private final TaskDao taskDao;
private final UserActivityDao userActivityDao;
private final Preferences preferences;
private Context context;
private int exportCount = 0;
private ProgressDialog progressDialog;
private Handler handler;
@Inject
public TasksJsonExporter(
TagDataDao tagDataDao,
TaskDao taskDao,
UserActivityDao userActivityDao,
Preferences preferences,
AlarmDao alarmDao,
LocationDao locationDao,
TagDao tagDao,
GoogleTaskDao googleTaskDao,
FilterDao filterDao,
GoogleTaskListDao googleTaskListDao,
TaskAttachmentDao taskAttachmentDao,
CaldavDao caldavDao,
WorkManager workManager) {
this.tagDataDao = tagDataDao;
this.taskDao = taskDao;
this.userActivityDao = userActivityDao;
this.preferences = preferences;
this.alarmDao = alarmDao;
this.locationDao = locationDao;
this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
this.filterDao = filterDao;
this.googleTaskListDao = googleTaskListDao;
this.taskAttachmentDao = taskAttachmentDao;
this.caldavDao = caldavDao;
this.workManager = workManager;
}
private static String getDateForExport() {
return newDateTime().toString("yyMMdd-HHmm");
}
private void post(Runnable runnable) {
if (handler != null) {
handler.post(runnable);
}
}
private void setProgress(final int taskNumber, final int total) {
post(
() -> {
progressDialog.setMax(total);
progressDialog.setProgress(taskNumber);
});
}
public void exportTasks(
final Context context,
final ExportType exportType,
@Nullable final ProgressDialog progressDialog) {
this.context = context;
this.exportCount = 0;
this.progressDialog = progressDialog;
if (exportType == ExportType.EXPORT_TYPE_MANUAL) {
handler = new Handler();
new Thread(() -> runBackup(exportType)).start();
} else {
runBackup(exportType);
}
}
private void runBackup(ExportType exportType) {
try {
String filename = getFileName(exportType);
List<Task> tasks = taskDao.getAll();
if (tasks.size() > 0) {
File file =
new File(
String.format("%s/%s", context.getFilesDir(), BackupConstants.INTERNAL_BACKUP));
file.delete();
file.createNewFile();
Uri internalStorageBackup = Uri.fromFile(file);
OutputStream os = context.getContentResolver().openOutputStream(internalStorageBackup);
doTasksExport(os, tasks);
os.close();
Uri externalStorageBackup =
FileHelper.newFile(
context,
preferences.getBackupDirectory(),
MIME,
Files.getNameWithoutExtension(filename),
EXTENSION);
FileHelper.copyStream(context, internalStorageBackup, externalStorageBackup);
workManager.scheduleDriveUpload(externalStorageBackup, exportType == ExportType.EXPORT_TYPE_SERVICE);
new BackupManager(context).dataChanged();
}
if (exportType == ExportType.EXPORT_TYPE_MANUAL) {
onFinishExport(filename);
}
} catch (IOException e) {
Timber.e(e);
} finally {
post(
() -> {
if (progressDialog != null
&& progressDialog.isShowing()
&& context instanceof Activity) {
DialogUtilities.dismissDialog((Activity) context, progressDialog);
}
});
}
}
private void doTasksExport(OutputStream os, List<Task> tasks) throws IOException {
List<BackupContainer.TaskBackup> taskBackups = new ArrayList<>();
for (Task task : tasks) {
setProgress(taskBackups.size(), tasks.size());
long taskId = task.getId();
taskBackups.add(
new BackupContainer.TaskBackup(
task,
alarmDao.getAlarms(taskId),
locationDao.getGeofencesForTask(taskId),
tagDao.getTagsForTask(taskId),
googleTaskDao.getAllByTaskId(taskId),
userActivityDao.getCommentsForTask(task.getUuid()),
taskAttachmentDao.getAttachments(task.getUuid()),
caldavDao.getTasks(taskId)));
}
Map<String, Object> data = new HashMap<>();
data.put("version", BuildConfig.VERSION_CODE);
data.put("timestamp", System.currentTimeMillis());
data.put(
"data",
new BackupContainer(
taskBackups,
locationDao.getPlaces(),
tagDataDao.getAll(),
filterDao.getAll(),
googleTaskListDao.getAccounts(),
googleTaskListDao.getAllLists(),
caldavDao.getAccounts(),
caldavDao.getCalendars(),
preferences.getPrefs(Integer.class),
preferences.getPrefs(Long.class),
preferences.getPrefs(String.class),
preferences.getPrefs(Boolean.class)));
OutputStreamWriter out = new OutputStreamWriter(os, UTF_8);
Gson gson = BuildConfig.DEBUG ? new GsonBuilder().setPrettyPrinting().create() : new Gson();
out.write(gson.toJson(data));
out.close();
exportCount = taskBackups.size();
}
private void onFinishExport(final String outputFile) {
post(
() -> {
if (exportCount == 0) {
Toast.makeText(
context, context.getString(R.string.export_toast_no_tasks), Toast.LENGTH_LONG)
.show();
} else {
CharSequence text =
String.format(
context.getString(R.string.export_toast),
context
.getResources()
.getQuantityString(R.plurals.Ntasks, exportCount, exportCount),
outputFile);
Toast.makeText(context, text, Toast.LENGTH_LONG).show();
}
});
}
private String getFileName(ExportType type) {
switch (type) {
case EXPORT_TYPE_SERVICE:
return String.format(BackupConstants.BACKUP_FILE_NAME, getDateForExport());
case EXPORT_TYPE_MANUAL:
return String.format(BackupConstants.EXPORT_FILE_NAME, getDateForExport());
default:
throw new UnsupportedOperationException("Unhandled export type");
}
}
public enum ExportType {
EXPORT_TYPE_SERVICE,
EXPORT_TYPE_MANUAL
}
}

@ -0,0 +1,185 @@
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 android.widget.Toast
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.backup.BackupConstants
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task
import org.tasks.BuildConfig
import org.tasks.R
import org.tasks.backup.BackupContainer.TaskBackup
import org.tasks.data.*
import org.tasks.date.DateTimeUtils.newDateTime
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 java.util.*
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 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
}
fun exportTasks(context: Context?, exportType: ExportType, progressDialog: ProgressDialog?) {
this.context = context
exportCount = 0
this.progressDialog = progressDialog
if (exportType == ExportType.EXPORT_TYPE_MANUAL) {
handler = Handler()
Thread(Runnable { runBackup(exportType) }).start()
} else {
runBackup(exportType)
}
}
private fun runBackup(exportType: ExportType) {
try {
val filename = getFileName(exportType)
val tasks = taskDao.getAll()
if (tasks.isNotEmpty()) {
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 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
taskBackups.add(
TaskBackup(
task,
alarmDao.getAlarms(taskId),
locationDao.getGeofencesForTask(taskId),
tagDao.getTagsForTask(taskId),
googleTaskDao.getAllByTaskId(taskId),
userActivityDao.getCommentsForTask(task.uuid),
taskAttachmentDao.getAttachments(task.uuid),
caldavDao.getTasks(taskId)))
}
val data: MutableMap<String, Any> = HashMap()
data["version"] = BuildConfig.VERSION_CODE
data["timestamp"] = System.currentTimeMillis()
data["data"] = BackupContainer(
taskBackups,
locationDao.getPlaces(),
tagDataDao.getAll(),
filterDao.getAll(),
googleTaskListDao.getAccounts(),
googleTaskListDao.getAllLists(),
caldavDao.getAccounts(),
caldavDao.getCalendars(),
preferences.getPrefs(Int::class.java),
preferences.getPrefs(Long::class.java),
preferences.getPrefs(String::class.java),
preferences.getPrefs(Boolean::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 {
if (exportCount == 0) {
Toast.makeText(
context, context!!.getString(R.string.export_toast_no_tasks), Toast.LENGTH_LONG)
.show()
} else {
val text: CharSequence = String.format(
context!!.getString(R.string.export_toast),
context!!
.resources
.getQuantityString(R.plurals.Ntasks, exportCount, exportCount),
outputFile)
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
}
}
private fun getFileName(type: ExportType): String {
return 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")
}
}

@ -1,300 +0,0 @@
package org.tasks.backup;
import static org.tasks.backup.TasksJsonExporter.UTF_8;
import static org.tasks.data.Place.newPlace;
import static org.tasks.preferences.Preferences.P_CURRENT_VERSION;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import androidx.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskMover;
import com.todoroo.astrid.service.Upgrader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map.Entry;
import javax.inject.Inject;
import org.tasks.LocalBroadcastManager;
import org.tasks.R;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.data.CaldavAccount;
import org.tasks.data.CaldavCalendar;
import org.tasks.data.CaldavDao;
import org.tasks.data.CaldavTask;
import org.tasks.data.Filter;
import org.tasks.data.FilterDao;
import org.tasks.data.Geofence;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskAccount;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.GoogleTaskList;
import org.tasks.data.GoogleTaskListDao;
import org.tasks.data.LocationDao;
import org.tasks.data.Place;
import org.tasks.data.Tag;
import org.tasks.data.TagDao;
import org.tasks.data.TagData;
import org.tasks.data.TagDataDao;
import org.tasks.data.TaskAttachment;
import org.tasks.data.TaskAttachmentDao;
import org.tasks.data.UserActivity;
import org.tasks.data.UserActivityDao;
import org.tasks.preferences.Preferences;
import timber.log.Timber;
public class TasksJsonImporter {
private final TagDataDao tagDataDao;
private final UserActivityDao userActivityDao;
private final TaskDao taskDao;
private final LocalBroadcastManager localBroadcastManager;
private final AlarmDao alarmDao;
private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final GoogleTaskListDao googleTaskListDao;
private final FilterDao filterDao;
private final TaskAttachmentDao taskAttachmentDao;
private final CaldavDao caldavDao;
private final Preferences preferences;
private final TaskMover taskMover;
private final LocationDao locationDao;
private final ImportResult result = new ImportResult();
@Inject
public TasksJsonImporter(
TagDataDao tagDataDao,
UserActivityDao userActivityDao,
TaskDao taskDao,
LocationDao locationDao,
LocalBroadcastManager localBroadcastManager,
AlarmDao alarmDao,
TagDao tagDao,
GoogleTaskDao googleTaskDao,
GoogleTaskListDao googleTaskListDao,
FilterDao filterDao,
TaskAttachmentDao taskAttachmentDao,
CaldavDao caldavDao,
Preferences preferences,
TaskMover taskMover) {
this.tagDataDao = tagDataDao;
this.userActivityDao = userActivityDao;
this.taskDao = taskDao;
this.locationDao = locationDao;
this.localBroadcastManager = localBroadcastManager;
this.alarmDao = alarmDao;
this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
this.googleTaskListDao = googleTaskListDao;
this.filterDao = filterDao;
this.taskAttachmentDao = taskAttachmentDao;
this.caldavDao = caldavDao;
this.preferences = preferences;
this.taskMover = taskMover;
}
private void setProgressMessage(
Handler handler, ProgressDialog progressDialog, final String message) {
if (progressDialog == null) {
return;
}
handler.post(() -> progressDialog.setMessage(message));
}
public ImportResult importTasks(Context context, Uri backupFile, @Nullable ProgressDialog progressDialog) {
Handler handler = new Handler(context.getMainLooper());
Gson gson = new Gson();
InputStream is;
try {
is = context.getContentResolver().openInputStream(backupFile);
} catch (FileNotFoundException e) {
throw new IllegalStateException(e);
}
InputStreamReader reader = new InputStreamReader(is, UTF_8);
JsonObject input = gson.fromJson(reader, JsonObject.class);
try {
JsonElement data = input.get("data");
int version = input.get("version").getAsInt();
BackupContainer backupContainer = gson.fromJson(data, BackupContainer.class);
for (TagData tagData : backupContainer.getTags()) {
tagData.setColor(themeToColor(context, version, tagData.getColor()));
if (tagDataDao.getByUuid(tagData.getRemoteId()) == null) {
tagDataDao.createNew(tagData);
}
}
for (GoogleTaskAccount googleTaskAccount : backupContainer.getGoogleTaskAccounts()) {
if (googleTaskListDao.getAccount(googleTaskAccount.getAccount()) == null) {
googleTaskListDao.insert(googleTaskAccount);
}
}
for (Place place : backupContainer.getPlaces()) {
if (locationDao.getByUid(place.getUid()) == null) {
locationDao.insert(place);
}
}
for (GoogleTaskList googleTaskList : backupContainer.getGoogleTaskLists()) {
googleTaskList.setColor(themeToColor(context, version, googleTaskList.getColor()));
if (googleTaskListDao.getByRemoteId(googleTaskList.getRemoteId()) == null) {
googleTaskListDao.insert(googleTaskList);
}
}
for (Filter filter : backupContainer.getFilters()) {
filter.setColor(themeToColor(context, version, filter.getColor()));
if (filterDao.getByName(filter.getTitle()) == null) {
filterDao.insert(filter);
}
}
for (CaldavAccount account : backupContainer.getCaldavAccounts()) {
if (caldavDao.getAccountByUuid(account.getUuid()) == null) {
caldavDao.insert(account);
}
}
for (CaldavCalendar calendar : backupContainer.getCaldavCalendars()) {
calendar.setColor(themeToColor(context, version, calendar.getColor()));
if (caldavDao.getCalendarByUuid(calendar.getUuid()) == null) {
caldavDao.insert(calendar);
}
}
for (BackupContainer.TaskBackup backup : backupContainer.getTasks()) {
result.taskCount++;
setProgressMessage(
handler,
progressDialog,
context.getString(R.string.import_progress_read, result.taskCount));
Task task = backup.task;
if (taskDao.fetch(task.getUuid()) != null) {
result.skipCount++;
continue;
}
task.suppressRefresh();
task.suppressSync();
taskDao.createNew(task);
long taskId = task.getId();
String taskUuid = task.getUuid();
for (Alarm alarm : backup.alarms) {
alarm.setTask(taskId);
alarmDao.insert(alarm);
}
for (UserActivity comment : backup.comments) {
comment.setTargetId(taskUuid);
if (version < 546) {
comment.convertPictureUri();
}
userActivityDao.createNew(comment);
}
for (GoogleTask googleTask : backup.google) {
googleTask.setTask(taskId);
googleTaskDao.insert(googleTask);
}
for (LegacyLocation location : backup.locations) {
Place place = newPlace();
place.setLongitude(location.longitude);
place.setLatitude(location.latitude);
place.setName(location.name);
place.setAddress(location.address);
place.setUrl(location.url);
place.setPhone(location.phone);
locationDao.insert(place);
Geofence geofence = new Geofence();
geofence.setTask(taskId);
geofence.setPlace(place.getUid());
geofence.setRadius(location.radius);
geofence.setArrival(location.arrival);
geofence.setDeparture(location.departure);
locationDao.insert(geofence);
}
for (Tag tag : backup.tags) {
tag.setTask(taskId);
tag.setTaskUid(taskUuid);
tagDao.insert(tag);
}
for (Geofence geofence : backup.getGeofences()) {
geofence.setTask(taskId);
locationDao.insert(geofence);
}
for (TaskAttachment attachment : backup.getAttachments()) {
attachment.setTaskId(taskUuid);
if (version < 546) {
attachment.convertPathUri();
}
taskAttachmentDao.insert(attachment);
}
for (CaldavTask caldavTask : backup.getCaldavTasks()) {
caldavTask.setTask(taskId);
caldavDao.insert(caldavTask);
}
result.importCount++;
}
googleTaskDao.updateParents();
caldavDao.updateParents();
for (Entry<String, Integer> entry : backupContainer.getIntPrefs().entrySet()) {
if (P_CURRENT_VERSION.equals(entry.getKey())) {
continue;
}
preferences.setInt(entry.getKey(), entry.getValue());
}
for (Entry<String, Long> entry : backupContainer.getLongPrefs().entrySet()) {
preferences.setLong(entry.getKey(), entry.getValue());
}
for (Entry<String, String> entry : backupContainer.getStringPrefs().entrySet()) {
preferences.setString(entry.getKey(), entry.getValue());
}
for (Entry<String, Boolean> entry : backupContainer.getBoolPrefs().entrySet()) {
preferences.setBoolean(entry.getKey(), entry.getValue());
}
if (version < Upgrader.V8_2) {
int themeIndex = preferences.getInt(R.string.p_theme_color, 7);
preferences.setInt(
R.string.p_theme_color,
Upgrader.getAndroidColor(context, themeIndex));
}
if (version < Upgrader.V9_6) {
taskMover.migrateLocalTasks();
}
reader.close();
is.close();
} catch (IOException e) {
Timber.e(e);
}
localBroadcastManager.broadcastRefresh();
return result;
}
private int themeToColor(Context context, int version, int color) {
return version < Upgrader.V8_2 ? Upgrader.getAndroidColor(context, color) : color;
}
public static class ImportResult {
public int taskCount;
public int importCount;
public int skipCount;
}
static class LegacyLocation {
String name;
String address;
String phone;
String url;
double latitude;
double longitude;
int radius;
boolean arrival;
boolean departure;
}
}

@ -0,0 +1,230 @@
package org.tasks.backup
import android.app.ProgressDialog
import android.content.Context
import android.net.Uri
import android.os.Handler
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.service.TaskMover
import com.todoroo.astrid.service.Upgrader
import com.todoroo.astrid.service.Upgrader.Companion.getAndroidColor
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.data.*
import org.tasks.data.Place.Companion.newPlace
import org.tasks.preferences.Preferences
import timber.log.Timber
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import javax.inject.Inject
class TasksJsonImporter @Inject constructor(
private val tagDataDao: TagDataDao,
private val userActivityDao: UserActivityDao,
private val taskDao: TaskDao,
private val locationDao: LocationDao,
private val localBroadcastManager: LocalBroadcastManager,
private val alarmDao: AlarmDao,
private val tagDao: TagDao,
private val googleTaskDao: GoogleTaskDao,
private val googleTaskListDao: GoogleTaskListDao,
private val filterDao: FilterDao,
private val taskAttachmentDao: TaskAttachmentDao,
private val caldavDao: CaldavDao,
private val preferences: Preferences,
private val taskMover: TaskMover) {
private val result = ImportResult()
private fun setProgressMessage(
handler: Handler, progressDialog: ProgressDialog?, message: String) {
if (progressDialog == null) {
return
}
handler.post { progressDialog.setMessage(message) }
}
fun importTasks(context: Context, backupFile: Uri?, progressDialog: ProgressDialog?): ImportResult {
val handler = Handler(context.mainLooper)
val gson = Gson()
val `is`: InputStream?
`is` = try {
context.contentResolver.openInputStream(backupFile!!)
} catch (e: FileNotFoundException) {
throw IllegalStateException(e)
}
val reader = InputStreamReader(`is`, TasksJsonExporter.UTF_8)
val input = gson.fromJson(reader, JsonObject::class.java)
try {
val data = input["data"]
val version = input["version"].asInt
val backupContainer = gson.fromJson(data, BackupContainer::class.java)
backupContainer.tags?.forEach { tagData ->
tagData.setColor(themeToColor(context, version, tagData.getColor()!!))
if (tagDataDao.getByUuid(tagData.remoteId!!) == null) {
tagDataDao.createNew(tagData)
}
}
backupContainer.googleTaskAccounts?.forEach { googleTaskAccount ->
if (googleTaskListDao.getAccount(googleTaskAccount.account!!) == null) {
googleTaskListDao.insert(googleTaskAccount)
}
}
backupContainer.places?.forEach { place ->
if (locationDao.getByUid(place.uid!!) == null) {
locationDao.insert(place)
}
}
backupContainer.googleTaskLists?.forEach { googleTaskList ->
googleTaskList.setColor(themeToColor(context, version, googleTaskList.getColor()!!))
if (googleTaskListDao.getByRemoteId(googleTaskList.remoteId!!) == null) {
googleTaskListDao.insert(googleTaskList)
}
}
backupContainer.filters?.forEach { filter ->
filter.setColor(themeToColor(context, version, filter.getColor()!!))
if (filterDao.getByName(filter.title!!) == null) {
filterDao.insert(filter)
}
}
backupContainer.caldavAccounts?.forEach { account ->
if (caldavDao.getAccountByUuid(account.uuid!!) == null) {
caldavDao.insert(account)
}
}
backupContainer.caldavCalendars?.forEach { calendar ->
calendar.color = themeToColor(context, version, calendar.color)
if (caldavDao.getCalendarByUuid(calendar.uuid!!) == null) {
caldavDao.insert(calendar)
}
}
backupContainer.tasks?.forEach { backup ->
result.taskCount++
setProgressMessage(
handler,
progressDialog,
context.getString(R.string.import_progress_read, result.taskCount))
val task = backup.task
if (taskDao.fetch(task.uuid) != null) {
result.skipCount++
return@forEach
}
task.suppressRefresh()
task.suppressSync()
taskDao.createNew(task)
val taskId = task.id
val taskUuid = task.uuid
for (alarm in backup.alarms) {
alarm.task = taskId
alarmDao.insert(alarm)
}
for (comment in backup.comments) {
comment.targetId = taskUuid
if (version < 546) {
comment.convertPictureUri()
}
userActivityDao.createNew(comment)
}
for (googleTask in backup.google) {
googleTask.task = taskId
googleTaskDao.insert(googleTask)
}
for (location in backup.locations) {
val place = newPlace()
place.longitude = location.longitude
place.latitude = location.latitude
place.name = location.name
place.address = location.address
place.url = location.url
place.phone = location.phone
locationDao.insert(place)
val geofence = Geofence()
geofence.task = taskId
geofence.place = place.uid
geofence.radius = location.radius
geofence.isArrival = location.arrival
geofence.isDeparture = location.departure
locationDao.insert(geofence)
}
for (tag in backup.tags) {
tag.task = taskId
tag.setTaskUid(taskUuid)
tagDao.insert(tag)
}
backup.geofences?.forEach { geofence ->
geofence.task = taskId
locationDao.insert(geofence)
}
backup.attachments?.forEach { attachment ->
attachment.taskId = taskUuid
if (version < 546) {
attachment.convertPathUri()
}
taskAttachmentDao.insert(attachment)
}
backup.caldavTasks?.forEach { caldavTask ->
caldavTask.task = taskId
caldavDao.insert(caldavTask)
}
result.importCount++
}
googleTaskDao.updateParents()
caldavDao.updateParents()
backupContainer.intPrefs?.forEach { (key, value) ->
if (Preferences.P_CURRENT_VERSION == key) {
return@forEach
}
preferences.setInt(key, value)
}
backupContainer.longPrefs?.forEach { (key, value) ->
preferences.setLong(key, value)
}
backupContainer.stringPrefs?.forEach { (key, value) ->
preferences.setString(key, value)
}
backupContainer.boolPrefs?.forEach { (key, value) ->
preferences.setBoolean(key, value)
}
if (version < Upgrader.V8_2) {
val themeIndex = preferences.getInt(R.string.p_theme_color, 7)
preferences.setInt(
R.string.p_theme_color,
getAndroidColor(context, themeIndex))
}
if (version < Upgrader.V9_6) {
taskMover.migrateLocalTasks()
}
reader.close()
`is`!!.close()
} catch (e: IOException) {
Timber.e(e)
}
localBroadcastManager.broadcastRefresh()
return result
}
private fun themeToColor(context: Context, version: Int, color: Int) =
if (version < Upgrader.V8_2) getAndroidColor(context, color) else color
class ImportResult {
var taskCount = 0
var importCount = 0
var skipCount = 0
}
class LegacyLocation {
var name: String? = null
var address: String? = null
var phone: String? = null
var url: String? = null
var latitude = 0.0
var longitude = 0.0
var radius = 0
var arrival = false
var departure = false
}
}

@ -82,9 +82,12 @@ public class ImportTasksDialog extends DialogFragment {
context.getString(
R.string.import_summary_message,
"",
r.getQuantityString(R.plurals.Ntasks, result.taskCount, result.taskCount),
r.getQuantityString(R.plurals.Ntasks, result.importCount, result.importCount),
r.getQuantityString(R.plurals.Ntasks, result.skipCount, result.skipCount),
r.getQuantityString(R.plurals.Ntasks, result.getTaskCount(), result.getTaskCount()),
r.getQuantityString(
R.plurals.Ntasks,
result.getImportCount(),
result.getImportCount()),
r.getQuantityString(R.plurals.Ntasks, result.getSkipCount(), result.getSkipCount()),
r.getQuantityString(R.plurals.Ntasks, 0, 0)))
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.dismiss())
.show();

Loading…
Cancel
Save