producteev preferences, created an abstract sync preferences

pull/14/head
Tim Su 16 years ago
parent 62d55bf50e
commit 66300d4eb3

@ -289,6 +289,19 @@
android:taskAffinity="com.todoroo.astrid.reminders.NotificationActivity"
android:screenOrientation="portrait"
android:clearTaskOnLaunch="true" />
<!-- producteev -->
<activity android:name="com.todoroo.astrid.producteev.ProducteevPreferences"
android:icon="@drawable/ic_menu_rmilk"
android:label="@string/producteev_PPr_header">
<intent-filter>
<action android:name="com.todoroo.astrid.TASK_LIST_MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<!-- rmilk -->
<receiver android:name="com.todoroo.astrid.rmilk.MilkFilterExposer">

@ -0,0 +1,326 @@
package com.todoroo.astrid.common;
import java.util.Date;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceManager;
import android.view.View;
import android.view.ViewGroup.OnHierarchyChangeListener;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.widget.TodorooPreferences;
/**
* Utility class for common synchronization action: displaying synchronization
* preferences and an action panel so users can initiate actions from the menu.
*
* @author Tim Su <tim@todoroo.com
*
*/
abstract public class SyncProviderPreferences extends TodorooPreferences {
// --- interface
/**
* @return your plugin identifier
*/
abstract public String getIdentifier();
/**
* @return your preference resource
*/
@Override
abstract public int getPreferenceResource();
/**
* @return key for sync interval
*/
abstract public int getSyncIntervalKey();
/**
* kick off synchronization
*/
abstract public void startSync();
/**
* log user out
*/
abstract public void logOut();
// --- preference utility methods
private static final String PREF_TOKEN = "_token"; //$NON-NLS-1$
private static final String PREF_LAST_SYNC = "_last_sync"; //$NON-NLS-1$
private static final String PREF_LAST_ATTEMPTED_SYNC = "_last_attempted"; //$NON-NLS-1$
private static final String PREF_LAST_ERROR = "_last_error"; //$NON-NLS-1$
private static final String PREF_ONGOING = "_ongoing"; //$NON-NLS-1$
/** Get preferences object from the context */
private static SharedPreferences getPrefs() {
return PreferenceManager.getDefaultSharedPreferences(ContextManager.getContext());
}
/**
* @return true if we have a token for this user, false otherwise
*/
public boolean isLoggedIn() {
return getPrefs().getString(getIdentifier() + PREF_TOKEN, null) != null;
}
/** authentication token, or null if doesn't exist */
public String getToken() {
return getPrefs().getString(getIdentifier() + PREF_TOKEN, null);
}
/** Sets the authentication token. Set to null to clear. */
public void setToken(String setting) {
Editor editor = getPrefs().edit();
editor.putString(getIdentifier() + PREF_TOKEN, setting);
editor.commit();
}
/** @return Last Successful Sync Date, or 0 */
public long getLastSyncDate() {
return getPrefs().getLong(getIdentifier() + PREF_LAST_SYNC, 0);
}
/** @return Last Attempted Sync Date, or 0 if it was successful */
public long getLastAttemptedSyncDate() {
return getPrefs().getLong(getIdentifier() + PREF_LAST_ATTEMPTED_SYNC, 0);
}
/** @return Last Error, or null if no last error */
public String getLastError() {
return getPrefs().getString(PREF_LAST_ERROR, null);
}
/** @return Last Error, or null if no last error */
public boolean isOngoing() {
return getPrefs().getBoolean(getIdentifier() + PREF_ONGOING, false);
}
/** Deletes Last Successful Sync Date */
public void clearLastSyncDate() {
Editor editor = getPrefs().edit();
editor.remove(getIdentifier() + PREF_LAST_SYNC);
editor.commit();
}
/** Set Last Successful Sync Date */
public void setLastError(String error) {
Editor editor = getPrefs().edit();
editor.putString(getIdentifier() + PREF_LAST_ERROR, error);
editor.commit();
}
/** Set Ongoing */
public void stopOngoing() {
Editor editor = getPrefs().edit();
editor.putBoolean(getIdentifier() + PREF_ONGOING, false);
editor.commit();
}
/** Set Last Successful Sync Date */
public void recordSuccessfulSync() {
Editor editor = getPrefs().edit();
editor.putLong(getIdentifier() + PREF_LAST_SYNC, DateUtilities.now());
editor.putLong(getIdentifier() + PREF_LAST_ATTEMPTED_SYNC, 0);
editor.commit();
}
/** Set Last Attempted Sync Date */
public void recordSyncStart() {
Editor editor = getPrefs().edit();
editor.putLong(getIdentifier() + PREF_LAST_ATTEMPTED_SYNC, DateUtilities.now());
editor.putString(getIdentifier() + PREF_LAST_ERROR, null);
editor.putBoolean(getIdentifier() + PREF_ONGOING, true);
editor.commit();
}
/**
* Reads the frequency, in seconds, auto-sync should occur.
*
* @return seconds duration, or 0 if not desired
*/
public static int getSyncAutoSyncFrequency() {
String value = getPrefs().getString(
ContextManager.getContext().getString(
R.string.rmilk_MPr_interval_key), null);
if (value == null)
return 0;
try {
return Integer.parseInt(value);
} catch (Exception e) {
return 0;
}
}
// --- implementation
@Autowired
private DialogUtilities dialogUtilities;
private int statusColor = Color.BLACK;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getListView().setOnHierarchyChangeListener(new OnHierarchyChangeListener() {
@Override
public void onChildViewRemoved(View parent, View child) {
//
}
@Override
public void onChildViewAdded(View parent, View child) {
View view = findViewById(R.id.status);
if(view != null)
view.setBackgroundColor(statusColor);
}
});
}
/**
*
* @param resource
* if null, updates all resources
*/
@Override
public void updatePreferences(Preference preference, Object value) {
final Resources r = getResources();
// interval
if (r.getString(getSyncIntervalKey()).equals(
preference.getKey())) {
int index = AndroidUtilities.indexOf(
r.getStringArray(R.array.rmilk_MPr_interval_values),
(String) value);
if (index <= 0)
preference.setSummary(R.string.rmilk_MPr_interval_desc_disabled);
else
preference.setSummary(r.getString(
R.string.rmilk_MPr_interval_desc,
r.getStringArray(R.array.rmilk_MPr_interval_entries)[index]));
}
// status
else if (r.getString(R.string.rmilk_MPr_status_key).equals(preference.getKey())) {
boolean loggedIn = isLoggedIn();
String status;
String subtitle = ""; //$NON-NLS-1$
// ! logged in - display message, click -> sync
if(!loggedIn) {
status = r.getString(R.string.rmilk_status_loggedout);
statusColor = Color.RED;
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
startSync();
finish();
return true;
}
});
}
// sync is occurring
else if(isOngoing()) {
status = r.getString(R.string.rmilk_status_ongoing);
statusColor = Color.rgb(0, 0, 100);
}
// last sync was error
else if(getLastAttemptedSyncDate() != 0) {
status = r.getString(R.string.rmilk_status_failed,
DateUtilities.getDateWithTimeFormat(SyncProviderPreferences.this).
format(new Date(getLastAttemptedSyncDate())));
if(getLastSyncDate() > 0) {
subtitle = r.getString(R.string.rmilk_status_failed_subtitle,
DateUtilities.getDateWithTimeFormat(SyncProviderPreferences.this).
format(new Date(getLastSyncDate())));
}
statusColor = Color.rgb(100, 0, 0);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
String error = getLastError();
if(error != null)
dialogUtilities.okDialog(SyncProviderPreferences.this, error, null);
return true;
}
});
} else if(getLastSyncDate() > 0) {
status = r.getString(R.string.rmilk_status_success,
DateUtilities.getDateWithTimeFormat(SyncProviderPreferences.this).
format(new Date(getLastSyncDate())));
statusColor = Color.rgb(0, 100, 0);
} else {
status = r.getString(R.string.rmilk_status_never);
statusColor = Color.rgb(0, 0, 100);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
startSync();
finish();
return true;
}
});
}
preference.setTitle(status);
preference.setSummary(subtitle);
View view = findViewById(R.id.status);
if(view != null)
view.setBackgroundColor(statusColor);
}
// sync button
else if (r.getString(R.string.rmilk_MPr_sync_key).equals(preference.getKey())) {
boolean loggedIn = isLoggedIn();
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
startSync();
finish();
return true;
}
});
if(!loggedIn)
preference.setTitle(R.string.rmilk_MPr_sync_log_in);
}
// log out button
else if (r.getString(R.string.rmilk_MPr_forget_key).equals(preference.getKey())) {
boolean loggedIn = isLoggedIn();
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
dialogUtilities.okCancelDialog(SyncProviderPreferences.this,
r.getString(R.string.rmilk_forget_confirm), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
logOut();
initializePreference(getPreferenceScreen());
}
}, null);
return true;
}
});
if(!loggedIn)
preference.setEnabled(false);
}
}
}

