diff --git a/api/src/com/todoroo/andlib/utility/AndroidUtilities.java b/api/src/com/todoroo/andlib/utility/AndroidUtilities.java index 9a231a5a6..7d5f535da 100644 --- a/api/src/com/todoroo/andlib/utility/AndroidUtilities.java +++ b/api/src/com/todoroo/andlib/utility/AndroidUtilities.java @@ -526,16 +526,55 @@ public class AndroidUtilities { * @param args arguments * @return method return value, or null if nothing was called or exception */ - @SuppressWarnings("nls") public static Object callApiMethod(int minSdk, Object receiver, String methodName, Class[] params, Object... args) { if(getSdkVersion() < minSdk) return null; - Method method; + return AndroidUtilities.callMethod(receiver.getClass(), + receiver, methodName, params, args); + } + + /** + * Call a static method via reflection if API level is at least minSdk + * @param minSdk minimum sdk number (i.e. 8) + * @param className fully qualified class to call method on + * @param methodName method name to call + * @param params method parameter types + * @param args arguments + * @return method return value, or null if nothing was called or exception + */ + @SuppressWarnings("nls") + public static Object callApiStaticMethod(int minSdk, String className, + String methodName, Class[] params, Object... args) { + if(getSdkVersion() < minSdk) + return null; + + try { + return AndroidUtilities.callMethod(Class.forName(className), + null, methodName, params, args); + } catch (ClassNotFoundException e) { + getExceptionService().reportError("call-method", e); + return null; + } + } + + /** + * Call a method via reflection + * @param class class to call method on + * @param receiver object to call method on (can be null) + * @param methodName method name to call + * @param params method parameter types + * @param args arguments + * @return method return value, or null if nothing was called or exception + */ + @SuppressWarnings("nls") + public static Object callMethod(Class cls, Object receiver, + String methodName, Class[] params, Object... args) { try { - method = receiver.getClass().getMethod(methodName, params); - return method.invoke(receiver, args); + Method method = cls.getMethod(methodName, params); + Object result = method.invoke(receiver, args); + return result; } catch (SecurityException e) { getExceptionService().reportError("call-method", e); } catch (NoSuchMethodException e) { diff --git a/api/src/com/todoroo/astrid/data/TaskApiDao.java b/api/src/com/todoroo/astrid/data/TaskApiDao.java index c09237eb5..d7cd59fe1 100644 --- a/api/src/com/todoroo/astrid/data/TaskApiDao.java +++ b/api/src/com/todoroo/astrid/data/TaskApiDao.java @@ -171,10 +171,6 @@ public class TaskApiDao extends ContentResolverDao { values.size() <= 2) return true; - if(values.containsKey(Task.ELAPSED_SECONDS.name) && - values.size() <= 2) - return true; - return false; } diff --git a/astrid/.classpath b/astrid/.classpath index 7065d4619..273ff2370 100644 --- a/astrid/.classpath +++ b/astrid/.classpath @@ -29,5 +29,7 @@ + + diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index 0ae2b7074..e2db0d2c2 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionName="3.9.2" + android:versionCode="207"> @@ -318,12 +318,6 @@ - - - - - - @@ -641,6 +635,9 @@ + diff --git a/astrid/astrid.launch b/astrid/astrid.launch index 7b969a0ea..cb174a74d 100644 --- a/astrid/astrid.launch +++ b/astrid/astrid.launch @@ -6,7 +6,7 @@ - + diff --git a/astrid/build.xml b/astrid/build.xml index 1549c435e..3cdedd7e3 100644 --- a/astrid/build.xml +++ b/astrid/build.xml @@ -142,7 +142,7 @@ replace="\1 true;" /> - + diff --git a/astrid/common-src/com/localytics/android/DatapointHelper.java b/astrid/common-src/com/localytics/android/DatapointHelper.java index 5d42528d0..5b1600d95 100755 --- a/astrid/common-src/com/localytics/android/DatapointHelper.java +++ b/astrid/common-src/com/localytics/android/DatapointHelper.java @@ -8,15 +8,6 @@ package com.localytics.android; -import android.Manifest.permission; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.Build; -import android.telephony.TelephonyManager; -import android.util.Log; - import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -27,6 +18,15 @@ import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import android.Manifest.permission; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.telephony.TelephonyManager; +import android.util.Log; + /** * Provides a number of static functions to aid in the collection and formatting of datapoints. *

diff --git a/astrid/common-src/com/localytics/android/JsonObjects.java b/astrid/common-src/com/localytics/android/JsonObjects.java index 69d9bb15f..0df5ac190 100644 --- a/astrid/common-src/com/localytics/android/JsonObjects.java +++ b/astrid/common-src/com/localytics/android/JsonObjects.java @@ -1,9 +1,9 @@ package com.localytics.android; -import android.Manifest.permission; - import org.json.JSONArray; +import android.Manifest.permission; + /** * Set of constants for building JSON objects that get sent to the Localytics web service. */ diff --git a/astrid/common-src/com/localytics/android/LocalyticsProvider.java b/astrid/common-src/com/localytics/android/LocalyticsProvider.java index d25e30a93..a757bd4de 100644 --- a/astrid/common-src/com/localytics/android/LocalyticsProvider.java +++ b/astrid/common-src/com/localytics/android/LocalyticsProvider.java @@ -1,5 +1,13 @@ package com.localytics.android; +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -10,14 +18,6 @@ import android.database.sqlite.SQLiteQueryBuilder; import android.provider.BaseColumns; import android.util.Log; -import java.io.File; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - /** * Implements the storage mechanism for the Localytics library. The interface and implementation are similar to a ContentProvider * but modified to be better suited to a library. The interface is table-oriented, rather than Uri-oriented. diff --git a/astrid/common-src/com/localytics/android/LocalyticsSession.java b/astrid/common-src/com/localytics/android/LocalyticsSession.java index 248562947..face66b40 100755 --- a/astrid/common-src/com/localytics/android/LocalyticsSession.java +++ b/astrid/common-src/com/localytics/android/LocalyticsSession.java @@ -8,23 +8,6 @@ package com.localytics.android; -import android.Manifest.permission; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.CursorJoiner; -import android.os.Build; -import android.os.Build.VERSION; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.SystemClock; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.util.Log; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -51,6 +34,23 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import android.Manifest.permission; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.CursorJoiner; +import android.os.Build; +import android.os.Build.VERSION; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.text.format.DateUtils; +import android.util.Log; + import com.localytics.android.JsonObjects.BlobHeader; import com.localytics.android.LocalyticsProvider.ApiKeysDbColumns; import com.localytics.android.LocalyticsProvider.AttributesDbColumns; diff --git a/astrid/common-src/com/mdimension/jchronic/AstridChronic.java b/astrid/common-src/com/mdimension/jchronic/AstridChronic.java new file mode 100644 index 000000000..7cf5b3251 --- /dev/null +++ b/astrid/common-src/com/mdimension/jchronic/AstridChronic.java @@ -0,0 +1,198 @@ +package com.mdimension.jchronic; + +import java.util.LinkedList; +import java.util.List; + +import com.mdimension.jchronic.handlers.Handler; +import com.mdimension.jchronic.numerizer.Numerizer; +import com.mdimension.jchronic.repeaters.Repeater; +import com.mdimension.jchronic.tags.Grabber; +import com.mdimension.jchronic.tags.Ordinal; +import com.mdimension.jchronic.tags.Pointer; +import com.mdimension.jchronic.tags.Scalar; +import com.mdimension.jchronic.tags.Separator; +import com.mdimension.jchronic.tags.TimeZone; +import com.mdimension.jchronic.utils.Span; +import com.mdimension.jchronic.utils.Token; + +public class AstridChronic { + public static final String VERSION = "0.2.3"; + + private AstridChronic() { + // DO NOTHING + } + + public static Span parse(String text) { + return AstridChronic.parse(text, new Options()); + } + + /** + * Parses a string containing a natural language date or time. If the parser + * can find a date or time, either a Time or Chronic::Span will be returned + * (depending on the value of :guess). If no date or time can be found, + * +nil+ will be returned. + * + * Options are: + * + * [:context] + * :past or :future (defaults to :future) + * + * If your string represents a birthday, you can set :context to :past + * and if an ambiguous string is given, it will assume it is in the + * past. Specify :future or omit to set a future context. + * + * [:now] + * Time (defaults to Time.now) + * + * By setting :now to a Time, all computations will be based off + * of that time instead of Time.now + * + * [:guess] + * +true+ or +false+ (defaults to +true+) + * + * By default, the parser will guess a single point in time for the + * given date or time. If you'd rather have the entire time span returned, + * set :guess to +false+ and a Chronic::Span will be returned. + * + * [:ambiguous_time_range] + * Integer or :none (defaults to 6 (6am-6pm)) + * + * If an Integer is given, ambiguous times (like 5:00) will be + * assumed to be within the range of that time in the AM to that time + * in the PM. For example, if you set it to 7, then the parser will + * look for the time between 7am and 7pm. In the case of 5:00, it would + * assume that means 5:00pm. If :none is given, no assumption + * will be made, and the first matching instance of that time will + * be used. + */ + @SuppressWarnings("unchecked") + public static Span parse(String text, Options options) { + // store now for later =) + //_now = options.getNow(); + + // put the text into a normal format to ease scanning + String normalizedText = AstridChronic.preNormalize(text); + + // get base tokens for each word + List tokens = AstridChronic.baseTokenize(normalizedText); + + try { + tokens = Repeater.scan(tokens, options); + } catch (Throwable e) { + throw new RuntimeException("Failed to scan tokens.", e); + } + + List scannerClasses = new LinkedList(); + scannerClasses.add(Grabber.class); + scannerClasses.add(Pointer.class); + scannerClasses.add(Scalar.class); + scannerClasses.add(Ordinal.class); + scannerClasses.add(Separator.class); + scannerClasses.add(TimeZone.class); + for (Class scannerClass : scannerClasses) { + try { + tokens = (List) scannerClass.getMethod("scan", List.class, Options.class).invoke(null, tokens, options); + } + catch (Throwable e) { + throw new RuntimeException("Failed to scan tokens.", e); + } + } + + List taggedTokens = new LinkedList(); + for (Token token : tokens) { + if (token.isTagged()) { + taggedTokens.add(token); + } + } + tokens = taggedTokens; + + if (options.isDebug()) { + System.out.println("Chronic.parse: " + tokens); + } + + Span span = Handler.tokensToSpan(tokens, options); + + // guess a time within a span if required + if (options.isGuess()) { + span = guess(span); + } + + return span; + } + + /** + * Clean up the specified input text by stripping unwanted characters, + * converting idioms to their canonical form, converting number words + * to numbers (three => 3), and converting ordinal words to numeric + * ordinals (third => 3rd) + */ + protected static String preNormalize(String text) { + String normalizedText = text.toLowerCase(); + normalizedText = Chronic.numericizeNumbers(normalizedText); + normalizedText = normalizedText.replaceAll("['\"\\.]", ""); + normalizedText = normalizedText.replaceAll("([/\\-,@])", " $1 "); + normalizedText = normalizedText.replaceAll("\\btoday\\b", "this day"); + normalizedText = normalizedText.replaceAll("\\btomm?orr?ow\\b", "next day"); + normalizedText = normalizedText.replaceAll("\\byesterday\\b", "last day"); + normalizedText = normalizedText.replaceAll("\\bnoon\\b", "12:00"); + normalizedText = normalizedText.replaceAll("\\bmidnight\\b", "24:00"); + normalizedText = normalizedText.replaceAll("\\bbefore now\\b", "past"); + normalizedText = normalizedText.replaceAll("\\bnow\\b", "this second"); + normalizedText = normalizedText.replaceAll("\\b(ago|before)\\b", "past"); + normalizedText = normalizedText.replaceAll("\\bthis past\\b", "last"); + normalizedText = normalizedText.replaceAll("\\bthis last\\b", "last"); + normalizedText = normalizedText.replaceAll("\\b(?:in|during) the (morning)\\b", "$1"); + normalizedText = normalizedText.replaceAll("\\b(?:in the|during the|at) (afternoon|evening|night)\\b", "$1"); + normalizedText = normalizedText.replaceAll("\\btonight\\b", "this night"); + normalizedText = normalizedText.replaceAll("(?=\\w)([ap]m|oclock)\\b", " $1"); + normalizedText = normalizedText.replaceAll("\\b(hence|after|from)\\b", "future"); + normalizedText = AstridChronic.numericizeOrdinals(normalizedText); + return normalizedText; + } + + /** + * Convert number words to numbers (three => 3) + */ + protected static String numericizeNumbers(String text) { + return Numerizer.numerize(text); + } + + /** + * Convert ordinal words to numeric ordinals (third => 3rd) + */ + protected static String numericizeOrdinals(String text) { + return text; + } + + /** + * Split the text on spaces and convert each word into + * a Token + */ + protected static List baseTokenize(String text) { + String[] words = text.split(" "); + List tokens = new LinkedList(); + for (String word : words) { + tokens.add(new Token(word)); + } + return tokens; + } + + /** + * Guess a specific time within the given span + */ + // DIFF: We return Span instead of Date + protected static Span guess(Span span) { + if (span == null) { + return null; + } + long guessValue; + if (span.getWidth() > 1) { + guessValue = span.getBegin() + (span.getWidth() / 2); + } + else { + guessValue = span.getBegin(); + } + Span guess = new Span(guessValue, guessValue); + return guess; + } +} diff --git a/astrid/libs/android-support-v4.jar b/astrid/libs/android-support-v4.jar new file mode 100755 index 000000000..d006198e6 Binary files /dev/null and b/astrid/libs/android-support-v4.jar differ diff --git a/astrid/libs/jchronic-0.2.3.jar b/astrid/libs/jchronic-0.2.3.jar new file mode 100644 index 000000000..c0f15a32a Binary files /dev/null and b/astrid/libs/jchronic-0.2.3.jar differ diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java index 1924f8489..8f79a9a53 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/ActFmLoginActivity.java @@ -136,7 +136,8 @@ public class ActFmLoginActivity extends FragmentActivity implements AuthListener ContextManager.setContext(this); setContentView(getContentViewResource()); - setTitle(getTitleResource()); + if(getTitleResource() != 0) + setTitle(getTitleResource()); if (getSupportActionBar() != null) getSupportActionBar().hide(); @@ -146,15 +147,6 @@ public class ActFmLoginActivity extends FragmentActivity implements AuthListener noSync = getIntent().getBooleanExtra(EXTRA_DO_NOT_SYNC, false); showToast = getIntent().getBooleanExtra(SHOW_TOAST, true); - - facebook = new Facebook(APP_ID); - facebookRunner = new AsyncFacebookRunner(facebook); - - errors = (TextView) findViewById(R.id.error); - LoginButton loginButton = (LoginButton) findViewById(R.id.fb_login); - loginButton.init(this, facebook, this, new String[] { "email", - "offline_access", "publish_stream" }); - initializeUI(); getWindow().setFormat(PixelFormat.RGBA_8888); @@ -198,6 +190,14 @@ public class ActFmLoginActivity extends FragmentActivity implements AuthListener } protected void initializeUI() { + facebook = new Facebook(APP_ID); + facebookRunner = new AsyncFacebookRunner(facebook); + + errors = (TextView) findViewById(R.id.error); + LoginButton loginButton = (LoginButton) findViewById(R.id.fb_login); + loginButton.init(this, facebook, this, new String[] { "email", + "offline_access", "publish_stream" }); + findViewById(R.id.gg_login).setOnClickListener(googleListener); Button pwLogin = (Button) findViewById(R.id.pw_login); pwLogin.setOnClickListener(signUpListener); diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/TagUpdatesActivity.java b/astrid/plugin-src/com/todoroo/astrid/actfm/TagUpdatesActivity.java index cd4570b12..2de190d18 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/TagUpdatesActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/TagUpdatesActivity.java @@ -1,7 +1,6 @@ package com.todoroo.astrid.actfm; import android.app.ListActivity; -import android.app.ProgressDialog; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; @@ -28,7 +27,6 @@ import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback; import com.todoroo.astrid.actfm.ActFmCameraModule.ClearImageCallback; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; @@ -38,6 +36,7 @@ import com.todoroo.astrid.dao.UpdateDao; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Update; +import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; import com.todoroo.astrid.service.TagDataService; @@ -141,7 +140,7 @@ public class TagUpdatesActivity extends ListActivity { }); refreshUpdatesList(); - refreshActivity(null); // start a pull in the background + refreshActivity(false); // start a pull in the background } private void refreshUpdatesList() { @@ -191,8 +190,7 @@ public class TagUpdatesActivity extends ListActivity { case MENU_REFRESH_ID: { - final ProgressDialog progressDialog = DialogUtilities.progressDialog(this, getString(R.string.DLG_please_wait)); - refreshActivity(progressDialog); + refreshActivity(true); return true; } @@ -200,20 +198,25 @@ public class TagUpdatesActivity extends ListActivity { } } - private void refreshActivity(final ProgressDialog progressDialog) { - actFmSyncService.fetchUpdatesForTag(tagData, true, new Runnable() { + private void refreshActivity(boolean manual) { + final ProgressBarSyncResultCallback callback = new ProgressBarSyncResultCallback( + this, R.id.progressBar, new Runnable() { + @Override + public void run() { + refreshUpdatesList(); + } + }); + + callback.started(); + callback.incrementMax(100); + actFmSyncService.fetchUpdatesForTag(tagData, manual, new Runnable() { @Override public void run() { - runOnUiThread(new Runnable() { - @Override - public void run() { - refreshUpdatesList(); - if (progressDialog != null) - DialogUtilities.dismissDialog(TagUpdatesActivity.this, progressDialog); - } - }); + callback.incrementProgress(50); + callback.finished(); } }); + callback.incrementProgress(50); } @SuppressWarnings("nls") diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewActivity.java b/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewActivity.java index 672683f84..9719063c9 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/TagViewActivity.java @@ -2,14 +2,10 @@ package com.todoroo.astrid.actfm; import greendroid.widget.AsyncImageView; -import java.io.IOException; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import android.app.Activity; -import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -19,7 +15,8 @@ import android.support.v4.view.Menu; import android.support.v4.view.MenuItem; import android.text.TextUtils; import android.util.DisplayMetrics; -import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; @@ -51,9 +48,9 @@ import com.todoroo.astrid.core.SortHelper; import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.tags.TagFilterExposer; -import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService.Tag; import com.todoroo.astrid.welcome.HelpInfoPopover; @@ -72,7 +69,7 @@ public class TagViewActivity extends TaskListActivity { private static final int REQUEST_CODE_SETTINGS = 0; - public static final String TOKEN_START_ACTIVITY = "startActivity"; + public static final String TOKEN_START_ACTIVITY = "startActivity"; //$NON-NLS-1$ private TagData tagData; @@ -211,17 +208,6 @@ public class TagViewActivity extends TaskListActivity { cursor.close(); } - if(tagData.getValue(TagData.REMOTE_ID) > 0) { - String fetchKey = LAST_FETCH_KEY + tagData.getId(); - long lastFetchDate = Preferences.getLong(fetchKey, 0); - if(DateUtilities.now() > lastFetchDate + 300000L) { - refreshData(false, false); - Preferences.setLong(fetchKey, DateUtilities.now()); - } - } else { - ((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.TLA_no_items); - } - setUpMembersGallery(); super.onNewIntent(intent); @@ -253,90 +239,33 @@ public class TagViewActivity extends TaskListActivity { // --------------------------------------------------------- refresh data - /** refresh the list with latest data from the web */ - private void refreshData(final boolean manual, boolean bypassTagShow) { - final boolean noRemoteId = tagData.getValue(TagData.REMOTE_ID) == 0; - final ProgressDialog progressDialog; - if(manual && !noRemoteId) - progressDialog = DialogUtilities.progressDialog(getActivity(), getString(R.string.DLG_please_wait)); - else - progressDialog = null; - - Thread tagShowThread = new Thread(new Runnable() { - @SuppressWarnings("nls") - @Override - public void run() { - try { - String oldName = tagData.getValue(TagData.NAME); - actFmSyncService.fetchTag(tagData); - - Activity activity = getActivity(); - if (activity != null) { - DialogUtilities.dismissDialog(activity, progressDialog); - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if(noRemoteId && tagData.getValue(TagData.REMOTE_ID) > 0) - refreshData(manual, true); - } - }); - } - - if(!oldName.equals(tagData.getValue(TagData.NAME))) { - TagService.getInstance().rename(oldName, - tagData.getValue(TagData.NAME)); - } - - } catch (IOException e) { - Log.e("tag-view-activity", "error-fetching-task-io", e); - } catch (JSONException e) { - Log.e("tag-view-activity", "error-fetching-task", e); - } - } - }); - if(!bypassTagShow) - tagShowThread.start(); + @Override + protected void initiateAutomaticSync() { + long lastAutoSync = Preferences.getLong(LAST_FETCH_KEY + tagData.getId(), 0); + if(DateUtilities.now() - lastAutoSync > DateUtilities.ONE_HOUR) + refreshData(false); + } - if(noRemoteId) { - ((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.TLA_no_items); - return; - } + /** refresh the list with latest data from the web */ + private void refreshData(final boolean manual) { + ((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.DLG_loading); - setUpMembersGallery(); - actFmSyncService.fetchTasksForTag(tagData, manual, new Runnable() { + syncService.synchronizeList(tagData, manual, new ProgressBarSyncResultCallback(this, + R.id.progressBar, new Runnable() { @Override public void run() { - final Activity activity = getActivity(); - if (activity != null) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - loadTaskListContent(true); - ((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.TLA_no_items); - DialogUtilities.dismissDialog(activity, progressDialog); - } - }); - } + setUpMembersGallery(); + loadTaskListContent(true); + ((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.TLA_no_items); } - }); + })); + Preferences.setLong(LAST_FETCH_KEY + tagData.getId(), DateUtilities.now()); - actFmSyncService.fetchUpdatesForTag(tagData, manual, new Runnable() { - @Override - public void run() { - final Activity activity = getActivity(); - if (activity != null) { - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - //refreshUpdatesList(); - DialogUtilities.dismissDialog(activity, progressDialog); - } - }); - } - } - }); + final boolean noRemoteId = tagData.getValue(TagData.REMOTE_ID) == 0; + if(noRemoteId && !manual) + ((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.TLA_no_items); } private void setUpMembersGallery() { @@ -483,7 +412,7 @@ public class TagViewActivity extends TaskListActivity { //refreshUpdatesList(); } }); - refreshData(false, true); + refreshData(false); NotificationManager nm = new AndroidNotificationManager(ContextManager.getContext()); nm.cancel(tagData.getValue(TagData.REMOTE_ID).intValue()); @@ -532,7 +461,7 @@ public class TagViewActivity extends TaskListActivity { // handle my own menus switch (item.getItemId()) { case MENU_REFRESH_ID: - refreshData(true, false); + refreshData(true); return true; } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncProvider.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncProvider.java index f54a91b8c..89bfc7b88 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncProvider.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncProvider.java @@ -133,15 +133,16 @@ public class ActFmSyncProvider extends SyncProvider { try { int serverTime = Preferences.getInt(ActFmPreferenceService.PREF_SERVER_TIME, 0); + ArrayList remoteTasks = new ArrayList(); - int newServerTime = fetchRemoteTasks(serverTime, remoteTasks); + // int newServerTime = fetchRemoteTasks(serverTime, remoteTasks); if (serverTime == 0) { // If we've never synced, we may lose some empty tags pushUnsavedTagData(); } - fetchRemoteTagData(serverTime); + // fetchRemoteTagData(serverTime); - SyncData syncData = populateSyncData(remoteTasks); + /* SyncData syncData = populateSyncData(remoteTasks); try { synchronizeTasks(syncData); @@ -150,7 +151,8 @@ public class ActFmSyncProvider extends SyncProvider { syncData.localUpdated.close(); } - Preferences.setInt(ActFmPreferenceService.PREF_SERVER_TIME, newServerTime); + Preferences.setInt(ActFmPreferenceService.PREF_SERVER_TIME, newServerTime); */ + actFmPreferenceService.recordSuccessfulSync(); syncSuccess = getFinalSyncStatus(); @@ -321,6 +323,7 @@ public class ActFmSyncProvider extends SyncProvider { } else { // Set default reminders for remotely created tasks TaskDao.setDefaultReminders(task.task); } + task.task.setValue(Task.LAST_SYNC, DateUtilities.now() + 1000); actFmDataService.saveTaskAndMetadata(task); } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java index 4382389d3..2e517038c 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java @@ -395,15 +395,17 @@ public final class ActFmSyncService { JSONObject result = actFmInvoker.invoke("task_save", params.toArray(new Object[params.size()])); ArrayList metadata = new ArrayList(); JsonHelper.taskFromJson(result, task, metadata); - Flags.set(Flags.ACTFM_SUPPRESS_SYNC); - taskDao.saveExisting(task); } catch (JSONException e) { handleException("task-save-json", e); } catch (IOException e) { if (notPermanentError(e)) addFailedPush(new FailedPush(PUSH_TYPE_TASK, task.getId())); handleException("task-save-io", e); + task.setValue(Task.LAST_SYNC, DateUtilities.now() + 1000L); } + + Flags.set(Flags.ACTFM_SUPPRESS_SYNC); + taskDao.saveExisting(task); } /** @@ -647,10 +649,11 @@ public final class ActFmSyncService { /** * Fetch all tags * @param serverTime + * @return new serverTime */ - public void fetchTags(int serverTime) throws JSONException, IOException { + public int fetchTags(int serverTime) throws JSONException, IOException { if(!checkForToken()) - return; + return 0; JSONObject result = actFmInvoker.invoke("tag_list", "token", token, "modified_after", serverTime); @@ -666,6 +669,53 @@ public final class ActFmSyncService { Long[] remoteIdArray = remoteIds.toArray(new Long[remoteIds.size()]); tagDataService.deleteWhere(Criterion.not(TagData.REMOTE_ID.in(remoteIdArray))); } + + return result.optInt("time", 0); + } + + /** + * Fetch active tasks asynchronously + * @param manual + * @param done + */ + public void fetchActiveTasks(final boolean manual, Runnable done) { + invokeFetchList("task", manual, new ListItemProcessor() { + @Override + protected void mergeAndSave(JSONArray list, HashMap locals) throws JSONException { + Task remote = new Task(); + + ArrayList metadata = new ArrayList(); + for(int i = 0; i < list.length(); i++) { + JSONObject item = list.getJSONObject(i); + readIds(locals, item, remote); + JsonHelper.taskFromJson(item, remote, metadata); + + if(remote.getValue(Task.USER_ID) == 0) { + if(!remote.isSaved()) + StatisticsService.reportEvent(StatisticsConstants.ACTFM_TASK_CREATED); + else if(remote.isCompleted()) + StatisticsService.reportEvent(StatisticsConstants.ACTFM_TASK_COMPLETED); + } + + if(!remote.isSaved() && remote.hasDueDate() && + remote.getValue(Task.DUE_DATE) < DateUtilities.now()) + remote.setFlag(Task.REMINDER_FLAGS, Task.NOTIFY_AFTER_DEADLINE, false); + + Flags.set(Flags.ACTFM_SUPPRESS_SYNC); + taskService.save(remote); + metadataService.synchronizeMetadata(remote.getId(), metadata, MetadataCriteria.withKey(TagService.KEY)); + remote.clear(); + } + } + + @Override + protected HashMap getLocalModels() { + TodorooCursor cursor = taskService.query(Query.select(Task.ID, + Task.REMOTE_ID).where(Task.REMOTE_ID.in(remoteIds)).orderBy( + Order.asc(Task.REMOTE_ID))); + return cursorToMap(cursor, taskDao, Task.REMOTE_ID, Task.ID); + } + }, done, "active_tasks"); } /** diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java new file mode 100644 index 000000000..78dc16837 --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java @@ -0,0 +1,234 @@ +/** + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.actfm.sync; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +import org.json.JSONException; + +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.service.ExceptionService; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.dao.TaskDao.TaskCriteria; +import com.todoroo.astrid.data.TagData; +import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.service.AstridDependencyInjector; +import com.todoroo.astrid.service.StartupService; +import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback; +import com.todoroo.astrid.service.SyncV2Service.SyncV2Provider; +import com.todoroo.astrid.service.TaskService; +import com.todoroo.astrid.tags.TagService; + +/** + * Exposes sync action + * + */ +public class ActFmSyncV2Provider implements SyncV2Provider { + + @Autowired ActFmPreferenceService actFmPreferenceService; + + @Autowired ActFmSyncService actFmSyncService; + + @Autowired ExceptionService exceptionService; + + @Autowired TaskService taskService; + + static { + AstridDependencyInjector.initialize(); + } + + public ActFmSyncV2Provider() { + DependencyInjectionService.getInstance().inject(this); + } + + @Override + public boolean isActive() { + return actFmPreferenceService.isLoggedIn(); + } + + private static final String LAST_TAG_FETCH_TIME = "actfm_lastTag"; //$NON-NLS-1$ + + // --- synchronize active tasks + + @Override + public void synchronizeActiveTasks(boolean manual, + final SyncResultCallback callback) { + + callback.started(); + callback.incrementMax(100); + + final AtomicInteger finisher = new AtomicInteger(2); + + startTagFetcher(callback, finisher); + + startTaskFetcher(manual, callback, finisher); + + pushQueued(callback, finisher); + + callback.incrementProgress(50); + } + + /** fetch changes to tags */ + private void startTagFetcher(final SyncResultCallback callback, + final AtomicInteger finisher) { + new Thread(new Runnable() { + @Override + public void run() { + int time = Preferences.getInt(LAST_TAG_FETCH_TIME, 0); + try { + time = actFmSyncService.fetchTags(time); + Preferences.setInt(LAST_TAG_FETCH_TIME, time); + } catch (JSONException e) { + exceptionService.reportError("actfm-sync", e); //$NON-NLS-1$ + } catch (IOException e) { + exceptionService.reportError("actfm-sync", e); //$NON-NLS-1$ + } finally { + callback.incrementProgress(20); + if(finisher.decrementAndGet() == 0) + callback.finished(); + } + } + }).start(); + } + + /** @return runnable to fetch changes to tags */ + private void startTaskFetcher(final boolean manual, final SyncResultCallback callback, + final AtomicInteger finisher) { + actFmSyncService.fetchActiveTasks(manual, new Runnable() { + @Override + public void run() { + callback.incrementProgress(30); + if(finisher.decrementAndGet() == 0) + callback.finished(); + } + }); + } + + private void pushQueued(final SyncResultCallback callback, + final AtomicInteger finisher) { + TodorooCursor cursor = taskService.query(Query.select(Task.PROPERTIES). + where(Criterion.or( + Criterion.and(TaskCriteria.isActive(), + Task.ID.gt(StartupService.INTRO_TASK_SIZE), + Task.REMOTE_ID.eq(0)), + Criterion.and(Task.REMOTE_ID.gt(0), + Task.MODIFICATION_DATE.gt(Task.LAST_SYNC))))); + + try { + callback.incrementMax(cursor.getCount() * 20); + finisher.addAndGet(cursor.getCount()); + + for(int i = 0; i < cursor.getCount(); i++) { + cursor.moveToNext(); + final Task task = new Task(cursor); + + new Thread(new Runnable() { + public void run() { + try { + actFmSyncService.pushTaskOnSave(task, task.getMergedValues()); + } finally { + callback.incrementProgress(20); + if(finisher.decrementAndGet() == 0) + callback.finished(); + } + } + }).start(); + } + } finally { + cursor.close(); + } + } + + // --- synchronize list + + @Override + public void synchronizeList(Object list, boolean manual, + final SyncResultCallback callback) { + + if(!(list instanceof TagData)) + return; + + TagData tagData = (TagData) list; + final boolean noRemoteId = tagData.getValue(TagData.REMOTE_ID) == 0; + + if(noRemoteId && !manual) + return; + + callback.started(); + callback.incrementMax(100); + + final AtomicInteger finisher = new AtomicInteger(3); + + fetchTagData(tagData, noRemoteId, manual, callback, finisher); + + if(!noRemoteId) { + fetchTasksForTag(tagData, manual, callback, finisher); + fetchUpdatesForTag(tagData, manual, callback, finisher); + } + + callback.incrementProgress(50); + } + + private void fetchTagData(final TagData tagData, final boolean noRemoteId, + final boolean manual, final SyncResultCallback callback, + final AtomicInteger finisher) { + new Thread(new Runnable() { + @Override + public void run() { + String oldName = tagData.getValue(TagData.NAME); + try { + actFmSyncService.fetchTag(tagData); + + if(noRemoteId) { + fetchTasksForTag(tagData, manual, callback, finisher); + fetchUpdatesForTag(tagData, manual, callback, finisher); + } + + if(!oldName.equals(tagData.getValue(TagData.NAME))) { + TagService.getInstance().rename(oldName, + tagData.getValue(TagData.NAME)); + } + } catch (IOException e) { + exceptionService.reportError("sync-io", e); //$NON-NLS-1$ + } catch (JSONException e) { + exceptionService.reportError("sync-json", e); //$NON-NLS-1$ + } finally { + callback.incrementProgress(20); + if(finisher.decrementAndGet() == 0) + callback.finished(); + } + } + }).start(); + } + + private void fetchUpdatesForTag(TagData tagData, boolean manual, final SyncResultCallback callback, + final AtomicInteger finisher) { + actFmSyncService.fetchUpdatesForTag(tagData, manual, new Runnable() { + @Override + public void run() { + callback.incrementProgress(20); + if(finisher.decrementAndGet() == 0) + callback.finished(); + } + }); + } + + private void fetchTasksForTag(TagData tagData, boolean manual, final SyncResultCallback callback, + final AtomicInteger finisher) { + actFmSyncService.fetchTasksForTag(tagData, manual, new Runnable() { + @Override + public void run() { + callback.incrementProgress(30); + if(finisher.decrementAndGet() == 0) + callback.finished(); + } + }); + } + +} diff --git a/astrid/plugin-src/com/todoroo/astrid/gcal/GCalHelper.java b/astrid/plugin-src/com/todoroo/astrid/gcal/GCalHelper.java index 68cde8d4a..6a19306a1 100644 --- a/astrid/plugin-src/com/todoroo/astrid/gcal/GCalHelper.java +++ b/astrid/plugin-src/com/todoroo/astrid/gcal/GCalHelper.java @@ -7,10 +7,12 @@ import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.text.TextUtils; +import android.text.format.Time; import android.util.Log; import com.timsu.astrid.R; import com.todoroo.andlib.service.ContextManager; +import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.core.PluginServices; @@ -66,8 +68,10 @@ public class GCalHelper { values.put("title", task.getValue(Task.TITLE)); values.put("description", task.getValue(Task.NOTES)); values.put("hasAlarm", 0); - values.put("transparency", 0); - values.put("visibility", 0); + if (AndroidUtilities.getSdkVersion() < 14) { + values.put("transparency", 0); + values.put("visibility", 0); + } boolean valuesContainCalendarId = (values.containsKey("calendar_id") && !TextUtils.isEmpty(values.getAsString("calendar_id"))); if (!valuesContainCalendarId) { @@ -152,5 +156,16 @@ public class GCalHelper { values.put("dtend", tzCorrectedDueDateNow); values.put("allDay", "1"); } + adjustDateForIcs(task, values); + } + + private static void adjustDateForIcs(Task task, ContentValues values) { + if (AndroidUtilities.getSdkVersion() >= 14) { + if ("1".equals(values.get("allDay"))) { + values.put("eventTimezone", Time.TIMEZONE_UTC); + } else { + values.put("eventTimezone", TimeZone.getDefault().getID()); + } + } } -} \ No newline at end of file +} diff --git a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java index 86e4f2b0d..8850a9082 100644 --- a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java @@ -10,7 +10,6 @@ import java.util.List; import org.json.JSONObject; import android.app.ListActivity; -import android.app.ProgressDialog; import android.content.Context; import android.graphics.Color; import android.os.Bundle; @@ -37,7 +36,6 @@ import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.actfm.sync.ActFmSyncService; @@ -47,9 +45,11 @@ import com.todoroo.astrid.dao.UpdateDao; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Update; +import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; +import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback; import com.todoroo.astrid.utility.Flags; public class EditNoteActivity extends ListActivity { @@ -95,12 +95,12 @@ public class EditNoteActivity extends ListActivity { findViewById(R.id.add_comment).setVisibility(View.VISIBLE); if(task.getValue(Task.REMOTE_ID) == 0) - refreshData(true); + refreshData(true, null); else { String fetchKey = LAST_FETCH_KEY + task.getId(); long lastFetchDate = Preferences.getLong(fetchKey, 0); if(DateUtilities.now() > lastFetchDate + 300000L) { - refreshData(false); + refreshData(false, null); Preferences.setLong(fetchKey, DateUtilities.now()); } else { loadingText.setText(R.string.ENA_no_comments); @@ -223,21 +223,32 @@ public class EditNoteActivity extends ListActivity { // --- events - private void refreshData(boolean manual) { - final ProgressDialog progressDialog; - if(manual) - progressDialog = DialogUtilities.progressDialog(this, getString(R.string.DLG_please_wait)); - else - progressDialog = null; + private void refreshData(boolean manual, SyncResultCallback existingCallback) { + final SyncResultCallback callback; + if(existingCallback != null) + callback = existingCallback; + else { + callback = new ProgressBarSyncResultCallback( + this, R.id.progressBar, new Runnable() { + @Override + public void run() { + setUpListAdapter(); + loadingText.setText(R.string.ENA_no_comments); + loadingText.setVisibility(items.size() == 0 ? View.VISIBLE : View.GONE); + } + }); + + callback.started(); + callback.incrementMax(100); + } + // push task if it hasn't been pushed if(task.getValue(Task.REMOTE_ID) == 0) { - // push task if it hasn't been pushed new Thread(new Runnable() { @Override public void run() { actFmSyncService.pushTask(task.getId()); - refreshData(false); - DialogUtilities.dismissDialog(EditNoteActivity.this, progressDialog); + refreshData(false, callback); } }).start(); return; @@ -246,17 +257,11 @@ public class EditNoteActivity extends ListActivity { actFmSyncService.fetchUpdatesForTask(task, manual, new Runnable() { @Override public void run() { - runOnUiThread(new Runnable() { - @Override - public void run() { - setUpListAdapter(); - loadingText.setText(R.string.ENA_no_comments); - loadingText.setVisibility(items.size() == 0 ? View.VISIBLE : View.GONE); - DialogUtilities.dismissDialog(EditNoteActivity.this, progressDialog); - } - }); + callback.incrementProgress(50); + callback.finished(); } }); + callback.incrementProgress(50); } private void addComment() { @@ -288,7 +293,7 @@ public class EditNoteActivity extends ListActivity { switch (item.getItemId()) { case MENU_REFRESH_ID: { - refreshData(true); + refreshData(true, null); return true; } diff --git a/astrid/proguard.cfg b/astrid/proguard.cfg index e679392c2..f900d0750 100644 --- a/astrid/proguard.cfg +++ b/astrid/proguard.cfg @@ -9,6 +9,7 @@ -dontoptimize -keepattributes SourceFile, SourceDir, LineNumberTable, LocalVariableTable, LocalVariableTypeTable -keep class com.todoroo.** +-keep class com.mdimension.** -keepnames class com.google.** # ignore reflection-based access from google libraries diff --git a/astrid/project.properties b/astrid/project.properties index d7ae8bbc2..2da646782 100644 --- a/astrid/project.properties +++ b/astrid/project.properties @@ -15,4 +15,4 @@ android.library.reference.2=../actionbarsherlock/library # Project target. target=android-14 apk-configurations= -android.library.reference.4=../greendroid/GreenDroid +android.library.reference.4=../viewPagerIndicator/library diff --git a/astrid/res/drawable-hdpi/header_logo.png b/astrid/res/drawable-hdpi/header_logo.png deleted file mode 100644 index 2330431e0..000000000 Binary files a/astrid/res/drawable-hdpi/header_logo.png and /dev/null differ diff --git a/astrid/res/drawable/astrid_com_logo_old.png b/astrid/res/drawable/astrid_com_logo_old.png deleted file mode 100644 index 5f9ff6893..000000000 Binary files a/astrid/res/drawable/astrid_com_logo_old.png and /dev/null differ diff --git a/astrid/res/drawable/header_logo.png b/astrid/res/drawable/header_logo.png deleted file mode 100644 index c04477bf0..000000000 Binary files a/astrid/res/drawable/header_logo.png and /dev/null differ diff --git a/astrid/res/drawable/icon_old.png b/astrid/res/drawable/icon_old.png deleted file mode 100644 index 25402e7f6..000000000 Binary files a/astrid/res/drawable/icon_old.png and /dev/null differ diff --git a/astrid/res/drawable/icon_plus.png b/astrid/res/drawable/icon_plus.png deleted file mode 100644 index fa6bfd062..000000000 Binary files a/astrid/res/drawable/icon_plus.png and /dev/null differ diff --git a/astrid/res/drawable/welcome_walkthrough_1.png b/astrid/res/drawable/welcome_walkthrough_1.png new file mode 100644 index 000000000..b7a4b0a58 Binary files /dev/null and b/astrid/res/drawable/welcome_walkthrough_1.png differ diff --git a/astrid/res/drawable/welcome_walkthrough_2.png b/astrid/res/drawable/welcome_walkthrough_2.png new file mode 100644 index 000000000..04857d997 Binary files /dev/null and b/astrid/res/drawable/welcome_walkthrough_2.png differ diff --git a/astrid/res/drawable/welcome_walkthrough_3.png b/astrid/res/drawable/welcome_walkthrough_3.png new file mode 100644 index 000000000..8fd2b31f4 Binary files /dev/null and b/astrid/res/drawable/welcome_walkthrough_3.png differ diff --git a/astrid/res/drawable/welcome_walkthrough_4.png b/astrid/res/drawable/welcome_walkthrough_4.png new file mode 100644 index 000000000..624f4157f Binary files /dev/null and b/astrid/res/drawable/welcome_walkthrough_4.png differ diff --git a/astrid/res/drawable/welcome_walkthrough_5.png b/astrid/res/drawable/welcome_walkthrough_5.png new file mode 100644 index 000000000..8a601fd15 Binary files /dev/null and b/astrid/res/drawable/welcome_walkthrough_5.png differ diff --git a/astrid/res/drawable/welcome_walkthrough_6.png b/astrid/res/drawable/welcome_walkthrough_6.png new file mode 100644 index 000000000..f353d3d63 Binary files /dev/null and b/astrid/res/drawable/welcome_walkthrough_6.png differ diff --git a/astrid/res/drawable/welcome_walkthrough_fabric.png b/astrid/res/drawable/welcome_walkthrough_fabric.png new file mode 100644 index 000000000..67f9c3941 Binary files /dev/null and b/astrid/res/drawable/welcome_walkthrough_fabric.png differ diff --git a/astrid/res/layout/edit_note_activity.xml b/astrid/res/layout/edit_note_activity.xml index b371ae39f..951355cf1 100644 --- a/astrid/res/layout/edit_note_activity.xml +++ b/astrid/res/layout/edit_note_activity.xml @@ -5,6 +5,15 @@ android:layout_height="fill_parent" android:orientation="vertical" android:background="@drawable/background_gradient"> + + + + + diff --git a/astrid/res/layout/task_list_activity.xml b/astrid/res/layout/task_list_activity.xml index 4e331735b..539016f54 100644 --- a/astrid/res/layout/task_list_activity.xml +++ b/astrid/res/layout/task_list_activity.xml @@ -7,6 +7,14 @@ style="@style/Content" android:orientation="vertical"> + + diff --git a/astrid/res/layout/welcome_walkthrough.xml b/astrid/res/layout/welcome_walkthrough.xml new file mode 100755 index 000000000..48265dd26 --- /dev/null +++ b/astrid/res/layout/welcome_walkthrough.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/astrid/res/layout/welcome_walkthrough_login_page.xml b/astrid/res/layout/welcome_walkthrough_login_page.xml new file mode 100644 index 000000000..3b0ff4323 --- /dev/null +++ b/astrid/res/layout/welcome_walkthrough_login_page.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + +