Merge remote-tracking branch 'sbosley/110922_sb_list_view_iosify'

pull/14/head
Tim Su 13 years ago
commit f1d8fae6b2

@ -86,6 +86,10 @@ public class Update extends RemoteModel {
/** List of all properties for this model */
public static final Property<?>[] PROPERTIES = generateProperties(Update.class);
// --- constants
public static final String PICTURE_LOADING = "<loading>";
// --- defaults
/** Default values container */

@ -22,7 +22,7 @@
<classpathentry exported="true" kind="lib" path="libs/jackson-core-asl-1.6.7.jar"/>
<classpathentry exported="true" kind="lib" path="libs/google-api-client-googleapis-extensions-android2-1.4.1-beta.jar"/>
<classpathentry exported="true" kind="lib" path="libs/google-api-client-extensions-android2-1.4.1-beta.jar"/>
<classpathentry kind="src" path="facebook_src"/>
<classpathentry kind="src" path="astridApi_src"/>
<classpathentry kind="src" path="facebook_src"/>
<classpathentry kind="output" path="ecbuild"/>
</classpath>

@ -321,6 +321,12 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.todoroo.astrid.actfm.TagCreateActivity"
android:theme="@android:style/Theme.Dialog"/>
<activity android:name="com.todoroo.astrid.actfm.TagSettingsActivity"
android:windowSoftInputMode="stateHidden"/>
<activity android:name="com.todoroo.astrid.actfm.TagUpdatesActivity"
android:windowSoftInputMode="stateHidden"/>
<receiver android:name="com.todoroo.astrid.actfm.EditPeopleExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_ACTIONS" />
@ -365,7 +371,8 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity android:name="com.todoroo.astrid.gtasks.GtasksListAdder"/>
<activity android:name="com.todoroo.astrid.gtasks.GtasksListAdder"
android:theme="@android:style/Theme.Dialog"/>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />

@ -296,7 +296,7 @@ public class C2DMReceiver extends BroadcastReceiver {
}
FilterWithCustomIntent filter = (FilterWithCustomIntent)TagFilterExposer.filterFromTagData(context, tagData);
filter.customExtras.putString(TagViewActivity.EXTRA_START_TAB, "updates");
//filter.customExtras.putString(TagViewActivity.EXTRA_START_TAB, "updates");
if(intent.hasExtra("activity_id")) {
try {
Update update = new Update();

@ -0,0 +1,144 @@
package com.todoroo.astrid.actfm;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.widget.ArrayAdapter;
import com.timsu.astrid.R;
import com.todoroo.andlib.utility.DateUtilities;
public class ActFmCameraModule {
protected static final int REQUEST_CODE_CAMERA = 1;
protected static final int REQUEST_CODE_PICTURE = 2;
private static File lastTempFile = null;
public interface ClearImageCallback {
public void clearImage();
}
public static void showPictureLauncher(final Activity activity, final ClearImageCallback clearImageOption) {
ArrayList<String> options = new ArrayList<String>();
options.add(activity.getString(R.string.actfm_picture_camera));
options.add(activity.getString(R.string.actfm_picture_gallery));
if (clearImageOption != null) {
options.add(activity.getString(R.string.actfm_picture_clear));
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity,
android.R.layout.simple_spinner_dropdown_item, options.toArray(new String[options.size()]));
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@SuppressWarnings("nls")
@Override
public void onClick(DialogInterface d, int which) {
if(which == 0) {
lastTempFile = getTempFile(activity);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (lastTempFile != null) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(lastTempFile));
}
activity.startActivityForResult(intent, REQUEST_CODE_CAMERA);
} else if (which == 1) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
activity.startActivityForResult(Intent.createChooser(intent,
activity.getString(R.string.actfm_TVA_tag_picture)), REQUEST_CODE_PICTURE);
} else {
if (clearImageOption != null)
clearImageOption.clearImage();
}
}
};
// show a menu of available options
new AlertDialog.Builder(activity)
.setAdapter(adapter, listener)
.show().setOwnerActivity(activity);
}
@SuppressWarnings("nls")
private static File getTempFile(Activity activity) {
try {
String storageState = Environment.getExternalStorageState();
if(storageState.equals(Environment.MEDIA_MOUNTED)) {
String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + activity.getPackageName() + "/files/";
File photoFile = File.createTempFile("comment_pic_" + DateUtilities.now(), ".jpg", new File(path));
return photoFile;
}
} catch (IOException e) {
return null;
}
return null;
}
public interface CameraResultCallback {
public void handleCameraResult(Bitmap bitmap);
}
private static Bitmap bitmapFromUri(Activity activity, Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = activity.managedQuery(uri, projection, null, null, null);
String path;
if(cursor != null) {
try {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
} finally {
cursor.close();
}
} else {
path = uri.getPath();
}
return BitmapFactory.decodeFile(path);
}
public static boolean activityResult(Activity activity, int requestCode, int resultCode, Intent data,
CameraResultCallback cameraResult) {
if(requestCode == ActFmCameraModule.REQUEST_CODE_CAMERA && resultCode == Activity.RESULT_OK) {
Bitmap bitmap;
if (data == null) { // large from camera
if (lastTempFile != null) {
bitmap = bitmapFromUri(activity, Uri.fromFile(lastTempFile));
lastTempFile.deleteOnExit();
lastTempFile = null;
}
else
bitmap = null;
} else
bitmap = data.getParcelableExtra("data"); //$NON-NLS-1$
if(bitmap != null) {
activity.setResult(Activity.RESULT_OK);
cameraResult.handleCameraResult(bitmap);
}
return true;
} else if(requestCode == ActFmCameraModule.REQUEST_CODE_PICTURE && resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
Bitmap bitmap = bitmapFromUri(activity, uri);
if(bitmap != null) {
activity.setResult(Activity.RESULT_OK);
cameraResult.handleCameraResult(bitmap);
}
return true;
}
return false;
}
}