@ -1,25 +1,8 @@
package com.todoroo.astrid.producteev;
import java.util.Date;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.view.View;
import android.view.ViewGroup.OnHierarchyChangeListener;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.widget.TodorooPreferences;
import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
import com.todoroo.astrid.common.SyncProviderPreferences;
import com.todoroo.astrid.producteev.sync.ProducteevSyncProvider;
/**
* Displays synchronization preferences and an action panel so users can
@ -28,166 +11,32 @@ import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
* @author timsu
*
*/
public class ProducteevPreferences extends TodorooPreferences {
public class ProducteevPreferences extends SyncProviderPreferences {
@Autowired
private DialogUtilities dialogUtilities;
private int statusColor = Color.BLACK;
@Override
public String getIdentifier() {
return "pdv"; //$NON-NLS-1$
}
@Override
public int getPreferenceResource() {
return R.xml.preferences_rmilk;
return R.xml.preferences_producteev;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getListView().setOnHierarchyChangeListener(new OnHierarchyChangeListener() {
@Override
public void onChildViewRemoved(View parent, View child) {
//
}
@Override
public void onChildViewAdded(View parent, View child) {
View view = findViewById(R.id.status);
if(view != null)
view.setBackgroundColor(statusColor);
}
});
public int getSyncIntervalKey() {
return R.string.producteev_PPr_interval_key;
}
@Override
protected void onPause() {
super.onPause();
MilkBackgroundService.scheduleService();
public void startSync() {
new ProducteevSyncProvider().synchronize(this);
}
/**
*
* @param resource
* if null, updates all resources
*/
@Override
public void updatePreferences(Preference preference, Object value) {
final Resources r = getResources();
// interval
if (r.getString(R.string.rmilk_MPr_interval_key).equals(
preference.getKey())) {
int index = AndroidUtilities.indexOf(
r.getStringArray(R.array.rmilk_MPr_interval_values),
(String) value);
if (index <= 0)
preference.setSummary(R.string.rmilk_MPr_interval_desc_disabled);
else
preference.setSummary(r.getString(
R.string.rmilk_MPr_interval_desc,
r.getStringArray(R.array.rmilk_MPr_interval_entries)[index]));
}
// status
else if (r.getString(R.string.rmilk_MPr_status_key).equals(preference.getKey())) {
boolean loggedIn = ProducteevUtilities.isLoggedIn();
String status;
String subtitle = ""; //$NON-NLS-1$
// ! logged in - display message, click -> sync
if(!loggedIn) {
status = r.getString(R.string.rmilk_status_loggedout);
statusColor = Color.RED;
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
startService(new Intent(ProducteevPreferences.this, MilkBackgroundService.class));
finish();
return true;
}
});
}
// sync is occurring
else if(ProducteevUtilities.isOngoing()) {
status = r.getString(R.string.rmilk_status_ongoing);
statusColor = Color.rgb(0, 0, 100);
}
// last sync was error
else if(ProducteevUtilities.getLastAttemptedSyncDate() != 0) {
status = r.getString(R.string.rmilk_status_failed,
DateUtilities.getDateWithTimeFormat(ProducteevPreferences.this).
format(new Date(ProducteevUtilities.getLastAttemptedSyncDate())));
if(ProducteevUtilities.getLastSyncDate() > 0) {
subtitle = r.getString(R.string.rmilk_status_failed_subtitle,
DateUtilities.getDateWithTimeFormat(ProducteevPreferences.this).
format(new Date(ProducteevUtilities.getLastSyncDate())));
}
statusColor = Color.rgb(100, 0, 0);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
String error = ProducteevUtilities.getLastError();
if(error != null)
dialogUtilities.okDialog(ProducteevPreferences.this, error, null);
return true;
}
});
} else if(ProducteevUtilities.getLastSyncDate() > 0) {
status = r.getString(R.string.rmilk_status_success,
DateUtilities.getDateWithTimeFormat(ProducteevPreferences.this).
format(new Date(ProducteevUtilities.getLastSyncDate())));
statusColor = Color.rgb(0, 100, 0);
} else {
status = r.getString(R.string.rmilk_status_never);
statusColor = Color.rgb(0, 0, 100);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
startService(new Intent(ProducteevPreferences.this, MilkBackgroundService.class));
finish();
return true;
}
});
}
preference.setTitle(status);
preference.setSummary(subtitle);
View view = findViewById(R.id.status);
if(view != null)
view.setBackgroundColor(statusColor);
}
// sync button
else if (r.getString(R.string.rmilk_MPr_sync_key).equals(preference.getKey())) {
boolean loggedIn = ProducteevUtilities.isLoggedIn();
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
new RTMSyncProvider().synchronize(ProducteevPreferences.this);
finish();
return true;
}
});
if(!loggedIn)
preference.setTitle(R.string.rmilk_MPr_sync_log_in);
}
// log out button
else if (r.getString(R.string.rmilk_MPr_forget_key).equals(preference.getKey())) {
boolean loggedIn = ProducteevUtilities.isLoggedIn();
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
dialogUtilities.okCancelDialog(ProducteevPreferences.this,
r.getString(R.string.rmilk_forget_confirm), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
new RTMSyncProvider().signOut();
initializePreference(getPreferenceScreen());
}
}, null);
return true;
}
});
if(!loggedIn)
preference.setEnabled(false);
}
public void logOut() {
new ProducteevSyncProvider().signOut();
}
}

