added a monthly update force for Astrid, also fixed up task importing. but it doesn't work yet?

pull/14/head
Tim Su 14 years ago
parent b30e9a8e56
commit 5d43da7b68

@ -17,7 +17,7 @@ public class BackupConstants {
// Do NOT edit the constants in this file! You will break compatibility with old backups
// --- format 2
// --- general xml
/** Tag containing Astrid backup data */
public static final String ASTRID_TAG = "astrid";
@ -28,9 +28,14 @@ public class BackupConstants {
/** Attribute indicating backup file format */
public static final String ASTRID_ATTR_FORMAT = "format";
// --- format 2
/** Tag containing a task */
public static final String TASK_TAG = "task";
/** Tag containing a metadata item */
public static final String METADATA_TAG = "metadata";
// --- format 1
public static final String TAG_TAG = "tag";

@ -46,7 +46,7 @@ public class FilePickerBuilder extends AlertDialog.Builder implements DialogInte
private void setPath(File path) {
if (path != null && path.exists()) {
this.path = path.getAbsolutePath();
// Reverse the order of the file list so newest timestamped file is first.
// Reverse the order of the file list so newest time-stamped file is first.
List<String> fileList = Arrays.asList(path.list(filter));
Collections.sort(fileList);
Collections.reverse(fileList);

@ -9,7 +9,6 @@ import org.xmlpull.v1.XmlSerializer;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.Xml;
import android.widget.Toast;
@ -57,10 +56,10 @@ public class TasksXmlExporter {
private final ExceptionService exceptionService = PluginServices.getExceptionService();
private final ProgressDialog progressDialog;
private final Handler importHandler;
private final Handler handler;
private void setProgress(final int taskNumber, final int total, final String title) {
importHandler.post(new Runnable() {
handler.post(new Runnable() {
public void run() {
progressDialog.setProgress(taskNumber * 10000 / total);
progressDialog.setMessage(context.getString(R.string.export_progress_read, title));
@ -73,23 +72,24 @@ public class TasksXmlExporter {
this.exportCount = 0;
progressDialog = new ProgressDialog(context);
importHandler = new Handler();
importHandler.post(new Runnable() {
@Override
public void run() {
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
progressDialog.setTitle(R.string.export_progress_title);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(false);
progressDialog.show();
}
});
handler = new Handler();
if(!isService) {
handler.post(new Runnable() {
@Override
public void run() {
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
progressDialog.setTitle(R.string.export_progress_title);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(false);
progressDialog.show();
}
});
}
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
try {
String output = setupFile(BackupConstants.getExportDirectory(),
isService);
@ -108,7 +108,6 @@ public class TasksXmlExporter {
Preferences.setString(BackupService.PREF_BACKUP_LAST_ERROR, e.toString());
}
}
Looper.loop();
}
}).start();
}
@ -152,7 +151,7 @@ public class TasksXmlExporter {
setProgress(i, length, task.getValue(Task.TITLE));
xml.startTag(null, BackupConstants.TASK_TAG);
serializeModel(task, Task.PROPERTIES);
serializeModel(task, Task.PROPERTIES, Task.ID);
serializeMetadata(task);
xml.endTag(null, BackupConstants.TASK_TAG);
this.exportCount++;
@ -170,9 +169,9 @@ public class TasksXmlExporter {
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
metadata.readFromCursor(cursor);
xml.startTag(null, BackupConstants.TAG_TAG);
serializeModel(metadata, Metadata.PROPERTIES);
xml.endTag(null, BackupConstants.TAG_TAG);
xml.startTag(null, BackupConstants.METADATA_TAG);
serializeModel(metadata, Metadata.PROPERTIES, Metadata.ID, Metadata.TASK);
xml.endTag(null, BackupConstants.METADATA_TAG);
}
} finally {
cursor.close();
@ -183,8 +182,12 @@ public class TasksXmlExporter {
* Turn a model into xml attributes
* @param model
*/
private void serializeModel(AbstractModel model, Property<?>[] properties) {
for(Property<?> property : properties) {
private void serializeModel(AbstractModel model, Property<?>[] properties, Property<?>... excludes) {
outer: for(Property<?> property : properties) {
for(Property<?> exclude : excludes)
if(property == exclude)
continue outer;
try {
property.accept(xmlWritingVisitor, model);
} catch (Exception e) {
@ -259,11 +262,16 @@ public class TasksXmlExporter {
}
private void displayToast(String output) {
CharSequence text = String.format(context.getString(R.string.export_toast),
context.getResources().getQuantityString(R.plurals.Ntasks, exportCount,
exportCount), output);
Toast.makeText(context, text, Toast.LENGTH_LONG).show();
private void displayToast(final String output) {
handler.post(new Runnable() {
@Override
public void run() {
CharSequence text = String.format(context.getString(R.string.export_toast),
context.getResources().getQuantityString(R.plurals.Ntasks, exportCount,
exportCount), output);
Toast.makeText(context, text, Toast.LENGTH_LONG).show();
}
});
}
/**

@ -16,11 +16,14 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import com.google.ical.values.RRule;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.PropertyVisitor;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.ExceptionService;
@ -102,7 +105,6 @@ public class TasksXmlImporter {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
try {
performImport();
} catch (IOException e) {
@ -112,7 +114,6 @@ public class TasksXmlImporter {
exceptionService.displayAndReportError(context,
context.getString(R.string.backup_TXI_error), e);
}
Looper.loop();
}
}).start();
}
@ -136,27 +137,15 @@ public class TasksXmlImporter {
if (tag != null) {
// Process <astrid ... >
if (tag.equals(BackupConstants.ASTRID_TAG)) {
String version = xpp.getAttributeValue(null, BackupConstants.ASTRID_ATTR_FORMAT);
int intVersion;
try {
intVersion = version == null ? 1 : Integer.parseInt(version);
} catch (Exception e) {
String format = xpp.getAttributeValue(null, BackupConstants.ASTRID_ATTR_FORMAT);
if(TextUtils.equals(format, FORMAT1))
new Format1TaskImporter(xpp);
else if(TextUtils.equals(format, FORMAT2))
new Format2TaskImporter(xpp);
else
throw new UnsupportedOperationException(
"Did not know how to import tasks with xml format '" +
version + "'");
}
switch(intVersion) {
case 1:
new Astrid2TaskImporter(xpp);
break;
case 2:
new Astrid3TaskImporter(xpp);
break;
default:
throw new UnsupportedOperationException(
"Did not know how to import tasks with xml format number '" +
version + "'");
}
format + "'");
}
}
}
@ -167,7 +156,7 @@ public class TasksXmlImporter {
}
private void showSummary() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.import_summary_title);
Resources r = context.getResources();
String message = context.getString(R.string.import_summary_message,
@ -185,22 +174,149 @@ public class TasksXmlImporter {
}
}
});
builder.show();
importHandler.post(new Runnable() {
@Override
public void run() {
builder.show();
}
});
}
// --- importers
private class Astrid3TaskImporter {
@SuppressWarnings("unused")
// =============================================================== FORMAT2
private static final String FORMAT2 = "2"; //$NON-NLS-1$
private class Format2TaskImporter {
private final XmlPullParser xpp;
private final Task currentTask = new Task();
private final Metadata metadata = new Metadata();
public Astrid3TaskImporter(XmlPullParser xpp) {
public Format2TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException {
this.xpp = xpp;
// TODO
while (xpp.next() != XmlPullParser.END_DOCUMENT) {
String tag = xpp.getName();
if (tag == null || xpp.getEventType() == XmlPullParser.END_TAG)
continue;
else if (tag.equals(BackupConstants.TASK_TAG)) {
// Parse <task ... >
parseTask();
} else if (tag.equals(BackupConstants.METADATA_TAG)) {
// Process <metadata ... >
parseMetadata();
}
}
}
private void parseTask() {
taskCount++;
setProgressMessage(context.getString(R.string.import_progress_read,
taskCount));
currentTask.clear();
String title = xpp.getAttributeValue(null, Task.TITLE.name);
String created = xpp.getAttributeValue(null, Task.CREATION_DATE.name);
// if we don't have task name or creation date, skip
if (created == null || title == null) {
skipCount++;
return;
}
// if the task's name and creation date match an existing task, skip
TodorooCursor<Task> cursor = taskService.query(Query.select(Task.ID).
where(Criterion.and(Task.TITLE.eq(title),
Task.CREATION_DATE.eq(created))));
try {
if(cursor.getCount() > 0) {
skipCount++;
return;
}
} finally {
cursor.close();
}
// else, make a new task model and add away.
deserializeModel(currentTask, Task.PROPERTIES);
// Save the task to the database.
taskService.save(currentTask, false);
importCount++;
}
private void parseMetadata() {
if(!currentTask.isSaved())
return;
metadata.clear();
deserializeModel(metadata, Metadata.PROPERTIES);
metadata.setValue(Metadata.TASK, currentTask.getId());
metadataService.save(metadata);
}
/**
* Turn a model into xml attributes
* @param model
*/
private void deserializeModel(AbstractModel model, Property<?>[] properties) {
for(Property<?> property : properties) {
try {
property.accept(xmlReadingVisitor, model);
} catch (Exception e) {
Log.e("astrid-importer", //$NON-NLS-1$
"Caught exception while writing " + property.name + //$NON-NLS-1$
" from " + xpp.getText(), e); //$NON-NLS-1$
}
}
}
private final XmlReadingPropertyVisitor xmlReadingVisitor = new XmlReadingPropertyVisitor();
private class XmlReadingPropertyVisitor implements PropertyVisitor<Void, AbstractModel> {
@Override
public Void visitInteger(Property<Integer> property,
AbstractModel data) {
String value = xpp.getAttributeValue(null, property.name);
if(value != null)
data.setValue(property, Integer.parseInt(value));
return null;
}
@Override
public Void visitLong(Property<Long> property, AbstractModel data) {
String value = xpp.getAttributeValue(null, property.name);
if(value != null)
data.setValue(property, Long.parseLong(value));
return null;
}
@Override
public Void visitDouble(Property<Double> property,
AbstractModel data) {
String value = xpp.getAttributeValue(null, property.name);
if(value != null)
data.setValue(property, Double.parseDouble(value));
return null;
}
@Override
public Void visitString(Property<String> property,
AbstractModel data) {
String value = xpp.getAttributeValue(null, property.name);
if(value != null)
data.setValue(property, value);
return null;
}
}
}
private class Astrid2TaskImporter {
// =============================================================== FORMAT1
private static final String FORMAT1 = null;
private class Format1TaskImporter {
private final XmlPullParser xpp;
private Task currentTask = null;
private String upgradeNotes = null;
@ -208,7 +324,7 @@ public class TasksXmlImporter {
private final ArrayList<String> tags = new ArrayList<String>();
public Astrid2TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException {
public Format1TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException {
this.xpp = xpp;
while (xpp.next() != XmlPullParser.END_DOCUMENT) {

@ -41,6 +41,12 @@
<string name="export_toast">Backed Up %s to %s.</string>
<!-- Progress Dialog Title for exporting -->
<string name="export_progress_title">Exporting...</string>
<!-- Progress Dialog text for export reading task (%s -> task title) -->
<string name="export_progress_read">Reading task %s...</string>
<!-- Summary title for import -->
<string name="import_summary_title">Restore Summary</string>
@ -50,22 +56,25 @@ File %s contained %s.\n\n
%s imported,\n
%s already exist\n
</string>
<!-- Progress Dialog Title for importing -->
<string name="import_progress_title">Importing...</string>
<!-- Progress Dialog Title for exporting -->
<string name="export_progress_title">Exporting...</string>
<!-- Progress Dialog text for import opening file -->
<string name="import_progress_open">Opening file...</string>
<!-- Progress Dialog text for import reading task (%d -> task number)-->
<string name="import_progress_read">Reading task %d...</string>
<!-- Progress Dialog text for export reading task (%s -> task title) -->
<string name="export_progress_read">Reading task %s...</string>
<!-- Dialog when unable to open a file -->
<string name="DLG_error_opening">Could not find this item: </string>
<!-- Dialog when unable to open SD card folder -->
<string name="DLG_error_sdcard">Cannot access folder: %s</string>
<!-- Dialog when unable to open SD card in general -->
<string name="DLG_error_sdcard_general">Cannot access your SD card!</string>
<!-- File Selector dialog for import -->
<string name="import_file_prompt">Select a File to Restore</string>

@ -122,15 +122,14 @@
<!-- Title for dialog selecting a time (hours and minutes) -->
<string name="DLG_hour_minutes">Time (hours : minutes)</string>
<!-- Dialog when unable to open a file -->
<string name="DLG_error_opening">Could not find this item: </string>
<!-- Dialog when unable to open SD card folder -->
<string name="DLG_error_sdcard">Cannot access folder: %s</string>
<!-- Dialog when Astrid needs to be updated -->
<string name="DLG_please_update">Astrid should to be updated to the latest
version in the Android market! Please do that before continuing, or wait a
few seconds.</string>
<!-- Dialog when unable to open SD card in general -->
<string name="DLG_error_sdcard_general">Cannot access your SD card!</string>
<!-- Button for going to Market -->
<string name="DLG_to_market">Go To Market</string>
<!-- =============================================================== UI == -->

@ -3,6 +3,9 @@ package com.todoroo.astrid.activity;
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
import android.app.AlertDialog;
import android.app.ListActivity;
@ -15,6 +18,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
@ -157,6 +161,8 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
if(database == null)
return;
checkForUpgrades();
database.openForWriting();
setUpUiComponents();
setUpTaskList();
@ -171,6 +177,55 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
}).start();
}
private void checkForUpgrades() {
final AtomicInteger countdown = new AtomicInteger(10);
if(DateUtilities.now() > Constants.UPGRADE.getTime()) {
DialogInterface.OnClickListener okListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:" + //$NON-NLS-1$
getPackageName())));
finish();
}
};
final AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.DLG_information_title)
.setMessage(R.string.DLG_please_update)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.DLG_to_market, okListener)
.setNegativeButton(countdown.toString(), null)
.setCancelable(false)
.show();
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false);
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
final int number = countdown.addAndGet(-1);
if(number == 0)
timer.cancel();
runOnUiThread(new Runnable() {
public void run() {
if(number == 0) {
dialog.setCancelable(true);
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setText(
android.R.string.ok);
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(true);
} else {
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setText(
Integer.toString(number));
}
}
});
}
}, 0L, 1000L);
}
}
/**
* Create options menu (displayed when user presses menu key)
*

@ -1,5 +1,7 @@
package com.todoroo.astrid.utility;
import java.util.Date;
public final class Constants {
// --- general application constants
@ -30,6 +32,11 @@ public final class Constants {
*/
public static final boolean DEBUG = false;
/**
* Upgrade time
*/
public static final Date UPGRADE = new Date(110, 8, 1);
// --- notification id's
/** Notification Manager id for sync notifications */

Loading…
Cancel
Save