@ -0,0 +1,295 @@
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.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.service.ThemeService;
import com.todoroo.astrid.tags.TagFilterExposer;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.ui.PeopleContainer;
import com.todoroo.astrid.utility.Flags;
import com.todoroo.astrid.welcome.HelpInfoPopover;
public class TagSettingsActivity extends Activity {
protected static final int REQUEST_ACTFM_LOGIN = 3;
private static final String MEMBERS_IN_PROGRESS = "members"; //$NON-NLS-1$
private TagData tagData;
@Autowired TagDataService tagDataService;
@Autowired ActFmSyncService actFmSyncService;
@Autowired ActFmPreferenceService actFmPreferenceService;
private PeopleContainer tagMembers;
private AsyncImageView picture;
private EditText tagName;
private CheckBox isSilent;
boolean isNewTag = false;
public TagSettingsActivity() {
DependencyInjectionService.getInstance().inject(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
ThemeService.applyTheme(this);
setContentView(R.layout.tag_settings_activity);
tagData = getIntent().getParcelableExtra(TagViewActivity.EXTRA_TAG_DATA);
if (tagData == null) {
isNewTag = true;
tagData = new TagData();
}
setUpSettingsPage();
if(savedInstanceState != null && savedInstanceState.containsKey(MEMBERS_IN_PROGRESS)) {
final String members = savedInstanceState.getString(MEMBERS_IN_PROGRESS);
new Thread(new Runnable() {
@Override
public void run() {
AndroidUtilities.sleepDeep(500);
runOnUiThread(new Runnable() {
@Override
public void run() {
updateMembers(members);
}
});
}
}).start();
}
showCollaboratorsPopover();
}
private void showCollaboratorsPopover() {
if (!Preferences.getBoolean(R.string.p_showed_collaborators_help, false)) {
View members = findViewById(R.id.members_container);
HelpInfoPopover.showPopover(this, members, R.string.help_popover_collaborators);
Preferences.setBoolean(R.string.p_showed_collaborators_help, true);
}
}
protected void setUpSettingsPage() {
tagMembers = (PeopleContainer) findViewById(R.id.members_container);
tagName = (EditText) findViewById(R.id.tag_name);
picture = (AsyncImageView) findViewById(R.id.picture);
isSilent = (CheckBox) findViewById(R.id.tag_silenced);
if(actFmPreferenceService.isLoggedIn()) {
picture.setVisibility(View.VISIBLE);
findViewById(R.id.listSettingsMore).setVisibility(View.VISIBLE);
}
picture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
ActFmCameraModule.showPictureLauncher(TagSettingsActivity.this, null);
}
});
findViewById(R.id.saveMembers).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
saveSettings();
}
});
refreshSettingsPage();
}
private void saveSettings() {
setResult(RESULT_OK);
String oldName = tagData.getValue(TagData.NAME);
String newName = tagName.getText().toString();
if (TextUtils.isEmpty(newName)) {
return;
}
boolean nameChanged = !oldName.equals(newName);
TagService service = TagService.getInstance();
if (nameChanged) {
if (oldName.equalsIgnoreCase(newName)) { // Change the capitalization of a list manually
tagData.setValue(TagData.NAME, newName);
service.renameCaseSensitive(oldName, newName);
tagData.setFlag(TagData.FLAGS, TagData.FLAG_EMERGENT, false);
} else { // Rename list--check for existing name
newName = service.getTagWithCase(newName);
tagName.setText(newName);
if (!newName.equals(oldName)) {
tagData.setValue(TagData.NAME, newName);
service.rename(oldName, newName);
tagData.setFlag(TagData.FLAGS, TagData.FLAG_EMERGENT, false);
} else {
nameChanged = false;
}
}
}
if(newName.length() > 0 && oldName.length() == 0) {
tagDataService.save(tagData);
//setUpNewTag(newName);
}
JSONArray members = tagMembers.toJSONArray();
if(members.length() > 0 && !actFmPreferenceService.isLoggedIn()) {
startActivityForResult(new Intent(this, ActFmLoginActivity.class),
REQUEST_ACTFM_LOGIN);
return;
}
int oldMemberCount = tagData.getValue(TagData.MEMBER_COUNT);
if (members.length() > oldMemberCount) {
StatisticsService.reportEvent(StatisticsConstants.ACTFM_LIST_SHARED);
}
tagData.setValue(TagData.MEMBERS, members.toString());
tagData.setValue(TagData.MEMBER_COUNT, members.length());
tagData.setFlag(TagData.FLAGS, TagData.FLAG_SILENT, isSilent.isChecked());
if(actFmPreferenceService.isLoggedIn())
Flags.set(Flags.TOAST_ON_SAVE);
else
Toast.makeText(this, R.string.tag_list_saved, Toast.LENGTH_LONG).show();
tagDataService.save(tagData);
if (isNewTag) {
Intent intent = new Intent(this, TagViewActivity.class);
intent.putExtra(TagViewActivity.EXTRA_TAG_NAME, newName);
intent.putExtra(TagViewActivity.TOKEN_FILTER, TagFilterExposer.filterFromTagData(this, tagData));
finish();
startActivity(intent);
return;
}
refreshSettingsPage();
}
@SuppressWarnings("nls")
private void refreshSettingsPage() {
tagName.setText(tagData.getValue(TagData.NAME));
if (isNewTag) {
((TextView)findViewById(R.id.listLabel)).setText(getString(R.string.tag_new_list));
} else {
((TextView) findViewById(R.id.listLabel)).setText(this.getString(R.string.tag_settings_title, tagData.getValue(TagData.NAME)));
}
picture.setUrl(tagData.getValue(TagData.PICTURE));
setTitle(tagData.getValue(TagData.NAME));
TextView ownerLabel = (TextView) findViewById(R.id.tag_owner);
try {
if(tagData.getFlag(TagData.FLAGS, TagData.FLAG_EMERGENT)) {
ownerLabel.setText(String.format("<%s>", getString(R.string.actfm_TVA_tag_owner_none)));
} else if(tagData.getValue(TagData.USER_ID) == 0) {
ownerLabel.setText(Preferences.getStringValue(ActFmPreferenceService.PREF_NAME));
} else {
JSONObject owner = new JSONObject(tagData.getValue(TagData.USER));
ownerLabel.setText(owner.getString("name"));
}
} catch (JSONException e) {
Log.e("tag-view-activity", "json error refresh owner", e);
ownerLabel.setText("<error>");
System.err.println(tagData.getValue(TagData.USER));
}
String peopleJson = tagData.getValue(TagData.MEMBERS);
updateMembers(peopleJson);
}
@SuppressWarnings("nls")
private void updateMembers(String peopleJson) {
tagMembers.removeAllViews();
if(!TextUtils.isEmpty(peopleJson)) {
try {
JSONArray people = new JSONArray(peopleJson);
tagMembers.fromJSONArray(people);
} catch (JSONException e) {
System.err.println(peopleJson);
Log.e("tag-view-activity", "json error refresh members", e);
}
}
tagMembers.addPerson(""); //$NON-NLS-1$
}
private void uploadTagPicture(final Bitmap bitmap) {
new Thread(new Runnable() {
@Override
public void run() {
try {
String url = actFmSyncService.setTagPicture(tagData.getValue(TagData.REMOTE_ID), bitmap);
tagData.setValue(TagData.PICTURE, url);
Flags.set(Flags.ACTFM_SUPPRESS_SYNC);
tagDataService.save(tagData);
} catch (IOException e) {
DialogUtilities.okDialog(TagSettingsActivity.this, e.toString(), null);
}
}
}).start();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(tagMembers.getChildCount() > 1) {
JSONArray members = tagMembers.toJSONArray();
outState.putString(MEMBERS_IN_PROGRESS, members.toString());
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
CameraResultCallback callback = new CameraResultCallback() {
@Override
public void handleCameraResult(Bitmap bitmap) {
picture.setImageBitmap(bitmap);
uploadTagPicture(bitmap);
}
};
if (ActFmCameraModule.activityResult(this, requestCode, resultCode, data, callback)) {
// Handled
} else if(requestCode == REQUEST_ACTFM_LOGIN && resultCode == Activity.RESULT_OK) {
saveSettings();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}

@ -0,0 +1,272 @@
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;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
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;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.adapter.UpdateAdapter;
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.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.service.ThemeService;
import com.todoroo.astrid.utility.Flags;
public class TagUpdatesActivity extends ListActivity {
private TagData tagData;
private UpdateAdapter updateAdapter;
private EditText addCommentField;
private ImageButton pictureButton;
private Bitmap picture = null;
private static final int MENU_REFRESH_ID = Menu.FIRST;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired TagDataService tagDataService;
@Autowired UpdateDao updateDao;
@Autowired ActFmSyncService actFmSyncService;
public TagUpdatesActivity() {
DependencyInjectionService.getInstance().inject(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
ThemeService.applyTheme(this);
setContentView(R.layout.tag_updates_activity);
tagData = getIntent().getParcelableExtra(TagViewActivity.EXTRA_TAG_DATA);
OnTouchListener onTouch = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
v.requestFocusFromTouch();
return false;
}
};
addCommentField = (EditText) findViewById(R.id.commentField);
addCommentField.setOnTouchListener(onTouch);
setUpUpdateList();
}
protected void setUpUpdateList() {
((TextView) findViewById(R.id.listLabel)).setText(this.getString(R.string.tag_updates_title, tagData.getValue(TagData.NAME)));
final ImageButton commentButton = (ImageButton) findViewById(R.id.commentButton);
addCommentField = (EditText) findViewById(R.id.commentField);
addCommentField.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if(actionId == EditorInfo.IME_NULL && addCommentField.getText().length() > 0) {
addComment();
return true;
}
return false;
}
});
addCommentField.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
commentButton.setVisibility((s.length() > 0) ? View.VISIBLE : View.GONE);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//
}
});
commentButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addComment();
}
});
final ClearImageCallback clearImage = new ClearImageCallback() {
@Override
public void clearImage() {
picture = null;
pictureButton.setImageResource(R.drawable.icn_camera);
}
};
pictureButton = (ImageButton) findViewById(R.id.picture);
pictureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (picture != null)
ActFmCameraModule.showPictureLauncher(TagUpdatesActivity.this, clearImage);
else
ActFmCameraModule.showPictureLauncher(TagUpdatesActivity.this, null);
}
});
refreshUpdatesList();
}
private void refreshUpdatesList() {
if(!actFmPreferenceService.isLoggedIn() || tagData.getValue(Task.REMOTE_ID) <= 0)
return;
if(updateAdapter == null) {
TodorooCursor<Update> currentCursor = tagDataService.getUpdates(tagData);
startManagingCursor(currentCursor);
updateAdapter = new UpdateAdapter(this, R.layout.update_adapter_row,
currentCursor, false, null);
((ListView)findViewById(android.R.id.list)).setAdapter(updateAdapter);
} else {
Cursor cursor = updateAdapter.getCursor();
cursor.requery();
startManagingCursor(cursor);
}
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if(menu.size() > 0)
return true;
MenuItem item;
if(actFmPreferenceService.isLoggedIn()) {
item = menu.add(Menu.NONE, MENU_REFRESH_ID, Menu.NONE,
R.string.ENA_refresh_comments);
item.setIcon(R.drawable.ic_menu_refresh);
}
return true;
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
// handle my own menus
switch (item.getItemId()) {
case MENU_REFRESH_ID: {
final ProgressDialog progressDialog = DialogUtilities.progressDialog(this, getString(R.string.DLG_please_wait));
actFmSyncService.fetchUpdatesForTag(tagData, true, new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
refreshUpdatesList();
DialogUtilities.dismissDialog(TagUpdatesActivity.this, progressDialog);
}
});
}
});
return true;
}
default: return false;
}
}
@SuppressWarnings("nls")
private void addComment() {
if(tagData.getValue(TagData.REMOTE_ID) == 0L)
return;
Update update = new Update();
update.setValue(Update.MESSAGE, addCommentField.getText().toString());
update.setValue(Update.ACTION_CODE, "tag_comment");
update.setValue(Update.USER_ID, 0L);
update.setValue(Update.TAGS, "," + tagData.getValue(TagData.REMOTE_ID) + ",");
update.setValue(Update.CREATION_DATE, DateUtilities.now());
if (picture != null) {
update.setValue(Update.PICTURE, Update.PICTURE_LOADING);
}
Flags.set(Flags.ACTFM_SUPPRESS_SYNC);
updateDao.createNew(update);
final long updateId = update.getId();
new Thread() {
@Override
public void run() {
actFmSyncService.pushUpdate(updateId, picture);
}
}.start();
addCommentField.setText(""); //$NON-NLS-1$
pictureButton.setImageResource(R.drawable.icn_camera);
refreshUpdatesList();
StatisticsService.reportEvent(StatisticsConstants.ACTFM_TAG_COMMENT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
CameraResultCallback callback = new CameraResultCallback() {
@Override
public void handleCameraResult(Bitmap bitmap) {
picture = bitmap;
pictureButton.setImageBitmap(picture);
}
};
if (ActFmCameraModule.activityResult(this, requestCode, resultCode, data, callback)) {
//Handled
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
protected void onStop() {
StatisticsService.sessionStop(this);
super.onStop();
}
@Override
protected void onResume() {
super.onResume();
StatisticsService.sessionStart(this);
}
@Override
protected void onPause() {
super.onPause();
StatisticsService.sessionPause();
}
}

@ -8,25 +8,15 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -34,18 +24,10 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabWidget;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
@ -55,33 +37,25 @@ import com.todoroo.andlib.service.NotificationManager;
import com.todoroo.andlib.service.NotificationManager.AndroidNotificationManager;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
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;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.adapter.UpdateAdapter;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
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.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
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.ui.PeopleContainer;
import com.todoroo.astrid.utility.Flags;
import com.todoroo.astrid.welcome.HelpInfoPopover;
public class TagViewActivity extends TaskListActivity implements OnTabChangeListener {
public class TagViewActivity extends TaskListActivity {
private static final String LAST_FETCH_KEY = "tag-fetch-"; //$NON-NLS-1$
@ -89,17 +63,12 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
public static final String EXTRA_TAG_NAME = "tag"; //$NON-NLS-1$
public static final String EXTRA_TAG_REMOTE_ID = "remoteId"; //$NON-NLS-1$
public static final String EXTRA_START_TAB = "tab"; //$NON-NLS-1$
public static final String EXTRA_NEW_TAG = "new"; //$NON-NLS-1$
protected static final int MENU_REFRESH_ID = MENU_SYNC_ID;
public static final String EXTRA_TAG_DATA = "tagData"; //$NON-NLS-1$
protected static final int REQUEST_CODE_CAMERA = 1;
protected static final int REQUEST_CODE_PICTURE = 2;
protected static final int REQUEST_ACTFM_LOGIN = 3;
protected static final int MENU_REFRESH_ID = MENU_SYNC_ID;
private static final String MEMBERS_IN_PROGRESS = "members"; //$NON-NLS-1$
private static final String TAB_IN_PROGRESS = "tab"; //$NON-NLS-1$
private static final int REQUEST_CODE_SETTINGS = 0;
private TagData tagData;
@ -109,24 +78,16 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired UpdateDao updateDao;
private UpdateAdapter updateAdapter;
private PeopleContainer tagMembers;
private EditText addCommentField;
private AsyncImageView picture;
private EditText tagName;
private View taskListView;
private CheckBox isSilent;
private TabHost tabHost;
private TabWidget tabWidget;
private String[] tabLabels;
private boolean dataLoaded = false;
private boolean updatesTabAdded = false;
private long currentId;
private JSONObject currentMember;
private Filter originalFilter;
//private ImageAdapter galleryAdapter;
// --- UI initialization
@ -145,113 +106,69 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
}
};
((EditText) findViewById(R.id.quickAddText)).setOnTouchListener(onTouch);
((EditText) findViewById(R.id.commentField)).setOnTouchListener(onTouch);
if(getIntent().hasExtra(EXTRA_START_TAB))
tabHost.setCurrentTabByTag(getIntent().getStringExtra(EXTRA_START_TAB));
View settingsContainer = findViewById(R.id.settingsContainer);
settingsContainer.setVisibility(View.VISIBLE);
View settingsButton = findViewById(R.id.settings);
settingsButton.setOnClickListener(settingsListener);
View membersEdit = findViewById(R.id.members_edit);
membersEdit.setOnClickListener(settingsListener);
if(savedInstanceState != null && savedInstanceState.containsKey(MEMBERS_IN_PROGRESS)) {
final String members = savedInstanceState.getString(MEMBERS_IN_PROGRESS);
new Thread(new Runnable() {
findViewById(R.id.listLabel).setPadding(0, 0, 0, 0);
if (actFmPreferenceService.isLoggedIn()) {
View activityContainer = findViewById(R.id.activityContainer);
activityContainer.setVisibility(View.VISIBLE);
ImageView activity = (ImageView) findViewById(R.id.activity);
activity.setOnClickListener(new View.OnClickListener() {
@Override
public void run() {
AndroidUtilities.sleepDeep(500);
runOnUiThread(new Runnable() {
@Override
public void run() {
updateMembers(members);
}
});
public void onClick(View v) {
Intent intent = new Intent(TagViewActivity.this, TagUpdatesActivity.class);
intent.putExtra(EXTRA_TAG_DATA, tagData);
startActivity(intent);
}
}).start();
}
if(savedInstanceState != null && savedInstanceState.containsKey(TAB_IN_PROGRESS)) {
tabHost.setCurrentTab(savedInstanceState.getInt(TAB_IN_PROGRESS));
});
}
onNewIntent(getIntent());
originalFilter = filter;
showListSettingsPopover();
}
private final OnClickListener settingsListener = new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(TagViewActivity.this, TagSettingsActivity.class);
intent.putExtra(EXTRA_TAG_DATA, tagData);
startActivityForResult(intent, REQUEST_CODE_SETTINGS);
}
};
/* (non-Javadoc)
* @see com.todoroo.astrid.activity.TaskListActivity#getListBody(android.view.ViewGroup)
*/
@SuppressWarnings("nls")
@Override
protected View getListBody(ViewGroup root) {
ViewGroup parent = (ViewGroup) getLayoutInflater().inflate(R.layout.task_list_body_tag, root, false);
ViewGroup tabContent = (ViewGroup) parent.findViewById(android.R.id.tabcontent);
tabLabels = getResources().getStringArray(R.array.TVA_tabs);
tabHost = (TabHost) parent.findViewById(android.R.id.tabhost);
tabWidget = (TabWidget) parent.findViewById(android.R.id.tabs);
tabHost.setup();
ViewGroup parent = (ViewGroup) getLayoutInflater().inflate(R.layout.task_list_body_tag_v2, root, false);
taskListView = super.getListBody(parent);
if(actFmPreferenceService.isLoggedIn())
((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.DLG_loading);
tabContent.addView(taskListView);
addTab(taskListView.getId(), "tasks", tabLabels[0]);
tabHost.setOnTabChangedListener(this);
parent.addView(taskListView);
return parent;
}
private void addTab(int contentId, String id, String label) {
TabHost.TabSpec spec = tabHost.newTabSpec(id);
spec.setContent(contentId);
TextView textIndicator = (TextView) getLayoutInflater().inflate(R.layout.gd_tab_indicator, tabWidget, false);
textIndicator.setText(label);
spec.setIndicator(textIndicator);
tabHost.addTab(spec);
}
private void showListTabPopover() {
private void showListSettingsPopover() {
if (!Preferences.getBoolean(R.string.p_showed_list_settings_help, false)) {
View tabView = tabWidget.getChildTabViewAt(tabWidget.getTabCount() - 1);
View tabView = findViewById(R.id.settings);
HelpInfoPopover.showPopover(this, tabView, R.string.help_popover_list_settings);
Preferences.setBoolean(R.string.p_showed_list_settings_help, true);
}
}
private void showCollaboratorsPopover() {
if (!Preferences.getBoolean(R.string.p_showed_collaborators_help, false)) {
View members = findViewById(R.id.members_container);
HelpInfoPopover.showPopover(this, members, R.string.help_popover_collaborators);
Preferences.setBoolean(R.string.p_showed_collaborators_help, true);
}
}
@SuppressWarnings("nls")
@Override
public void onTabChanged(String tabId) {
if(tabId.equals("tasks"))
findViewById(R.id.taskListFooter).setVisibility(View.VISIBLE);
else
findViewById(R.id.taskListFooter).setVisibility(View.GONE);
if(tabId.equals("updates"))
findViewById(R.id.updatesFooter).setVisibility(View.VISIBLE);
else
findViewById(R.id.updatesFooter).setVisibility(View.GONE);
if(tabId.equals("settings"))
findViewById(R.id.membersFooter).setVisibility(View.VISIBLE);
else
findViewById(R.id.membersFooter).setVisibility(View.GONE);
showPopovers();
}
@SuppressWarnings("nls")
private void showPopovers() {
if(tabHost.getCurrentTabTag().equals("settings"))
showCollaboratorsPopover();
else
showListTabPopover();
}
/**
* Create options menu (displayed when user presses menu key)
*
@ -289,97 +206,6 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
return true;
}
protected void setUpSettingsPage() {
addTab(R.id.tab_settings, "settings", tabLabels[2]); //$NON-NLS-1$
tagMembers = (PeopleContainer) findViewById(R.id.members_container);
tagName = (EditText) findViewById(R.id.tag_name);
picture = (AsyncImageView) findViewById(R.id.picture);
isSilent = (CheckBox) findViewById(R.id.tag_silenced);
if(actFmPreferenceService.isLoggedIn()) {
picture.setVisibility(View.VISIBLE);
findViewById(R.id.listSettingsMore).setVisibility(View.VISIBLE);
}
picture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(TagViewActivity.this,
android.R.layout.simple_spinner_dropdown_item, new String[] {
getString(R.string.actfm_picture_camera),
getString(R.string.actfm_picture_gallery),
});
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@SuppressWarnings("nls")
@Override
public void onClick(DialogInterface d, int which) {
if(which == 0) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CODE_CAMERA);
} else {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent,
getString(R.string.actfm_TVA_tag_picture)), REQUEST_CODE_PICTURE);
}
}
};
// show a menu of available options
new AlertDialog.Builder(TagViewActivity.this)
.setAdapter(adapter, listener)
.show().setOwnerActivity(TagViewActivity.this);
}
});
findViewById(R.id.saveMembers).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
saveSettings();
}
});
refreshSettingsPage();
}
protected void setUpUpdateList() {
final ImageButton quickAddButton = (ImageButton) findViewById(R.id.commentButton);
addCommentField = (EditText) findViewById(R.id.commentField);
addCommentField.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if(actionId == EditorInfo.IME_NULL && addCommentField.getText().length() > 0) {
addComment();
return true;
}
return false;
}
});
addCommentField.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
quickAddButton.setVisibility((s.length() > 0) ? View.VISIBLE : View.GONE);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//
}
});
quickAddButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
addComment();
}
});
refreshUpdatesList();
}
// --- data loading
@Override
@ -392,14 +218,10 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
String tag = getIntent().getStringExtra(EXTRA_TAG_NAME);
long remoteId = getIntent().getLongExtra(EXTRA_TAG_REMOTE_ID, 0);
boolean newTag = getIntent().getBooleanExtra(EXTRA_NEW_TAG, false);
if(tag == null && remoteId == 0 && !newTag)
if(tag == null && remoteId == 0)
return;
if(newTag)
getIntent().putExtra(TOKEN_FILTER, Filter.emptyFilter(getString(R.string.tag_new_list)));
TodorooCursor<TagData> cursor = tagDataService.query(Query.select(TagData.PROPERTIES).where(Criterion.or(TagData.NAME.eqCaseInsensitive(tag),
Criterion.and(TagData.REMOTE_ID.gt(0), TagData.REMOTE_ID.eq(remoteId)))));
try {
@ -425,32 +247,9 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
}
}
super.onNewIntent(intent);
setUpUpdateList();
setUpSettingsPage();
}
private void refreshUpdatesList() {
if(!actFmPreferenceService.isLoggedIn() || tagData.getValue(Task.REMOTE_ID) <= 0)
return;
setUpMembersGallery();
if(!updatesTabAdded ) {
updatesTabAdded = true;
addTab(R.id.tab_updates, "updates", tabLabels[1]); //$NON-NLS-1$
}
if(updateAdapter == null) {
TodorooCursor<Update> currentCursor = tagDataService.getUpdates(tagData);
startManagingCursor(currentCursor);
updateAdapter = new UpdateAdapter(this, R.layout.update_adapter_row,
currentCursor, false, null);
((ListView)findViewById(R.id.tab_updates)).setAdapter(updateAdapter);
} else {
Cursor cursor = updateAdapter.getCursor();
cursor.requery();
startManagingCursor(cursor);
}
super.onNewIntent(intent);
}
@Override
@ -465,48 +264,6 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
}
}
@SuppressWarnings("nls")
private void refreshSettingsPage() {
tagName.setText(tagData.getValue(TagData.NAME));
picture.setUrl(tagData.getValue(TagData.PICTURE));
setTitle(getString(R.string.tag_FEx_name, tagData.getValue(TagData.NAME)));
TextView ownerLabel = (TextView) findViewById(R.id.tag_owner);
try {
if(tagData.getFlag(TagData.FLAGS, TagData.FLAG_EMERGENT)) {
ownerLabel.setText(String.format("<%s>", getString(R.string.actfm_TVA_tag_owner_none)));
} else if(tagData.getValue(TagData.USER_ID) == 0) {
ownerLabel.setText(Preferences.getStringValue(ActFmPreferenceService.PREF_NAME));
} else {
JSONObject owner = new JSONObject(tagData.getValue(TagData.USER));
ownerLabel.setText(owner.getString("name"));
}
} catch (JSONException e) {
Log.e("tag-view-activity", "json error refresh owner", e);
ownerLabel.setText("<error>");
System.err.println(tagData.getValue(TagData.USER));
}
String peopleJson = tagData.getValue(TagData.MEMBERS);
updateMembers(peopleJson);
}
@SuppressWarnings("nls")
private void updateMembers(String peopleJson) {
tagMembers.removeAllViews();
if(!TextUtils.isEmpty(peopleJson)) {
try {
JSONArray people = new JSONArray(peopleJson);
tagMembers.fromJSONArray(people);
} catch (JSONException e) {
System.err.println(peopleJson);
Log.e("tag-view-activity", "json error refresh members", e);
}
}
tagMembers.addPerson(""); //$NON-NLS-1$
}
// --------------------------------------------------------- refresh data
/** refresh the list with latest data from the web */
@ -533,7 +290,6 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
public void run() {
if(noRemoteId && tagData.getValue(TagData.REMOTE_ID) > 0)
refreshData(manual, true);
refreshSettingsPage();
}
});
@ -555,6 +311,7 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
if(noRemoteId)
return;
setUpMembersGallery();
actFmSyncService.fetchTasksForTag(tagData, manual, new Runnable() {
@Override
public void run() {
@ -575,12 +332,137 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
runOnUiThread(new Runnable() {
@Override
public void run() {
refreshUpdatesList();
//refreshUpdatesList();
DialogUtilities.dismissDialog(TagViewActivity.this, progressDialog);
}
});
}
});
}
private void setUpMembersGallery() {
LinearLayout membersView = (LinearLayout)findViewById(R.id.shared_with);
membersView.setOnClickListener(settingsListener);
try {
String membersString = tagData.getValue(TagData.MEMBERS);
JSONArray members = new JSONArray(membersString);
if (members.length() > 0) {
membersView.setOnClickListener(null);
membersView.removeAllViews();
for (int i = 0; i < members.length(); i++) {
JSONObject member = members.getJSONObject(i);
addImageForMember(membersView, member);
}
// Handle creator
if(tagData.getValue(TagData.USER_ID) != 0) {
JSONObject owner = new JSONObject(tagData.getValue(TagData.USER));
addImageForMember(membersView, owner);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
findViewById(R.id.filter_assigned).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
resetAssignedFilter();
}
});
}
@SuppressWarnings("nls")
private void addImageForMember(LinearLayout membersView, JSONObject member) {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
AsyncImageView image = new AsyncImageView(this);
image.setLayoutParams(new LinearLayout.LayoutParams((int)(50 * displayMetrics.density),
(int)(50 * displayMetrics.density)));
image.setDefaultImageResource(R.drawable.ic_contact_picture_2);
image.setScaleType(ImageView.ScaleType.FIT_XY);
try {
final long id = member.getLong("id");
if (id == ActFmPreferenceService.userId())
member = ActFmPreferenceService.thisUser();
final JSONObject memberToUse = member;
final String memberName = displayName(memberToUse);
if (memberToUse.has("picture")) {
image.setUrl(memberToUse.getString("picture"));
}
image.setOnClickListener(listenerForImage(memberToUse, id, memberName));
} catch (JSONException e) {
System.err.println("Unable to create listener");
e.printStackTrace();
}
membersView.addView(image);
}
private OnClickListener listenerForImage(final JSONObject member, final long id, final String displayName) {
return new OnClickListener() {
@Override
public void onClick(View v) {
if (currentId == id) {
// Back to all
resetAssignedFilter();
} else {
// New filter
currentId = id;
currentMember = member;
Criterion assigned = Criterion.and(TaskCriteria.activeAndVisible(), Task.USER_ID.eq(id));
filter = TagFilterExposer.filterFromTag(TagViewActivity.this, new Tag(tagData), assigned);
TextView filterByAssigned = (TextView) findViewById(R.id.filter_assigned);
filterByAssigned.setVisibility(View.VISIBLE);
filterByAssigned.setText(getString(R.string.actfm_TVA_filtered_by_assign, displayName));
setUpTaskList();
}
}
};
}
@Override
protected Intent getOnClickQuickAddIntent(Task t) {
Intent intent = super.getOnClickQuickAddIntent(t);
// Customize extras
return intent;
}
@Override
protected Intent getOnLongClickQuickAddIntent(Task t) {
Intent intent = super.getOnClickQuickAddIntent(t);
// Customize extras
return intent;
}
private void resetAssignedFilter() {
currentId = -1;
currentMember = null;
filter = originalFilter;
findViewById(R.id.filter_assigned).setVisibility(View.GONE);
setUpTaskList();
}
@SuppressWarnings("nls")
private String displayName(JSONObject user) {
String name = user.optString("name");
if (!TextUtils.isEmpty(name) && !"null".equals(name)) {
name = name.trim();
int index = name.indexOf(' ');
if (index > 0) {
return name.substring(0, index);
} else {
return name;
}
} else {
String email = user.optString("email");
email = email.trim();
int index = email.indexOf('@');
if (index > 0) {
return email.substring(0, index);
} else {
return email;
}
}
}
// --- receivers
@ -597,7 +479,7 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
runOnUiThread(new Runnable() {
@Override
public void run() {
refreshUpdatesList();
//refreshUpdatesList();
}
});
refreshData(false, true);
@ -622,79 +504,6 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
unregisterReceiver(notifyReceiver);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(tagMembers.getChildCount() > 1) {
JSONArray members = tagMembers.toJSONArray();
outState.putString(MEMBERS_IN_PROGRESS, members.toString());
}
outState.putInt(TAB_IN_PROGRESS, tabHost.getCurrentTab());
}
// --- events
private void saveSettings() {
String oldName = tagData.getValue(TagData.NAME);
String newName = tagName.getText().toString();
boolean nameChanged = !oldName.equals(newName);
TagService service = TagService.getInstance();
if (nameChanged) {
if (oldName.equalsIgnoreCase(newName)) { // Change the capitalization of a list manually
tagData.setValue(TagData.NAME, newName);
service.renameCaseSensitive(oldName, newName);
tagData.setFlag(TagData.FLAGS, TagData.FLAG_EMERGENT, false);
} else { // Rename list--check for existing name
newName = service.getTagWithCase(newName);
tagName.setText(newName);
if (!newName.equals(oldName)) {
tagData.setValue(TagData.NAME, newName);
service.rename(oldName, newName);
tagData.setFlag(TagData.FLAGS, TagData.FLAG_EMERGENT, false);
} else {
nameChanged = false;
}
}
}
if(newName.length() > 0 && oldName.length() == 0) {
tagDataService.save(tagData);
setUpNewTag(newName);
}
JSONArray members = tagMembers.toJSONArray();
if(members.length() > 0 && !actFmPreferenceService.isLoggedIn()) {
startActivityForResult(new Intent(this, ActFmLoginActivity.class),
REQUEST_ACTFM_LOGIN);
return;
}
int oldMemberCount = tagData.getValue(TagData.MEMBER_COUNT);
if (members.length() > oldMemberCount) {
StatisticsService.reportEvent(StatisticsConstants.ACTFM_LIST_SHARED);
}
tagData.setValue(TagData.MEMBERS, members.toString());
tagData.setValue(TagData.MEMBER_COUNT, members.length());
tagData.setFlag(TagData.FLAGS, TagData.FLAG_SILENT, isSilent.isChecked());
if(actFmPreferenceService.isLoggedIn())
Flags.set(Flags.TOAST_ON_SAVE);
else
Toast.makeText(this, R.string.tag_list_saved, Toast.LENGTH_LONG).show();
tagDataService.save(tagData);
if (nameChanged) {
filter = TagFilterExposer.filterFromTagData(this, tagData);
taskAdapter = null;
loadTaskListContent(true);
}
refreshSettingsPage();
}
@Override
protected Task quickAddTask(String title, boolean selectNewTask) {
if(tagData.getValue(TagData.NAME).length() == 0) {
@ -704,89 +513,18 @@ public class TagViewActivity extends TaskListActivity implements OnTabChangeList
return super.quickAddTask(title, selectNewTask);
}
private void setUpNewTag(String name) {
filter = TagFilterExposer.filterFromTag(this, new Tag(name, 0, 0),
TaskCriteria.activeAndVisible());
getIntent().putExtra(TOKEN_FILTER, filter);
super.onNewIntent(getIntent());
}
@SuppressWarnings("nls")
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_CODE_CAMERA && resultCode == RESULT_OK) {
Bitmap bitmap = data.getParcelableExtra("data");
if(bitmap != null) {
picture.setImageBitmap(bitmap);
uploadTagPicture(bitmap);
}
} else if(requestCode == REQUEST_CODE_PICTURE && resultCode == RESULT_OK) {
Uri uri = data.getData();
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
String path;
if(cursor != null) {
try {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
} finally {
cursor.close();
}
} else {
path = uri.getPath();
}
Bitmap bitmap = BitmapFactory.decodeFile(path);
if(bitmap != null) {
picture.setImageBitmap(bitmap);
uploadTagPicture(bitmap);
}
} else if(requestCode == REQUEST_ACTFM_LOGIN && resultCode == Activity.RESULT_OK) {
saveSettings();
if (requestCode == REQUEST_CODE_SETTINGS && resultCode == RESULT_OK) {
tagData = tagDataService.fetchById(tagData.getId(), TagData.PROPERTIES);
filter = TagFilterExposer.filterFromTagData(this, tagData);
taskAdapter = null;
loadTaskListContent(true);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void uploadTagPicture(final Bitmap bitmap) {
new Thread(new Runnable() {
@Override
public void run() {
try {
String url = actFmSyncService.setTagPicture(tagData.getValue(TagData.REMOTE_ID), bitmap);
tagData.setValue(TagData.PICTURE, url);
Flags.set(Flags.ACTFM_SUPPRESS_SYNC);
tagDataService.save(tagData);
} catch (IOException e) {
DialogUtilities.okDialog(TagViewActivity.this, e.toString(), null);
}
}
}).start();
}
@SuppressWarnings("nls")
private void addComment() {
if(tagData.getValue(TagData.REMOTE_ID) == 0L)
return;
Update update = new Update();
update.setValue(Update.MESSAGE, addCommentField.getText().toString());
update.setValue(Update.ACTION_CODE, "tag_comment");
update.setValue(Update.USER_ID, 0L);
update.setValue(Update.TAGS, "," + tagData.getValue(TagData.REMOTE_ID) + ",");
update.setValue(Update.CREATION_DATE, DateUtilities.now());
Flags.checkAndClear(Flags.ACTFM_SUPPRESS_SYNC);
updateDao.createNew(update);
addCommentField.setText(""); //$NON-NLS-1$
refreshUpdatesList();
StatisticsService.reportEvent(StatisticsConstants.ACTFM_TAG_COMMENT);
}
@Override
public boolean onMenuItemSelected(int featureId, final MenuItem item) {
// handle my own menus

@ -103,7 +103,7 @@ public class ActFmPreferenceService extends SyncProviderUtilities {
}
@SuppressWarnings("nls")
private synchronized static JSONObject thisUser() {
public synchronized static JSONObject thisUser() {
if(user == null) {
user = new JSONObject();
try {

@ -152,7 +152,7 @@ public final class ActFmSyncService {
new Thread(new Runnable() {
@Override
public void run() {
pushUpdateOnSave(model, setValues);
pushUpdateOnSave(model, setValues, null);
}
}).start();
}
@ -227,7 +227,7 @@ public final class ActFmSyncService {
/**
* Synchronize with server when data changes
*/
public void pushUpdateOnSave(Update update, ContentValues values) {
public void pushUpdateOnSave(Update update, ContentValues values, Bitmap imageData) {
if(!values.containsKey(Update.MESSAGE.name))
return;
@ -243,13 +243,22 @@ public final class ActFmSyncService {
if(update.getValue(Update.TASK) > 0) {
params.add("task_id"); params.add(update.getValue(Update.TASK));
}
MultipartEntity picture = null;
if (imageData != null) {
picture = buildPictureData(imageData);
}
if(!checkForToken())
return;
try {
params.add("token"); params.add(token);
JSONObject result = actFmInvoker.invoke("comment_add", params.toArray(new Object[params.size()]));
JSONObject result;
if (picture == null)
result = actFmInvoker.invoke("comment_add", params.toArray(new Object[params.size()]));
else
result = actFmInvoker.post("comment_add", picture, params.toArray(new Object[params.size()]));
update.setValue(Update.REMOTE_ID, result.optLong("id"));
update.setValue(Update.PICTURE, result.optString("picture"));
updateDao.saveExisting(update);
} catch (IOException e) {
if (notPermanentError(e))
@ -396,7 +405,16 @@ public final class ActFmSyncService {
*/
public void pushUpdate(long updateId) {
Update update = updateDao.fetch(updateId, Update.PROPERTIES);
pushUpdateOnSave(update, update.getMergedValues());
pushUpdateOnSave(update, update.getMergedValues(), null);
}
/**
* Push complete update with new image to server (used for new comments)
*/
public void pushUpdate(long updateId, Bitmap imageData) {
Update update = updateDao.fetch(updateId, Update.PROPERTIES);
pushUpdateOnSave(update, update.getMergedValues(), imageData);
}
/**
@ -747,6 +765,12 @@ public final class ActFmSyncService {
if(!checkForToken())
return null;
MultipartEntity data = buildPictureData(bitmap);
JSONObject result = actFmInvoker.post("tag_save", data, "id", tagId, "token", token);
return result.optString("picture");
}
private MultipartEntity buildPictureData(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if(bitmap.getWidth() > 512 || bitmap.getHeight() > 512) {
float scale = Math.min(512f / bitmap.getWidth(), 512f / bitmap.getHeight());
@ -757,8 +781,7 @@ public final class ActFmSyncService {
byte[] bytes = baos.toByteArray();
MultipartEntity data = new MultipartEntity();
data.addPart("picture", new ByteArrayBody(bytes, "image/jpg", "image.jpg"));
JSONObject result = actFmInvoker.post("tag_save", data, "id", tagId, "token", token);
return result.optString("picture");
return data;
}
// --- generic invokation
@ -894,7 +917,7 @@ public final class ActFmSyncService {
model.setValue(Update.MESSAGE, "");
else
model.setValue(Update.MESSAGE, json.getString("message"));
model.setValue(Update.PICTURE, json.getString("picture"));
model.setValue(Update.PICTURE, json.optString("picture", ""));
model.setValue(Update.CREATION_DATE, readDate(json, "created_at"));
String tagIds = "," + json.optString("tag_ids", "") + ",";
model.setValue(Update.TAGS, tagIds);

@ -95,8 +95,7 @@ public class FilterByTagExposer extends BroadcastReceiver {
Tag tag = new Tag(tags.get(which), 0, 0);
String listTitle = tag.tag;
String title = ContextManager.getString(
R.string.tag_FEx_name, tag.tag);
String title = tag.tag;
Criterion criterion = TaskCriteria.activeAndVisible();
QueryTemplate tagTemplate = tag.queryTemplate(criterion);
ContentValues contentValues = new ContentValues();

@ -63,7 +63,7 @@ public class TagFilterExposer extends BroadcastReceiver {
/** Create filter from new tag object */
@SuppressWarnings("nls")
public static FilterWithCustomIntent filterFromTag(Context context, Tag tag, Criterion criterion) {
String title = context.getString(R.string.tag_FEx_name, tag.tag);
String title = tag.tag;
QueryTemplate tagTemplate = tag.queryTemplate(criterion);
ContentValues contentValues = new ContentValues();
contentValues.put(Metadata.KEY.name, TagService.KEY);

@ -4,7 +4,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.todoroo.astrid.actfm.TagViewActivity;
import com.todoroo.astrid.actfm.TagSettingsActivity;
import com.todoroo.astrid.api.Addon;
import com.todoroo.astrid.api.AstridApiConstants;
@ -29,9 +29,7 @@ public class TagsPlugin extends BroadcastReceiver {
* @param activity
*/
public static Intent newTagDialog(Context context) {
Intent intent = new Intent(context, TagViewActivity.class);
intent.putExtra(TagViewActivity.EXTRA_NEW_TAG, true);
intent.putExtra(TagViewActivity.EXTRA_START_TAB, "settings"); //$NON-NLS-1$
Intent intent = new Intent(context, TagSettingsActivity.class);
return intent;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="false"
android:drawable="@drawable/header_background"/>
<item android:state_pressed="true" android:state_enabled="true"
android:drawable="@drawable/header_background_pressed"/>
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/header_background_pressed"/>
</selector>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="false"
android:drawable="@drawable/header_background_white"/>
<item android:state_pressed="true" android:state_enabled="true"
android:drawable="@drawable/header_background_pressed"/>
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/header_background_pressed"/>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

@ -17,10 +17,10 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="false" android:drawable="@drawable/header_tags_normal" />
android:state_focused="false" android:drawable="@drawable/icn_arrow_light" />
<item android:state_pressed="true" android:state_enabled="true"
android:drawable="@drawable/header_tags_pressed" />
android:drawable="@drawable/icn_arrow_over" />
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/header_tags_pressed" />
android:state_focused="true" android:drawable="@drawable/icn_arrow_over" />
</selector>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="false" android:drawable="@drawable/icn_arrow" />
<item android:state_pressed="true" android:state_enabled="true"
android:drawable="@drawable/icn_arrow_over" />
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/icn_arrow_over" />
</selector>

@ -29,7 +29,7 @@
android:layout_weight="100"
android:gravity="center"
android:paddingRight="50dip"
android:src="@drawable/header_logo"
android:src="@drawable/header_logo_new"
android:scaleType="center"/>
</LinearLayout>

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- settings tab -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:astrid="http://schemas.android.com/apk/res/com.timsu.astrid"
android:id="@+id/settings"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
style="@style/Content">
<LinearLayout
style="@style/Header"
android:layout_width="fill_parent"
android:layout_height="43dip"
android:layout_weight="1"
android:orientation="horizontal">
<!-- List Label -->
<TextView android:id="@+id/listLabel"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:gravity="center"
android:singleLine="true"
android:ellipsize="start"
style="@style/TextAppearance.TLA_Header"/>
</LinearLayout>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="100">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dip"
android:orientation="vertical">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dip">
<greendroid.widget.AsyncImageView
android:id="@+id/picture"
android:layout_width="80dip"
android:layout_height="80dip"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="fitCenter"
android:paddingRight="10dip"
android:visibility="gone"
astrid:defaultSrc="@android:drawable/ic_menu_gallery" />
<TextView
android:id="@+id/tag_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/picture"
android:layout_alignParentTop="true"
android:layout_marginTop="10dip"
style="@style/TextAppearance.GEN_EditLabel"
android:text="@string/actfm_TVA_tag_label" />
<EditText
android:id="@+id/tag_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/picture"
android:layout_below="@id/tag_label"
android:layout_marginTop="10dip" />
</RelativeLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="@android:drawable/divider_horizontal_dark" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="10dip"
android:paddingBottom="5dip"
style="@style/TextAppearance.GEN_EditLabel"
android:text="@string/actfm_TVA_members_label" />
<com.todoroo.astrid.ui.PeopleContainer
android:id="@+id/members_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<!-- Footer -->
<LinearLayout
android:id="@+id/listSettingsMore"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:orientation="vertical"
android:visibility="gone">
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="@android:drawable/divider_horizontal_dark" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
style="@style/TextAppearance.GEN_EditLabel"
android:text="@string/actfm_TVA_tag_owner_label" />
<TextView
android:id="@+id/tag_owner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:textSize="20sp"/>
<CheckBox
android:id="@+id/tag_silenced"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:paddingLeft="45dip"
style="@style/TextAppearance"
android:text="@string/actfm_TVA_silence_label" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/membersFooter"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="10dip"
android:padding="5dip"
android:background="@drawable/footer_background"
android:orientation="horizontal"
android:baselineAligned="false">
<ImageButton
android:id="@+id/saveMembers"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/tango_save" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
style="@style/Content">
<LinearLayout
style="@style/Header"
android:layout_width="fill_parent"
android:layout_height="43dip"
android:layout_weight="1"
android:orientation="horizontal">
<!-- List Label -->
<TextView android:id="@+id/listLabel"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:gravity="center"
android:singleLine="true"
android:ellipsize="start"
style="@style/TextAppearance.TLA_Header"/>
</LinearLayout>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"/>
<!-- Footer -->
<LinearLayout
android:id="@+id/updatesFooter"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="47dip"
android:layout_weight="1"
android:background="@drawable/footer_background"
android:padding="3dip"
android:orientation="horizontal">
<!-- Voice Add Button -->
<ImageButton android:id="@+id/picture"
android:layout_width="39dip"
android:layout_height="39dip"
android:layout_gravity="top"
android:layout_marginRight="3dip"
android:paddingLeft="7dip"
android:paddingRight="7dip"
android:paddingBottom="2dip"
android:layout_weight="1"
android:background="@drawable/footer_button"
android:src="@drawable/icn_camera"
android:scaleType="fitCenter"/>
<!-- Quick Add Task -->
<EditText android:id="@+id/commentField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dip"
android:layout_weight="100"
android:background="@drawable/footer_edittext"
android:hint="@string/TVA_add_comment"
android:textSize="16sp"
android:autoText="true"
android:capitalize="sentences"/>
<!-- Extended Add Button -->
<ImageButton android:id="@+id/commentButton"
android:layout_width="wrap_content"
android:layout_height="39dip"
android:layout_gravity="top"
android:layout_marginRight="3dip"
android:layout_weight="1"
android:background="@drawable/footer_button"
android:src="@drawable/ic_footer_add"
android:scaleType="center"/>
</LinearLayout>
</LinearLayout>

@ -7,44 +7,98 @@
style="@style/Content"
android:orientation="vertical">
<!-- Header -->
<LinearLayout
style="@style/Header"
android:layout_width="fill_parent"
android:layout_height="43dip"
android:layout_weight="1"
android:orientation="horizontal">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="43dip"
android:layout_weight="1"
android:orientation="horizontal">
<!-- Filters Button -->
<ImageView android:id="@+id/back"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:src="@drawable/header_tags"
android:scaleType="center" />
<!-- List Label -->
<TextView android:id="@+id/listLabel"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:gravity="center"
android:singleLine="true"
android:paddingRight="50dip"
android:ellipsize="start"
style="@style/TextAppearance.TLA_Header"/>
<!-- Header Logo -->
<ImageView android:id="@+id/headerLogo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:gravity="center"
android:paddingRight="50dip"
android:src="@drawable/header_logo"
android:scaleType="center"
android:visibility="gone"/>
<!-- Filters Button -->
<ImageView android:id="@+id/back"
android:layout_width="43dip"
android:layout_height="fill_parent"
android:background="?attr/asHeaderButtonBackground"
android:padding="7dip"
android:src="@drawable/icn_lists"
android:scaleType="fitCenter" />
<View
android:layout_width="0.5dip"
android:layout_height="fill_parent"
android:background="#ff222222"/>
<LinearLayout
style="@style/Header"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:orientation="horizontal">
<!-- Header Logo -->
<ImageView android:id="@+id/headerLogo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:gravity="center"
android:paddingRight="43dip"
android:src="@drawable/header_logo_new"
android:scaleType="center"
android:visibility="gone"/>
<!-- List Label -->
<TextView android:id="@+id/listLabel"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:paddingRight="50dip"
android:layout_weight="100"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
style="@style/TextAppearance.TLA_Header"/>
</LinearLayout>
<LinearLayout android:id="@+id/activityContainer"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:visibility="gone">
<View
android:layout_width="0.5dip"
android:layout_height="fill_parent"
android:background="#ff222222"/>
<ImageView android:id="@+id/activity"
android:layout_height="fill_parent"
android:layout_width="43dip"
android:background="?attr/asHeaderButtonBackground"
android:padding="7dip"
android:src="@drawable/icn_cmmt_off"
android:scaleType="fitCenter" />
</LinearLayout>
<LinearLayout android:id="@+id/settingsContainer"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:visibility="gone">
<View
android:layout_width="0.5dip"
android:layout_height="fill_parent"
android:background="#ff222222"/>
<ImageView
android:id="@+id/settings"
android:layout_height="fill_parent"
android:layout_width="43dip"
android:background="?attr/asHeaderButtonBackground"
android:padding="7dip"
android:src="@drawable/icn_settings"
android:scaleType="fitCenter" />
</LinearLayout>
</LinearLayout>
<!-- Body goes here -->

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="100">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="43dip"
android:layout_weight="1"
android:background="?attr/asMembersHeaderBackground">
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="43dip"
android:layout_weight="15"
android:scrollbars="none">
<LinearLayout
android:id="@+id/shared_with"
android:layout_width="wrap_content"
android:layout_height="fill_parent">
<TextView
android:id="@+id/no_members"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:layout_marginLeft="10dip"
style="@style/TextAppearance"
android:textStyle="bold"
android:text="@string/actfm_TVA_no_members_alert"/>
</LinearLayout>
</HorizontalScrollView>
<ImageView
android:id="@+id/members_edit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="85"
android:padding="7dip"
android:src="?attr/asMembersHeaderArrow"
android:scaleType="fitCenter"/>
</LinearLayout>
<TextView
android:id="@+id/filter_assigned"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingTop="3dip"
android:paddingBottom="3dip"
style="@style/TextAppearance"
android:background="@android:color/darker_gray"
android:visibility="gone"/>
</LinearLayout>
<!-- List body goes here -->
</LinearLayout>

@ -1,57 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- See the file "LICENSE" for the full license governing this code. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:astrid="http://schemas.android.com/apk/res/com.timsu.astrid"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/list_selector_background"
android:paddingTop="4dip"
android:paddingBottom="4dip"
android:paddingLeft="4dip"
android:paddingRight="6dip">
android:orientation="vertical">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/list_selector_background"
android:paddingTop="4dip"
android:paddingBottom="4dip"
android:paddingLeft="4dip"
android:paddingRight="6dip">
<!-- picture -->
<greendroid.widget.AsyncImageView android:id="@+id/picture"
android:layout_width="40dip"
android:layout_height="40dip"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingTop="5dip"
astrid:defaultSrc="@drawable/ic_contact_picture_2"
android:scaleType="fitCenter" />
<!-- title -->
<TextView android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingLeft="50dip"
android:paddingRight="75dip"
style="@style/TextAppearance.TAd_ItemTitle"
android:textSize="16sp"/>
<!-- action description -->
<TextView android:id="@+id/description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignParentLeft="true"
style="@style/TextAppearance.TAd_ItemDetails"
android:paddingLeft="50dip"
android:textSize="14sp" />
<!-- activity date -->
<TextView android:id="@+id/date"
android:layout_width="75dip"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:paddingTop="3dip"
style="@style/TextAppearance.TAd_ItemDueDate"
android:gravity="right"
android:ellipsize="end"
android:textSize="12sp"
android:singleLine="true"/>
</RelativeLayout>
<!-- picture -->
<greendroid.widget.AsyncImageView android:id="@+id/picture"
android:layout_width="40dip"
android:layout_height="40dip"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingTop="5dip"
astrid:defaultSrc="@drawable/ic_contact_picture_2"
android:scaleType="fitCenter" />
<!-- title -->
<TextView android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingLeft="50dip"
android:paddingRight="75dip"
style="@style/TextAppearance.TAd_ItemTitle"
android:textSize="16sp"/>
<!-- action description -->
<TextView android:id="@+id/description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignParentLeft="true"
style="@style/TextAppearance.TAd_ItemDetails"
android:paddingLeft="50dip"
android:textSize="14sp" />
<!-- activity date -->
<TextView android:id="@+id/date"
android:layout_width="75dip"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:paddingTop="3dip"
style="@style/TextAppearance.TAd_ItemDueDate"
android:gravity="right"
android:ellipsize="end"
android:textSize="12sp"
android:singleLine="true"/>
<greendroid.widget.AsyncImageView
android:id="@+id/comment_picture"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_alignParentBottom="true"
android:layout_marginLeft="50dip"
android:layout_marginBottom="4dip"
android:visibility="gone"
astrid:defaultSrc="@android:drawable/ic_menu_gallery"
android:scaleType="fitCenter"/>
</RelativeLayout>
</LinearLayout>

@ -4,6 +4,7 @@
<!-- theme attributes -->
<attr name="asContentBackground" format="reference"/>
<attr name="asHeaderBackground" format="reference"/>
<attr name="asHeaderButtonBackground" format="reference"/>
<attr name="asTextColor" format="color"/>
<attr name="asDetailsColor" format="color"/>
<attr name="asDueDateColor" format="color"/>
@ -12,9 +13,12 @@
<attr name="asFilterHeaderColor" format="color"/>
<attr name="asFilterHeaderBackground" format="reference"/>
<attr name="asFilterCountColor" format="color"/>
<attr name="asMembersHeaderBackground" format="reference"/>
<attr name="asMembersHeaderArrow" format="reference"/>
<declare-styleable name="ContactsAutoComplete">
<attr name="allowMultiple" format="boolean"/>
<attr name="completeTags" format="boolean"/>
</declare-styleable>
</resources>

@ -27,6 +27,9 @@
<!-- menu item to select from gallery -->
<string name="actfm_picture_gallery">Pick from Gallery</string>
<!-- menu item to clear picture selection -->
<string name="actfm_picture_clear">Clear Picture</string>
<!-- filter list activity: refresh tags -->
<string name="actfm_FLA_menu_refresh">Refresh Lists</string>
@ -48,6 +51,12 @@
<!-- Tab for showing setting -->
<item>List Settings</item>
</string-array>
<!-- Tag View: filtered by assigned to user -->
<string name="actfm_TVA_filtered_by_assign">%s\'s tasks. Tap for all.</string>
<!-- Tag View: list is private, no members -->
<string name="actfm_TVA_no_members_alert">Private: tap to share this list</string>
<!-- Tag View Menu: refresh -->
<string name="actfm_TVA_menu_refresh">Refresh</string>

@ -59,6 +59,10 @@
<!-- Dialog - dismiss -->
<string name="DLG_dismiss">Dismiss</string>
<string name="DLG_ok">OK</string>
<string name="DLG_cancel">Cancel</string>
<!-- =============================================================== UI == -->
<!-- Label for DateButtons with no value -->
@ -118,6 +122,9 @@
<!-- Quick Add Edit Box Hint-->
<string name="TLA_quick_add_hint">Add to this list...</string>
<!-- Quick Add Edit Box Hint for assigning -->
<string name="TLA_quick_add_hint_assign">Tap to assign %s a task</string>
<!-- Notification Volumne notification-->
<string name="TLA_notification_volume_low">Notifications are muted. You won\'t be able to hear Astrid!</string>

@ -85,5 +85,11 @@
<string name="tag_case_migration_notice">We\'ve noticed that you have some lists that have the same name with different capitalizations. We think you may have intended them to
be the same list, so we\'ve combined the duplicates. Don\'t worry though: the original lists are simply renamed with numbers (e.g. Shopping_1, Shopping_2). If you don\'t want this, you
can simply delete the new combined list!</string>
<!-- Header for tag settings -->
<string name="tag_settings_title">Settings: %s</string>
<!-- Header for tag activity -->
<string name="tag_updates_title">Activity: %s</string>
</resources>

@ -8,6 +8,7 @@
<item name="android:windowBackground">@null</item>
<item name="asContentBackground">@drawable/background_gradient</item>
<item name="asHeaderBackground">@drawable/header_background</item>
<item name="asHeaderButtonBackground">@drawable/header_button</item>
<item name="asTextColor">#ffffffff</item>
<item name="asDetailsColor">#ff777777</item>
<item name="asDueDateColor">#ff7777aa</item>
@ -15,6 +16,8 @@
<item name="asDueDateCompletedColor">#ff777777</item>
<item name="asFilterHeaderColor">#ffcccccc</item>
<item name="asFilterHeaderBackground">@drawable/edit_titlebar</item>
<item name="asMembersHeaderBackground">@drawable/ios_fabric_480_dark</item>
<item name="asMembersHeaderArrow">@drawable/members_arrow</item>
</style>
<style name="Theme.Transparent">
@ -26,11 +29,14 @@
<style name="Theme.White">
<item name="asContentBackground">@drawable/background_white</item>
<item name="asHeaderBackground">@drawable/header_background_white</item>
<item name="asHeaderButtonBackground">@drawable/header_button_white</item>
<item name="asTextColor">#ff000000</item>
<item name="asDetailsColor">#ff6666aa</item>
<item name="asDueDateColor">#ff000000</item>
<item name="asFilterHeaderColor">#ffffff</item>
<item name="asFilterHeaderBackground">@drawable/edit_titlebar_white</item>
<item name="asMembersHeaderBackground">@drawable/ios_fabric_480</item>
<item name="asMembersHeaderArrow">@drawable/members_arrow_white</item>
</style>
<style name="Theme.TransparentWhite" parent="@style/Theme.White">

@ -417,8 +417,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
public void onClick(View v) {
Task task = quickAddTask(quickAddBox.getText().toString(), true);
if(task != null && task.getValue(Task.TITLE).length() == 0) {
Intent intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
intent.putExtra(TaskEditActivity.TOKEN_ID, task.getId());
Intent intent = getOnClickQuickAddIntent(task);
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
}
}
@ -439,8 +438,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
Task task = quickAddTask(quickAddBox.getText().toString(), false);
if(task == null)
return true;
Intent intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
intent.putExtra(TaskEditActivity.TOKEN_ID, task.getId());
Intent intent = getOnLongClickQuickAddIntent(task);
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
return true;
}
@ -462,6 +460,19 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DITHER);
}
// Subclasses can override these to customize extras in quickadd intent
protected Intent getOnClickQuickAddIntent(Task t) {
Intent intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
intent.putExtra(TaskEditActivity.TOKEN_ID, t.getId());
return intent;
}
protected Intent getOnLongClickQuickAddIntent(Task t) {
Intent intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
intent.putExtra(TaskEditActivity.TOKEN_ID, t.getId());
return intent;
}
private void setUpBackgroundJobs() {
backgroundTimer = new Timer();

@ -4,15 +4,19 @@ import greendroid.widget.AsyncImageView;
import org.json.JSONObject;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.database.Cursor;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.CursorAdapter;
import android.widget.TextView;
@ -56,10 +60,10 @@ public class UpdateAdapter extends CursorAdapter {
OnCompletedTaskListener onCompletedTaskListener) {
super(activity, c, autoRequery);
DependencyInjectionService.getInstance().inject(this);
inflater = (LayoutInflater) activity.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
this.resource = resource;
this.activity = activity;
}
@ -104,6 +108,38 @@ public class UpdateAdapter extends CursorAdapter {
pictureView.setUrl(pictureUrl);
}
final AsyncImageView commentPictureView = (AsyncImageView)view.findViewById(R.id.comment_picture); {
final String updatePicture = update.getValue(Update.PICTURE);
if (!TextUtils.isEmpty(updatePicture) && !"null".equals(updatePicture)) {
commentPictureView.setVisibility(View.VISIBLE);
commentPictureView.setUrl(updatePicture);
final String message = update.getValue(Update.MESSAGE);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog image = new AlertDialog.Builder(activity).create();
AsyncImageView imageView = new AsyncImageView(activity);
imageView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
imageView.setDefaultImageResource(android.R.drawable.ic_menu_gallery);
imageView.setUrl(updatePicture);
image.setView(imageView);
image.setMessage(message);
image.setButton(activity.getString(R.string.DLG_close), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
return;
}
});
image.show();
}
});
} else {
commentPictureView.setVisibility(View.GONE);
}
}
// name
final TextView nameView = (TextView)view.findViewById(R.id.title); {
String nameValue = user.optString("name");

@ -179,9 +179,9 @@ public class PeopleContainer extends LinearLayout {
if(person.has("id") && person.getLong("id") == ActFmPreferenceService.userId())
textView = addPerson(Preferences.getStringValue(ActFmPreferenceService.PREF_NAME));
else if(!TextUtils.isEmpty(person.optString("name")))
else if(!TextUtils.isEmpty(person.optString("name")) && !"null".equals(person.optString("name")))
textView = addPerson(person.getString("name"));
else if(!TextUtils.isEmpty(person.optString("email")))
else if(!TextUtils.isEmpty(person.optString("email")) && !"null".equals(person.optString("email")))
textView = addPerson(person.getString("email"));
if(textView != null) {

Loading…
Cancel
Save