@ -1,150 +0,0 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.producteev;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.DateUtilities;
/**
* Constants and preferences for rtm plugin
*
* @author Tim Su <tim@todoroo.com>
*
*/
@SuppressWarnings("nls")
public class ProducteevUtilities {
// --- constants
/** add-on identifier */
public static final String IDENTIFIER = "producteev";
// --- Preference Keys
private static final String PREF_TOKEN = "pdv_token";
private static final String PREF_LAST_SYNC = "pdv_last_sync";
private static final String PREF_LAST_SYNC_SERVER = "pdv_last_sync_server";
private static final String PREF_LAST_ATTEMPTED_SYNC = "pdv_last_attempted";
private static final String PREF_LAST_ERROR = "pdv_last_error";
private static final String PREF_ONGOING = "pdv_ongoing";
// --- Preference Utility Methods
/** Get preferences object from the context */
private static SharedPreferences getPrefs() {
return PreferenceManager.getDefaultSharedPreferences(ContextManager.getContext());
}
/**
* @return true if we have a token for this user, false otherwise
*/
public static boolean isLoggedIn() {
return getPrefs().getString(PREF_TOKEN, null) != null;
}
/** authentication token, or null if doesn't exist */
public static String getToken() {
return getPrefs().getString(PREF_TOKEN, null);
}
/** Sets the authentication token. Set to null to clear. */
public static void setToken(String setting) {
Editor editor = getPrefs().edit();
editor.putString(PREF_TOKEN, setting);
editor.commit();
}
/** @return Last Successful Sync Date, or 0 */
public static long getLastSyncDate() {
return getPrefs().getLong(PREF_LAST_SYNC, 0);
}
/** @return Last Attempted Sync Date, or 0 if it was successful */
public static long getLastAttemptedSyncDate() {
return getPrefs().getLong(PREF_LAST_ATTEMPTED_SYNC, 0);
}
/** @return Last Error, or null if no last error */
public static String getLastError() {
return getPrefs().getString(PREF_LAST_ERROR, null);
}
/** @return Last sync time according to producteev, or null */
public static String getLastServerSyncTime() {
return getPrefs().getString(PREF_LAST_SYNC_SERVER, null);
}
/** @return Last Error, or null if no last error */
public static boolean isOngoing() {
return getPrefs().getBoolean(PREF_ONGOING, false);
}
/** Deletes Last Successful Sync Date */
public static void clearLastSyncDate() {
Editor editor = getPrefs().edit();
editor.remove(PREF_LAST_SYNC);
editor.commit();
}
/** Set Last Successful Sync Date */
public static void setLastError(String error) {
Editor editor = getPrefs().edit();
editor.putString(PREF_LAST_ERROR, error);
editor.commit();
}
/** Set Ongoing */
public static void stopOngoing() {
Editor editor = getPrefs().edit();
editor.putBoolean(PREF_ONGOING, false);
editor.commit();
}
/** Set Last Successful Sync Date */
public static void recordSuccessfulSync(String producteevTime) {
Editor editor = getPrefs().edit();
editor.putLong(PREF_LAST_SYNC, DateUtilities.now());
editor.putLong(PREF_LAST_ATTEMPTED_SYNC, 0);
editor.putString(PREF_LAST_SYNC_SERVER, producteevTime);
editor.commit();
}
/** Set Last Attempted Sync Date */
public static void recordSyncStart() {
Editor editor = getPrefs().edit();
editor.putLong(PREF_LAST_ATTEMPTED_SYNC, DateUtilities.now());
editor.putString(PREF_LAST_ERROR, null);
editor.putBoolean(PREF_ONGOING, true);
editor.commit();
}
/**
* Reads the frequency, in seconds, auto-sync should occur.
*
* @return seconds duration, or 0 if not desired
*/
public static int getSyncAutoSyncFrequency() {
String value = getPrefs().getString(
ContextManager.getContext().getString(
R.string.rmilk_MPr_interval_key), null);
if (value == null)
return 0;
try {
return Integer.parseInt(value);
} catch (Exception e) {
return 0;
}
}
}

@ -5,18 +5,14 @@ package com.todoroo.astrid.producteev.sync;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import org.json.JSONObject;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.text.TextUtils;
import android.widget.Toast;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
@ -26,28 +22,15 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.api.SynchronizationProvider;
import com.todoroo.astrid.api.TaskContainer;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.producteev.ProducteevUtilities;
import com.todoroo.astrid.producteev.ProducteevPreferences;
import com.todoroo.astrid.producteev.api.ProducteevInvoker;
import com.todoroo.astrid.rmilk.MilkPreferences;
import com.todoroo.astrid.rmilk.MilkUtilities;
import com.todoroo.astrid.rmilk.api.ServiceInternalException;
import com.todoroo.astrid.rmilk.api.data.RtmTask;
import com.todoroo.astrid.rmilk.api.data.RtmTaskList;
import com.todoroo.astrid.rmilk.api.data.RtmTaskNote;
import com.todoroo.astrid.rmilk.api.data.RtmTaskSeries;
import com.todoroo.astrid.rmilk.api.data.RtmTasks;
import com.todoroo.astrid.rmilk.api.data.RtmTask.Priority;
import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkNote;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.Preferences;
public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTaskContainer> {
@ -55,6 +38,7 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
private MilkDataService dataService = null;
private ProducteevInvoker invoker = null;
private int defaultDashboard;
private final ProducteevPreferences preferences = new ProducteevPreferences();
static {
AstridDependencyInjector.initialize();
@ -79,8 +63,8 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
* Sign out of RTM, deleting all synchronization metadata
*/
public void signOut() {
ProducteevUtilities.setToken(null);
ProducteevUtilities.clearLastSyncDate();
preferences.setToken(null);
preferences.clearLastSyncDate();
dataService.clearMetadata(); // TODO clear metadata
}
@ -103,7 +87,7 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
*/
@Override
protected void handleException(String tag, Exception e, boolean showError) {
ProducteevUtilities.setLastError(e.toString());
preferences.setLastError(e.toString());
// occurs when application was closed
if(e instanceof IllegalStateException) {
@ -136,7 +120,9 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
dataService = MilkDataService.getInstance();
// authenticate the user. this will automatically call the next step
authenticate(context);
// authenticate(context);
Toast.makeText(context, "hi! this is empty", Toast.LENGTH_LONG);
}
/**
@ -147,10 +133,10 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
final Resources r = context.getResources();
FlurryAgent.onEvent("producteev-started");
ProducteevUtilities.recordSyncStart();
preferences.recordSyncStart();
try {
String authToken = ProducteevUtilities.getToken();
String authToken = preferences.getToken();
String z = stripslashes(0, "71o3346pr40o5o4nt4n7t6n287t4op28","2");
String v = stripslashes(2, "9641n76n9s1736q1578q1o1337q19233","4ae");
@ -174,7 +160,7 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
} catch (Exception e) {
handleException("rtm-authenticate", e, true);
} finally {
ProducteevUtilities.stopOngoing();
preferences.stopOngoing();
}
}
@ -191,7 +177,7 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
// read all tasks
JSONObject tasks = invoker.tasksShowList(defaultDashboard,
ProducteevUtilities.getLastServerSyncTime());
null); // TODO
SyncData<ProducteevTaskContainer> syncData = populateSyncData(tasks);
try {
@ -230,283 +216,71 @@ public class ProducteevSyncProvider extends SynchronizationProvider<ProducteevTa
/**
* Populate SyncData data structure
*/
private SyncData<ProducteevTaskContainer> populateSyncData(ArrayList<ProducteevTaskContainer> remoteTasks) {
private SyncData<ProducteevTaskContainer> populateSyncData(JSONObject tasks) {
// fetch locally created tasks
TodorooCursor<Task> localCreated = dataService.getLocallyCreated(PROPERTIES);
// fetch locally updated tasks
TodorooCursor<Task> localUpdated = dataService.getLocallyUpdated(PROPERTIES);
return new SyncData<ProducteevTaskContainer>(remoteTasks, localCreated, localUpdated);
}
/**
* Add the tasks read from RTM to the given list
*/
private void addTasksToList(RtmTasks tasks, ArrayList<ProducteevTaskContainer> list) {
for (RtmTaskList taskList : tasks.getLists()) {
for (RtmTaskSeries taskSeries : taskList.getSeries()) {
ProducteevTaskContainer remoteTask = parseRemoteTask(taskSeries);
dataService.findLocalMatch(remoteTask);
list.add(remoteTask);
}
}
// return new SyncData<ProducteevTaskContainer>(tasks, localCreated, localUpdated);
return null;
}
// ----------------------------------------------------------------------
// ------------------------------------------------- create / push / pull
// ----------------------------------------------------------------------
@Override
protected void create(ProducteevTaskContainer task) throws IOException {
String listId = null;
if(task.dashboard > 0)
listId = Long.toString(task.listId);
RtmTaskSeries rtmTask = rtmService.tasks_add(timeline, listId,
task.task.getValue(Task.TITLE));
ProducteevTaskContainer newRemoteTask = parseRemoteTask(rtmTask);
transferIdentifiers(newRemoteTask, task);
push(task, newRemoteTask);
}
/**
* Determine whether this task's property should be transmitted
* @param task task to consider
* @param property property to consider
* @param remoteTask remote task proxy
* @return
*/
private boolean shouldTransmit(TaskContainer task, Property<?> property, TaskContainer remoteTask) {
if(!task.task.containsValue(property))
return false;
if(remoteTask == null)
return true;
if(!remoteTask.task.containsValue(property))
return true;
// special cases - match if they're zero or nonzero
if(property == Task.COMPLETION_DATE ||
property == Task.DELETION_DATE)
return !AndroidUtilities.equals((Long)task.task.getValue(property) == 0,
(Long)remoteTask.task.getValue(property) == 0);
return !AndroidUtilities.equals(task.task.getValue(property),
remoteTask.task.getValue(property));
}
/**
* Send changes for the given Task across the wire. If a remoteTask is
* supplied, we attempt to intelligently only transmit the values that
* have changed.
*/
@Override
protected void push(ProducteevTaskContainer local, ProducteevTaskContainer remote) throws IOException {
boolean remerge = false;
// fetch remote task for comparison
if(remote == null)
remote = pull(local);
String listId = Long.toString(local.listId);
String taskSeriesId = Long.toString(local.taskSeriesId);
String taskId = Long.toString(local.taskId);
if(remote != null && !AndroidUtilities.equals(local.listId, remote.listId))
rtmService.tasks_moveTo(timeline, Long.toString(remote.listId),
listId, taskSeriesId, taskId);
// either delete or re-create if necessary
if(shouldTransmit(local, Task.DELETION_DATE, remote)) {
if(local.task.getValue(Task.DELETION_DATE) > 0)
rtmService.tasks_delete(timeline, listId, taskSeriesId, taskId);
else if(remote == null) {
RtmTaskSeries rtmTask = rtmService.tasks_add(timeline, listId,
local.task.getValue(Task.TITLE));
remote = parseRemoteTask(rtmTask);
transferIdentifiers(remote, local);
}
}
if(shouldTransmit(local, Task.TITLE, remote))
rtmService.tasks_setName(timeline, listId, taskSeriesId,
taskId, local.task.getValue(Task.TITLE));
if(shouldTransmit(local, Task.IMPORTANCE, remote))
rtmService.tasks_setPriority(timeline, listId, taskSeriesId,
taskId, Priority.values()[local.task.getValue(Task.IMPORTANCE)]);
if(shouldTransmit(local, Task.DUE_DATE, remote))
rtmService.tasks_setDueDate(timeline, listId, taskSeriesId,
taskId, DateUtilities.unixtimeToDate(local.task.getValue(Task.DUE_DATE)),
local.task.hasDueTime());
if(shouldTransmit(local, Task.COMPLETION_DATE, remote)) {
if(local.task.getValue(Task.COMPLETION_DATE) == 0)
rtmService.tasks_uncomplete(timeline, listId, taskSeriesId,
taskId);
else {
rtmService.tasks_complete(timeline, listId, taskSeriesId,
taskId);
// if repeating, pull and merge
if(local.repeating)
remerge = true;
}
}
// tags
HashSet<String> localTags = new HashSet<String>();
HashSet<String> remoteTags = new HashSet<String>();
for(Metadata item : local.metadata)
if(TagService.KEY.equals(item.getValue(Metadata.KEY)))
localTags.add(item.getValue(TagService.TAG));
if(remote != null && remote.metadata != null) {
for(Metadata item : remote.metadata)
if(TagService.KEY.equals(item.getValue(Metadata.KEY)))
remoteTags.add(item.getValue(TagService.TAG));
}
if(!localTags.equals(remoteTags)) {
String[] tags = localTags.toArray(new String[localTags.size()]);
rtmService.tasks_setTags(timeline, listId, taskSeriesId,
taskId, tags);
}
// notes
if(shouldTransmit(local, Task.NOTES, remote)) {
String[] titleAndText = MilkNote.fromNoteField(local.task.getValue(Task.NOTES));
List<RtmTaskNote> notes = null;
if(remote != null && remote.remote.getNotes() != null)
notes = remote.remote.getNotes().getNotes();
if(notes != null && notes.size() > 0) {
String remoteNoteId = notes.get(0).getId();
rtmService.tasks_notes_edit(timeline, remoteNoteId, titleAndText[0],
titleAndText[1]);
} else {
rtmService.tasks_notes_add(timeline, listId, taskSeriesId,
taskId, titleAndText[0], titleAndText[1]);
}
}
// ----------------------------------------------------------------------
// ------------------------------------------------------- helper classes
// ----------------------------------------------------------------------
if(remerge) {
remote = pull(local);
remote.task.setId(local.task.getId());
write(remote);
}
private static final String stripslashes(int ____,String __,String ___) {
int _=__.charAt(____/92);_=_==116?_-1:_;_=((_>=97)&&(_<=123)?
((_-83)%27+97):_);return TextUtils.htmlEncode(____==31?___:
stripslashes(____+1,__.substring(1),___+((char)_)));
}
/** Create a task container for the given RtmTaskSeries */
private ProducteevTaskContainer parseRemoteTask(RtmTaskSeries rtmTaskSeries) {
Task task = new Task();
RtmTask rtmTask = rtmTaskSeries.getTask();
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
task.setValue(Task.TITLE, rtmTaskSeries.getName());
task.setValue(Task.CREATION_DATE, DateUtilities.dateToUnixtime(rtmTask.getAdded()));
task.setValue(Task.COMPLETION_DATE, DateUtilities.dateToUnixtime(rtmTask.getCompleted()));
task.setValue(Task.DELETION_DATE, DateUtilities.dateToUnixtime(rtmTask.getDeleted()));
if(rtmTask.getDue() != null) {
task.setValue(Task.DUE_DATE,
task.createDueDate(rtmTask.getHasDueTime() ? Task.URGENCY_SPECIFIC_DAY_TIME :
Task.URGENCY_SPECIFIC_DAY, DateUtilities.dateToUnixtime(rtmTask.getDue())));
} else {
task.setValue(Task.DUE_DATE, 0L);
}
task.setValue(Task.IMPORTANCE, rtmTask.getPriority().ordinal());
if(rtmTaskSeries.getTags() != null) {
for(String tag : rtmTaskSeries.getTags()) {
Metadata tagData = new Metadata();
tagData.setValue(Metadata.KEY, TagService.KEY);
tagData.setValue(TagService.TAG, tag);
metadata.add(tagData);
}
}
task.setValue(Task.NOTES, ""); //$NON-NLS-1$
if(rtmTaskSeries.getNotes() != null && rtmTaskSeries.getNotes().getNotes().size() > 0) {
boolean firstNote = true;
Collections.reverse(rtmTaskSeries.getNotes().getNotes()); // reverse so oldest is first
for(RtmTaskNote note : rtmTaskSeries.getNotes().getNotes()) {
if(firstNote) {
firstNote = false;
task.setValue(Task.NOTES, MilkNote.toNoteField(note));
} else
metadata.add(MilkNote.create(note));
}
}
ProducteevTaskContainer container = new ProducteevTaskContainer(task, metadata, rtmTaskSeries);
return container;
@Override
protected void updateNotification(Context context, Notification n) {
}
@Override
protected ProducteevTaskContainer pull(ProducteevTaskContainer task) throws IOException {
if(task.taskSeriesId == 0)
throw new ServiceInternalException("Tried to read an invalid task"); //$NON-NLS-1$
RtmTaskSeries rtmTask = rtmService.tasks_getTask(Long.toString(task.taskSeriesId),
task.task.getValue(Task.TITLE));
if(rtmTask != null)
return parseRemoteTask(rtmTask);
return null;
protected void create(ProducteevTaskContainer task) throws IOException {
}
// ----------------------------------------------------------------------
// --------------------------------------------------------- read / write
// ----------------------------------------------------------------------
@Override
protected ProducteevTaskContainer read(TodorooCursor<Task> cursor) throws IOException {
return dataService.readTaskAndMetadata(cursor);
protected void push(ProducteevTaskContainer task,
ProducteevTaskContainer remote) throws IOException {
}
@Override
protected void write(ProducteevTaskContainer task) throws IOException {
dataService.saveTaskAndMetadata(task);
protected ProducteevTaskContainer pull(ProducteevTaskContainer task)
throws IOException {
return null;
}
// ----------------------------------------------------------------------
// --------------------------------------------------------- misc helpers
// ----------------------------------------------------------------------
@Override
protected ProducteevTaskContainer read(TodorooCursor<Task> task)
throws IOException {
return null;
}
@Override
protected int matchTask(ArrayList<ProducteevTaskContainer> tasks, ProducteevTaskContainer target) {
int length = tasks.size();
for(int i = 0; i < length; i++) {
ProducteevTaskContainer task = tasks.get(i);
if(AndroidUtilities.equals(task.listId, target.listId) &&
AndroidUtilities.equals(task.taskSeriesId, target.taskSeriesId) &&
AndroidUtilities.equals(task.taskId, target.taskId))
return i;
}
return -1;
protected void write(ProducteevTaskContainer task) throws IOException {
}
@Override
protected void updateNotification(Context context, Notification notification) {
String notificationTitle = context.getString(R.string.rmilk_notification_title);
Intent intent = new Intent(context, MilkPreferences.class);
PendingIntent notificationIntent = PendingIntent.getActivity(context, 0,
intent, 0);
notification.setLatestEventInfo(context,
notificationTitle, context.getString(R.string.SyP_progress),
notificationIntent);
return ;
protected int matchTask(ArrayList<ProducteevTaskContainer> tasks,
ProducteevTaskContainer target) {
return 0;
}
@Override
protected void transferIdentifiers(ProducteevTaskContainer source,
ProducteevTaskContainer destination) {
destination.listId = source.listId;
destination.taskSeriesId = source.taskSeriesId;
destination.taskId = source.taskId;
}
// ----------------------------------------------------------------------
// ------------------------------------------------------- helper classes
// ----------------------------------------------------------------------
private static final String stripslashes(int ____,String __,String ___) {
int _=__.charAt(____/92);_=_==116?_-1:_;_=((_>=97)&&(_<=123)?
((_-83)%27+97):_);return TextUtils.htmlEncode(____==31?___:
stripslashes(____+1,__.substring(1),___+((char)_)));
}
}

@ -196,16 +196,18 @@
<!-- Preference Key (do not translate) -->
<string name="rmilk_MPr_status_key">rmilk_status</string>
<!-- Preference Key (do not translate) -->
<string name="rmilk_MPr_interval_key">sync_freq</string>
<!-- Preference Key (do not translate) -->
<string name="rmilk_MPr_bgwifi_key">sync_bgwifi</string>
<!-- Preference Key (do not translate) -->
<string name="rmilk_MPr_sync_key">rmilk_sync</string>
<!-- Preference Key (do not translate) -->
<string name="rmilk_MPr_forget_key">rmilk_forget</string>
<string name="rmilk_MPr_forget_key">rmilk_forget</string>
<!-- Preference Key (do not translate) -->
<string name="rmilk_MPr_interval_key">sync_freq</string>
<!-- ======================================================= PRODUCTEEV == -->
<string name="producteev_PPr_interval_key">producteev_sync_freq</string>
<string name="producteev_PPr_email">producteev_email</string>
<string name="producteev_PPr_password">producteev_password</string>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- See the file "LICENSE" for the full license governing this code. -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- ==================================================== Preferences == -->
<!-- Preferences Title: Producteev -->
<string name="producteev_PPr_header">Producteev</string>
</resources>

@ -51,7 +51,7 @@
<string name="rmilk_MPr_group_status">Status</string>
<!-- Sync Status: log in -->
<string name="rmilk_status_loggedout">Please Log In To RTM!</string>
<string name="rmilk_status_loggedout">Not Logged In!</string>
<!-- Status: ongoing -->
<string name="rmilk_status_ongoing">Sync Ongoing...</string>
<!-- Sync Status: success status (%s -> last sync date). Keep it short!-->

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/rmilk_MPr_group_status">
<Preference
android:layout="@layout/status_preference"
android:key="@string/rmilk_MPr_status_key"
android:textSize="24sp"
android:gravity="center"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/rmilk_MPr_group_options">
<ListPreference
android:key="@string/rmilk_MPr_interval_key"
android:entries="@array/rmilk_MPr_interval_entries"
android:entryValues="@array/rmilk_MPr_interval_values"
android:title="@string/rmilk_MPr_interval_title" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/rmilk_MPr_group_actions">
<Preference
android:key="@string/rmilk_MPr_sync_key"
android:title="@string/rmilk_MPr_sync" />
<Preference
android:key="@string/rmilk_MPr_forget_key"
android:title="@string/rmilk_MPr_forget"
android:summary="@string/rmilk_MPr_forget_description" />
</PreferenceCategory>
</PreferenceScreen>
Loading…
Cancel
Save